全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网
推荐引擎

在线算法开发手册

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

先决条件

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

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

推荐引擎提供了适用于个性化推荐的多种算法和模板,了解详情请访问系统内置算法和模板说明

基本知识

在线流程中,您要编写的算法体现为流程图中的一个个节点,如https://dtboost.aliyun.com/re/onlineflow?tp=tpl&id=45 所示:其中节点表现为函数,函数体基本结构如下

  1. 0 // 下面这部分是流程节点运行时真正的执行代码,要求您提交的在线代码严格按照以下格式。为方便讲解起见,我们给他起个代号叫做MAIN_ENTRY
  2. 1 function() {
  3. 2 // 函数体内您可以定义一些公用的变量或函数
  4. 3 var test_variable = 0;
  5. 4 var test_function = function() {
  6. 5 console.log('i am test_function');
  7. 6 }
  8. 7 var callback = this; // NodeJS里的回调函数习惯用callback表示,这里直接赋值,符合程序员习惯
  9. 8 var reclist = arguments[0][0]; //arguments[0][0]表示上游节点的输出数据,典型的情况下就是一个推荐列表
  10. 9 ... // 在这里完成您的处理逻辑
  11. 10 return callback(null, reclist); // 值得注意的是,这里必须写成callback的形式(由于是最后一个语句,因此有没有return无区别,但对于需要提前回调的情况,请注意使用return callback),而不能直接return一个变量,否则下游节点获取不到本节点的输出,程序也会hang住,框架会一直等待该函数回调事件
  12. 11 }

注意事项

  1. 第2-6行,定义的内层公用变量和函数,您可以在MAIN_ENTRY中调用,后文会提及公用变量和方法的一种高级用法(请移步“高级用法-使用共享缓存”)。
  2. 第8行,arguments代表的是上游输出给下游节点的数据列表,是一个二维数组,但由于流程中限制了每个节点只能有一个直接上游,因此arguments的第一维长度也就固定为<=1(=0对应的情况是callback的时候无第二个参数)。第二维的长度由上游节点callback时的参数长度决定,假设上游callback(null, ‘a’, ‘b’),那么arguments[0] = [‘a’,’b’]
  3. 第10行,关于callback函数的第一个参数,在“NodeJS最佳实践”中,callback的第一个参数固定表示是否遇到错误,如果callback的第一个参数不为null,框架会认为程序遇到异常退出,后续流程不会再继续流程。我们在这里编写代码的时候,也请遵循这一实践规范。
  4. 第10行,return callback(null, reclist),这里的reclist就是本节点输出给下游节点的数据,对应注释第2)条,下游可以通过arguments[0][0]获取。
  5. 代码中如何获取算法启动参数?对于同一算法,在线SDK允许您定义不同的函数参数取值,以完成不同的操作,这部分请参见https://dtboost.aliyun.com/re#/alg/editAlg?id=29, 这个算法里定义了一个topn参数,您可以在MAIN_ENTRY中通过topn = parseInt(topn);获取。需要注意的是,所有算法启动参数均以string类型传入,由您自己决定是否需要进行类型转换。

初级用法

下面展示了一个对推荐列表按item_id进行去重的简单方法

  1. function() {
  2. var callback = this;
  3. var reclist = arguments[0][0];
  4. var occupy = {}, mergedList = [];
  5. reclist.forEach(function(item) {
  6. var item_id = item.item_id === undefined ? item[0] : item.item_id;
  7. if (typeof(occupy[item_id]) === 'undefined') {
  8. occupy[item_id] = 1;
  9. mergedList.push(item);
  10. }
  11. });
  12. return callback(null, mergedList);
  13. }

这个代码很简单,这里不做进一步的详细分析。

高级用法

使用共享缓存

值得注意的是,所有您定义的函数,在执行时共享同一个this引用,举例来说,如果您定义了一个函数A和函数B(流程中B在A之后调用),假设两段函数分别为:

  1. function() { // 函数A
  2. this.cache_A = 'cache_A ';
  3. ...
  4. }
  1. function() { // 函数B
  2. console.log(tihs.cache_A); // 将输出cache_A
  3. ...
  4. }

这种机制使您可以将一些下游节点反复引用的数据缓存起来,避免重复调用相同函数造成的资源浪费。

同理,共享缓存机制可以方便您提前注册一些您自定义的功能性函数,以下给出一个示例:

  1. function() { // 我们假设这个函数的名称叫setup
  2. var add = function(a,b) { return a+b; }
  3. var sub = function(a,b) { return a-b; }
  4. var callback = this;
  5. this.func_add = add;
  6. this.func_sub = sub;
  7. var c = this.func_add(1,2); // c=3
  8. return callback(null, c);
  9. }

您可以在在线流程的初始节点执行该函数,那么该节点的所有下游节点都可以引用this.func_add和this.func_sub函数。具体来说,假设在线流程执行顺序为setup->A->B,那么A和B节点的函数体内均可调用this.func_add和this.func_sub函数。

注意:尽管提供了共享缓存机制,但不建议对所有节点都执行该操作,基于以下理由:

1)所有节点输出都缓存在内存中,无疑会增加内存占用量。

