全部产品

实时修正算法开发手册

更新时间:2017-06-07 13:26:11   分享:   

阿里云推荐引擎支持两类实时修正,分别通过数据修正API和实时的用户行为日志提交到推荐引擎。数据修正API一般用来解决物品的实时变更需求,比如有新物品上线,或者老物品下架,需要及时调整;利用用户行为日志的修正一般用来调整用户的兴趣偏好,根据用户实时行为进行更有针对性的推荐。阿里云推荐引擎会提供默认的修正算法,客户也可以根据业务需求自己定义。

233

先决条件

您需要熟悉基于NodeJS的开发模式,主要包括JS的基本语法+异步编程+函数回调(后两项为高级进阶要求,依您所需要开发的算法复杂度选择具备即可)。

算法代码可在推荐引擎提供的界面中进行编辑修改,并运行在推荐环境中,您不需要在本地搭建NodeJS的环境。

基本知识

一个实时修正算法表现一个函数(一段NodeJS代码),函数体基本结构如下:

  1. function(logs) { // logs为数组类型,即您通过日志API上传的一组原始日志,每条日志为string类型
  2. var callback = this; // 固定写法,callback为回调函数
  3. console.log('test log', logs);
  4. // 定义一个解析日志内容的方法,依您上传的日志格式进行解析。这里简单演示一个url请求参数的解析函数
  5. var parseLog = function(log) {
  6. var paraobj = {}, fields = log.split('&');
  7. fields.forEach(function(ele) {
  8. var tt = ele.split('=');
  9. var k = decodeURIComponent(tt[0]), v = decodeURIComponent(tt[1]);
  10. paraobj[k] = v;
  11. });
  12. return paraobj;
  13. }
  14. // 定义您需要读取的数据结构
  15. var DataReader = {
  16. REC_USER: []
  17. };
  18. // 解析当前日志中每个用户产生行为的item列表
  19. var user2rec = {};
  20. logs.forEach(function(log) {
  21. var logobj = parseLog(log);
  22. var user_id = logobj.user_id, item_id = logobj.item_id;
  23. DataReader.REC_USER.push(user_id);
  24. user2rec[user_id] = user2rec[user_id] || [];
  25. user2rec[user_id].push(item_id);
  26. });
  27. console.log(JSON.stringify(DataReader));
  28. // 根据您定义的数据结构读取在线数据,TOOLBOX的使用方法见下一节详细说明
  29. TOOLBOX.read(DataReader, function(err, data) {
  30. if (err) return callback(err);
  31. console.log(JSON.stringify(data));
  32. // 定义您要写入的数据结构
  33. var DataWriter = {REC_USER: {}};
  34. var REC_USER = data.REC_USER;
  35. // 执行一个简单逻辑,若当前用户没有推荐结果,把他最近产生过行为的item直接作为下次推荐列表
  36. REC_USER.forEach(function(reclist, idx) {
  37. var user_id = DataReader.REC_USER[idx];
  38. if (reclist.length === 0) {
  39. DataWriter.REC_USER[user_id] = user2rec[user_id].map(function(item_id) {
  40. return [item_id, 1.0];
  41. })
  42. }
  43. });
  44. // 根据您定义的结构更新在线数据,TOOLBOX的使用方法见下一节详细说明
  45. TOOLBOX.write(DataWriter, callback);
  46. });
  47. }

SDK内置属性

TOOLBOX:SDK内置方法

这部分方法以系统内置函数的形式提供,您可以通过TOOLBOX.func_name调用(func_name为具体的方法名称)。

:凡下文中提到的一个“推荐列表”在数据类型上均表示为一个二维数组,如[ [‘a’,1.0], [‘b’,0.9], [‘c’,0.8] ],其中每一维第一位(即例中的’a’,’b’,’c’)固定表示item_id,其余位数可自定义扩展,如例中的1.0,0.9,0.8表示对应item_id的得分。

TOOLBOX主要包含以下方法:

方法名称 方法说明 参数列表 返回参数 注意事项
read 读取一组指定类型的在线数据 DataReader:JSON格式,支持的全部数据类型限定为{“REC_USER”:[], “REC_ITEM”:[], “REC_TAG”:[], “REC_DEFAULT”:1 ,”OTHERS”:[]},您可以有选择性地进行属性填充。其中:
REC_USER:获取一组针对用户的推荐列表,取值类型为字符串数组,如[‘user1’,’user2’];
REC_ITEM:获取一组针对物品的推荐列表,取值类型为字符串数组,如[‘item1’,’item2’];
REC_TAG:获取一组针对自定义Tag的推荐列表,取值类型为字符串数组,如[‘tag1’,’tag2’];
REC_DEFAULT:获取默认推荐列表,不需要获取默认推荐结果时,可以不设定该属性或将属性值设为0(亦即REC_DEFAULT:0);
OTHERS表示获取一组自定义键值对,取值类型为字符串数组,如[‘key1’,’key2’]
返回结果格式同输入参数,与DataReader中各查询属性顺序一一对应的查询结果,其中:
REC_USER/REC_ITEM/REC_TAG/REC_DEFAULT:一组推荐列表(数组),如[[[‘a’,1.0], [‘b’,0.9], [‘c’,0.8]], [[‘a’,1.0], [‘b’,0.9], [‘c’,0.8]]];
REC_DEFAULT:一个推荐列表;
OTHERS:与自定义键顺序对应的值字符串
1、这是一个异步方法,需要使用回调形式
2、单次调用的查询条数目不超过100
write 写入一组指定类型的在线数据 DataWriter:JSON格式,支持的全部数据类型限定为{“REC_USER”:{}, “REC_ITEM”:{}, “REC_TAG”:{}, “REC_DEFAULT”:[] ,”OTHERS”:{}},您可以有选择性地进行属性填充。其中:
REC_USER:写入一组针对用户推荐列表,取值类型为JSON,如{“user1”:[[‘a’,1.0], [‘b’,0.9], [‘c’,0.8]], “user2”:[[‘a’,1.0], [‘b’,0.9], [‘c’,0.8]]};
REC_ITEM:同上;
REC_TAG:同上;
REC_DEFAULT:写入默认推荐列表,取值为推荐列表;
OTHERS表示写入一组自定义键值对,如{“key1”:”value1”,”key2”:”value2”}
这是一个异步方法,需要使用回调形式使用

实例附录(仅供参考)

实现实时行为过滤(看过不再推荐)

  1. function(logs) {
  2. var callback = this;
  3. var parseLog = function(log) {
  4. var paraobj = {}, fields = log.split('&');
  5. fields.forEach(function(ele) {
  6. var tt = ele.split('=');
  7. var k = decodeURIComponent(tt[0]), v = decodeURIComponent(tt[1]);
  8. paraobj[k] = v;
  9. });
  10. return paraobj;
  11. }
  12. var getKey = function(user_id) {
  13. return "U_BHV_HIST" + "#" + user_id.toString();
  14. }
  15. var DataReader = {
  16. REC_USER: [],
  17. OTHERS: []
  18. };
  19. var user2item = {};
  20. logs.forEach(function(log) {
  21. var logobj = parseLog(log);
  22. var user_id = logobj.user_id, item_id = logobj.item_id;
  23. user2item[user_id] = user2item[user_id] || {};
  24. user2item[user_id][item_id] = 1;
  25. });
  26. DataReader.REC_USER = Object.keys(user2item);
  27. // 请求获取用户实时历史行为
  28. DataReader.OTHERS = Object.keys(user2item).map(function(u) {
  29. return getKey(u);
  30. });
  31. var this_user_bhv = {};
  32. for (var user in user2item)
  33. this_user_bhv[user] = Object.keys(user2item[user]);
  34. TOOLBOX.read(DataReader, function(err, data) {
  35. if (err) return callback(err);
  36. var DataWriter = {REC_USER: {}, OTHERS: {}};
  37. var REC_USER = data.REC_USER, last_user_bhv = data.OTHERS.split('\001');
  38. REC_USER.forEach(function(reclist, idx) {
  39. var user_id = DataReader.REC_USER[idx];
  40. // 判断当前推荐列表中是否存在看过的item
  41. var filtered = reclist.filter(function(rec) {
  42. return this_user_bhv[user_id].every(function(item_id) {
  43. return rec[0] !== item_id;
  44. });
  45. });
  46. // 只在有更新的情况下写回,节省写在线存储开销
  47. if (filtered.length < reclist.length)
  48. DataWriter.REC_USER[user_id] = filtered;
  49. // 合并用户本次行为记录
  50. var diffitems = user2item[user_id];
  51. last_user_bhv.forEach(function(item_id) {
  52. diffitems[item_id] = 1;
  53. });
  54. DataWriter.OTHERS[getKey(user_id)] = Object.keys(diffitems).join('\001');
  55. });
  56. TOOLBOX.write(DataWriter, callback);
  57. });
  58. }
本文导读目录
本文导读目录
以上内容是否对您有帮助?