2)对于一些结构比较简单的节点上下游关系,建议直接采用callback的方式传递数据给下游,因为这种情况下下游节点完全不需要关注上游节点的实现细节,只要采用arguments[0][0]的方式接收上游输出即可,否则下游节点还需要查看上游节点将产出缓存在了哪个变量里。

SDK内置属性

CTX:SDK内置变量

请求上下文变量,包含以下一些属性:

  • REC_REQ:格式化后的API请求参数假设您的请求参数为:biz_code=biz&scn_code=scn&user_id=uid&item_id=iid&city_id=cid,那么您得到的CTX.REC_REQ变量是一个JSON对象{biz_code:biz,scn_code:scn,user_id:uid,item_id:iid,city_id:cid},您可以通过访问CTX.REC_REQ的各个属性来获得本次API请求的所有请求参数

  • REC_IS:推荐候选集,包含以下子属性:

属性名 属性说明 取值类型 访问方法
RD_UBRC 获取以当次请求参数中的user_id作为查询条件的推荐列表 二维数组,每一维表示一个推荐项,表示为[item_id, score],item_id表示推荐的item标示,score表示离线为该item计算得到的推荐打分。示例:[[i1,s1],…,[in,sn]] CTX.REC_IS.RD_UBRC
RD_IBRC 获取以当次请求参数中的item_id作为查询条件的推荐列表 同上 CTX.REC_IS.RD_IBRC
RD_UA 获取用户的离线资产表,即用户最近有行为记录的item列表 同上 CTX.REC_IS.RD_UA
RD_DFLT 获取离线计算好的默认推荐列表。 同上 CTX.REC_IS.RD_DFLT
  • REC_UF:获取离线计算得到的user特征向量,包含以下子属性:
属性名 属性说明 取值类型 访问方法
RD_UF user特征向量,字符串表示 string CTX.REC_UF.RD_UF
  • REC_IF:获取离线计算得到的item特征向量,包含以下子属性:
属性名 属性说明 取值类型 访问方法
RD_IF item特征向量,字符串表示 string CTX.REC_IF.RD_IF
  • REC_MODEL:获取离线计算得到的推荐模型,包含以下子属性:
属性名 属性说明 取值类型 访问方法
RD_MODEL 推荐模型,该数据取值类型依不同模型而定 string CTX.REC_IF.RD_IF

TOOLBOX:SDK内置方法

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

TOOLBOX主要包含以下一些方法:

方法名称 方法说明 参数列表 返回参数 注意事项
getRecItemInfo 获取item列表对应的rec_item_info表的item_info信息 CTX,即请求上下文变量
itemids:itemid数组,每一个元素对应一个item_id
与itemids元素一一对应的item_info信息 这是一个异步方法,需要使用回调形式使用,请参考https://dtboost.aliyun.com/re#/alg/editAlg?id=102
getTagReclist 获取自定义tag(可以为城市、性别等任意可作为生成推荐结果对象,比如对分城市的推荐结果做个性化,需要离线开发相应算法在线方能获取)的推荐列表 CTX,即请求上下文变量
tags:tag数组,每一个元素对应一个tag
与tags元素一一对应的推荐列表信息 异步方法
getTagValues 与getTagReclist同义,区别在于getTagValues获取的结果是裸数据(即原始字符串),getTagReclist对裸数据进行了一次解析为推荐列表 同getTagReclist 与tags元素一一对应的推荐列表裸字符串,用\002\003分隔 异步方法
getKeyValues 获取一组自定义键值 CTX,即请求上下文变量
keys:自定义键数组,每一个元素对应一个自定义键
与键keys一一对应的值数组 自定义键值的写入需要进行离线开发并导入在线,请参考离线算法开发手册
getValuesByDataform 获取在线存储中一组指定dataform的查询key的对应值 dataform:对应离线算法的输出类别,keys:一组查询主键,类型为数组 与keys一一对应的字符串 注意事项 假设需要在线获取物品特征向量,可以这样用
TOOLBOX.getValuesByDataform(‘ITEM_FEATURE’, [item_id1, item_id2], function(err, features) {
if (err) return callback(err);
//features[0]是item_id1的feature,features[1]是item_id2的feature字符串
});

Tips:关于默认推荐结果,SDK不提供get方法,原因在于大部分情况下都需要有一个全局默认结果,推荐引擎从API效率角度考虑,在处理流程前一并并行获取,只需要您在在线流程“选择离线数据中”勾选“RD_DFLT”即可,然后通过CTX.REC_IS.RD_DFLT获得

Tips:如果您确实需要系统提供其他方法,请在阿里云工单系统中详细描述您的需求,我们评估后会酌情进行添加。

关于require方法的使用

SDK提供了沙箱机制,您所能require到的NodeJS模块列出如下(包括NodeJS自带和第三方NPM包):

  • util
  • utility
  • lodash

尝试require其他模块将直接报错。有关模块的具体使用方法,请参考 http://npm.taobao.org 中的文档。

Tips:如果您确实需要require其他模块,请在阿里云工单系统中详细描述您的需求和所要引用的模块名称,我们评估后会酌情进行添加。

本文导读目录