BE引擎召回配置¶
阿里云召回引擎BE,是阿里巴巴集团推荐行业自研的召回引擎,提供全面召回的能力,具有高稳定、高性能的索引和查询机制、低运维成本、通过灵活过滤和配置策略加速迭代效率,支持秒级在线实时数据更新等特性。详细的介绍参考产品简介。
PAI-Rec 引擎内建支持对于 BE 引擎的访问,本文介绍如何通过配置就可以从 BE 召回数据。
数据源¶
首先要配置下数据源,这样通过数据源就可以访问到BE 引擎。
{
"BEConfs": {
"be-test": {
"Username": "",
"Password": "",
"Endpoint": "http://xxx.aime.aliyuncs.com",
"ReleaseType": "product"
}
}
}
上面的配置可以从 BE 实例控制台获取到
召回¶
BE 支持 X2I、向量、多路合并的多种类型的召回。这些召回的配置基本类似,下面一一说明。通常情况下,BE 会负责所有召回的输出,我们一般会使用多路合并的召回。但是多路合并的召回,具体每一路可以分为 X2I, 或者是向量召回。
多路合并召回¶
多数情况下,我们用此路召回。此路召回包含多个子链路召回,每个链路会配置优先级。
{
"Name": "BeRecall",
"RecallType": "BeRecall",
"BeConf": {
"Count": 500,
"BeName": "be-test",
"BizName": "be_common",
"BeRecallType": "multi_merge_recall",
"BeRecallParams": [
{
"Count": 50,
"RecallType": "x2i_recall",
"RecallName": "retarget_u2i",
"TriggerType": "user",
"UserTriggers": [
{
"TriggerKey": "uid"
}
],
"ItemIdName": "item_id"
},
{
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "etrec_i2i",
"TriggerType": "u2i_realtime",
"UserTriggerDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"HologresTableName": "user_realtime_behavior_holo",
"WhereClause": "",
"Limit": 50,
"TriggerCount": 20,
"EventPlayTime": "",
"EventWeight": "click:1;pre_go:2;add_collection:3;go:4",
"WeightExpression": "exp(-0.2 * (currentTime-eventTime)/3600/24)",
"NoUsePlayTimeField": true
},
"ItemIdName": "item_id",
"PropertyFields": [
"child_brand_id_new",
"root_brand_id",
"child_category_id",
"vertical_id"
],
"DiversityRules": [
{
"Dimensions": [
"vertical_id"
],
"Size": 10
},
{
"Dimensions": [
"child_category_id"
],
"Size": 5
},
{
"Dimensions": [
"root_brand_id"
],
"Size": 3
},
{
"Dimensions": [
"child_brand_id_new"
],
"Size": 2
}
]
},
"ItemIdName": "item_id",
"TriggerIdName": "trigger_id",
"UserTriggerRulesConf": {
"DefaultValue": 3,
"TriggerCounts": [
7,
7,
6,
5,
5,
3
]
}
},
{
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "offline_etrec_i2i",
"TriggerType": "u2i",
"UserCollaborativeDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"User2ItemTable": "ali_rec_sln_u2i_trigger_list_holo"
},
"ItemIdName": "item_id",
"TriggerIdName": "trigger_id",
"UserTriggerRulesConf": {
"DefaultValue": 3,
"TriggerCounts": [
7,
7,
6,
5,
5,
3
]
}
},
{
"Count": 50,
"RecallType": "x2i_recall",
"RecallName": "vertical_hot",
"TriggerType": "user",
"UserTriggers": [
{
"TriggerKey": "os"
},
{
"TriggerKey": "rel_sex"
},
{
"TriggerKey": "is_ordered_user"
}
],
"ItemIdName": "item_id"
},
{
"Count": 250,
"RecallType": "x2i_recall",
"RecallName": "mind_embedding",
"TriggerType": "user",
"UserTriggers": [
{
"TriggerKey": "uid"
}
],
"ItemIdName": "item_id"
},
{
"Count": 100,
"RecallType": "x2i_recall",
"RecallName": "global_hot",
"TriggerType": "fixvalue",
"TriggerValue": "-1",
"ItemIdName": "item_id"
}
],
"BeFilterNames": [
"UserExposureFilter",
"BizBlacklistFilter"
]
}
BeRecallParams 包含多个子链路配置。每个子链路需要配置召回类型(RecallType) 和召回名称(RecallName)。
Count BeConf 下表示总的召回输出的 item 数量是 500 个
BeName BEConfs 里定义的数据源名称
BizName be 配置里的业务名称
BeRecallType 多路合并,固定值 multi_merge_recall
BeRecallParams 定义了每一路的配置,每一路的配置是 x2i 或者是向量。 在上面的例子中, xi2 需要指定 RecallType = x2i_recall
通常的表现形式为:
{
"Name": "BeRecall",
"RecallType": "BeRecall",
"BeConf": {
"Count": 500,
"BeName": "be-test",
"BizName": "be_common",
"BeRecallType": "multi_merge_recall",
"BeRecallParams": [
{
"Count": 50,
"RecallType": "x2i_recall",
// 各路的具体定义
],
"BeFilterNames": [ // 过滤规则定义
"UserExposureFilter",
"BizBlacklistFilter"
],
"BeABParams":{ // be ab 参数的设置
}
}
X2I 召回的定义¶
我们具体介绍下 BeRecallParams 里每一路的配置的含义。
Count 定义了每一路召回的数量
RecallName 每一路的召回名称,需要和 be 里的配置保持一致
ItemIdName 返回的召回数据中,item id 的字段名称
在 X2I 的召回中,最主要是计算这个 X, 就是通常含义的 trigger。 我们支持多种不同的trigger , 下面详细说明。
固定值 Trigger¶
{
"Count": 100,
"RecallType": "x2i_recall",
"RecallName": "global_hot",
"TriggerType": "fixvalue",
"TriggerValue": "-1",
"ItemIdName": "item_id"
}
TriggerType = fixvalue , trigger 是个固定值,一般是全局的热门召回。 细节可以参考 这里
根据 user 属性组装 Trigger¶
{
"Count": 50,
"RecallType": "x2i_recall",
"RecallName": "vertical_hot",
"TriggerType": "user",
"UserTriggers": [
{
"TriggerKey": "os"
},
{
"TriggerKey": "rel_sex"
},
{
"TriggerKey": "is_ordered_user"
}
],
"ItemIdName": "item_id"
},
{
"Count": 250,
"RecallType": "x2i_recall",
"RecallName": "mind_embedding",
"TriggerType": "user",
"UserTriggers": [
{
"TriggerKey": "uid"
}
],
"ItemIdName": "item_id"
}
TriggerType = user , 我们可以根据 user 的属性,比如说 uid , 或者多个属性进行拼装成 trigger 进行召回。下面就是根据 uid 进行召回,可以理解成 U2I 召回
"UserTriggers": [ { "TriggerKey": "uid" } ]
根据 user 属性我们可以进行分组召回,多个属性拼接成一个值。类似下面的设置, 下面是把三个属性进行拼装。具体原理可以参考分组热门召回
"UserTriggers": [ { "TriggerKey": "os" }, { "TriggerKey": "rel_sex" }, { "TriggerKey": "is_ordered_user" } ],
U2I2I 召回¶
{
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "offline_etrec_i2i",
"TriggerType": "u2i",
"UserCollaborativeDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"User2ItemTable": "ali_rec_sln_u2i_trigger_list_holo"
},
"ItemIdName": "item_id",
"TriggerIdName": "trigger_id",
"UserTriggerRulesConf": {
"DefaultValue": 3,
"TriggerCounts": [
7,
7,
6,
5,
5,
3
]
}
}
TriggerType = u2i, 我们需要找出 user 发生过行为的 item 列表, 然后根据 I2I 进行召回。传给 BE 时,需要把 U2I 的trigger 构造好。 这里需要提供一个外部表。这里类似协同过滤的配置。
"UserCollaborativeDaoConf": { "AdapterType": "hologres", "HologresName": "pairec-holo", "User2ItemTable": "ali_rec_sln_u2i_trigger_list_holo" },
表结构
User2ItemTable 表
表字段
类型
字段说明
user_id
string
用户id, 保持唯一性
item_ids
string
用户浏览的 item id 列表。 支持形式: Itemid1,itemid2,itemid3 或者 itemid1:score1,itemid2:score2
trigger 打散设置¶
在组装 trigger 后,传给 BE 后,有可能前面几个 trigger 就能召回足够的数据,导致后面的 trigger 不起作用,这里我们可以指定每个 trigger 的限定数据量。
TriggerIdName UserTriggerRulesConf 配套使用, 限定每个 trigger召回数量,给到 BE
TriggerCounts 是个列表,依次根据给最大值的 score 匹配。 如果 trigger 列表长,从 defaultvalue 取值。如果defaultvalue 不提供,TriggerCounts 列表最后的值,当成 defaultvalue
适用于 TriggerType=u2i 或者 TriggerType= u2i_realtime
实时 U2I2I 召回¶
{
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "etrec_i2i",
"TriggerType": "u2i_realtime",
"UserTriggerDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"HologresTableName": "user_realtime_behavior_holo",
"WhereClause": "",
"Limit": 50,
"TriggerCount": 20,
"EventPlayTime": "",
"EventWeight": "click:1;pre_go:2;add_collection:3;go:4",
"WeightExpression": "exp(-0.2 * (currentTime-eventTime)/3600/24)",
"NoUsePlayTimeField": true
},
"PropertyFields": [
"child_brand_id_new",
"root_brand_id",
"child_category_id",
"vertical_id"
],
"DiversityRules": [
{
"Dimensions": [
"vertical_id"
],
"Size": 10
},
{
"Dimensions": [
"child_category_id"
],
"Size": 5
},
{
"Dimensions": [
"root_brand_id"
],
"Size": 3
},
{
"Dimensions": [
"child_brand_id_new"
],
"Size": 2
}
]
},
"ItemIdName": "item_id",
"TriggerIdName": "trigger_id",
"UserTriggerRulesConf": {
"DefaultValue": 3,
"TriggerCounts": [
7,
7,
6,
5,
5,
3
]
}
}
TriggerType = u2i_realtime, 可以实时的进行 U2I2I 的召回,思路就是实时获取到 U2I 的列表,然后组装 trigger 进行召回。具体原理参考这里。
额外的几个字段进行说明
Limit 是 获取 U2I 行为表的行数
TriggerCount 是最终计算出的 trigger 数量。如果没有显示指定此值, 会取 limit 的值
NoUsePlayTimeField 如果场景中没有 playtime的含义,设置为 true 即可
WeightMode 计算权重score 模式, max 或者 sum, 默认 sum
trigger 打散设置¶
和 u2i 设置一样的,限制 BE 中 每个 trigger 的召回数量, 需要设置 TriggerIdName 和 UserTriggerRulesConf。
通过 Limit 和 TriggerCount 可以选取最终 trigger 的数量。在这个选取过程中,我们希望做到 trigger 也能有一定的多样性。这时需要设置打散规则。
PropertyFields 打散规则需要根据不同的属性设置,这里指定哪些属性字段需要额外加载。
DiversityRules 根据维度字段(Dimensions 设置), 来设置 trigger 数量的上限,用 Size 表示。如果没有符合规则的 trigger ,我们会获取最大 score 的 trigger 进行填充
实时 dssm 向量召回¶
{
"Count": 600,
"RecallType": "x2i_recall",
"RecallName": "realtime_dssm_embedding",
"TriggerType": "user_realtime_embedding",
"UserRealtimeEmbeddingTrigger": {
"EmbeddingNum": 1200,
"RecallAlgo": "ali_recall_dssm_be_seq_rt",
"UserFeatureConfs": [
{
"FeatureDaoConf": {
"LoadFromCacheFeaturesName": "user_v1",
"FeatureStore": "user"
}
},
{
"FeatureDaoConf": {
"LoadFromCacheFeaturesName": "be_50_seq",
"FeatureStore": "user"
}
},
{
"FeatureDaoConf": {
"LoadFromCacheFeaturesName": "user_be_rt",
"FeatureStore": "user"
}
}
]
},
"ItemIdName": "item_id"
}
这里的执行流程是获取 user 特征, 然后调用 eas 模型 ali_recall_dssm_be_seq_rt,模型会实时算出 user embedding , 然后计算 item 的相似性,返回 item 列表。 然后把 item 列表传给 BE , 主要用于过滤数据。
TriggerType = user_realtime_embedding, 固定值
UserFeatureConfs 用户的特征加载逻辑,特征加载参考这里
RecallAlgo 模型的名称,在AlgoConfs 里能找到。需要注意, ResponseFuncName 要设置固定值 easyrecUserRealtimeEmbeddingResponseFunc
{
"Name": "ali_recall_dssm_be_seq_rt",
"Type": "EAS",
"EasConf": {
"Processor": "EasyRec",
"Timeout": 300,
"ResponseFuncName": "easyrecUserRealtimeEmbeddingResponseFunc",
"EndpointType": "DIRECT",
"Url": "http://xxx.vpc.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/ali_recall_dssm_be_seq_rt",
"Auth": "xxx"
}
}
EmbeddingNum 告诉模型返回的 item 的数量
实时 mind 向量召回¶
{
"Count": 600,
"RecallType": "x2i_recall",
"RecallName": "realtime_mind_embedding",
"TriggerType": "user_realtime_embedding_mind",
"UserRealtimeEmbeddingTrigger": {
"EmbeddingNum": 500,
"RecallAlgo": "ali_recall_mind_be_seq",
"DistinctParamName": "",
"DistinctParamValue": "",
"UserFeatureConfs": [
{
"FeatureDaoConf": {
"LoadFromCacheFeaturesName": "user_v1",
"FeatureStore": "user"
}
},
{
"FeatureDaoConf": {
"LoadFromCacheFeaturesName": "be_50_seq",
"FeatureStore": "user"
}
}
]
},
"ItemIdName": "item_id"
}
和上面实时 dssm 的逻辑是一致的。
TriggerType = user_realtime_embedding_mind, 固定值
UserFeatureConfs 用户的特征加载逻辑,特征加载参考这里
RecallAlgo 模型的名称,在AlgoConfs 里能找到。需要注意, ResponseFuncName 要设置固定值 easyrecUserRealtimeEmbeddingMindResponseFunc
{
"Name": "ali_recall_mind_be_seq",
"Type": "EAS",
"EasConf": {
"Processor": "EasyRec",
"Timeout": 300,
"ResponseFuncName": "easyrecUserRealtimeEmbeddingMindResponseFunc",
"EndpointType": "DIRECT",
"Url": "http://1301055674620248.vpc.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/ali_recall_mind_be_seq",
"Auth": "YTcwZGU1ZTI4NGJmN2Y5ZmViM2Q0MDM4ZDczOTJmNDhlZmUzYzdiOQ=="
}
}
EmbeddingNum 告诉模型返回的 item 的数量
DistinctParamName 打散参数名称
DistinctParamValue 打散参数配置, 会构造 BE 请求键值对 {DistinctParamName}={DistinctParamValue}
过滤规则¶
BE 引擎在召回的过程中,也可以根据一定的规则进行数据过滤,比如常见的曝光过滤。比如上面的例子中,我们设置
"BeFilterNames": [
"UserExposureFilter",
"BizBlacklistFilter"
]
UserExposureFilter 就是曝光过滤的名称,BizBlacklistFilter 是自定义过滤规则的名称。
曝光过滤¶
通常的做法,在 BE 中就能进行数据过滤。在数据回流中,写入到 BE 中,在召回数据时,自然会过滤数据。但是通过数据回流是有一定的延迟性的,如果想及时的过滤掉下发的数据,我们需要借助外部的存储,把短时间内下发的数据存储起来,每次进行召回时,需要把过滤的数据获取到实时的传给 BE , BE 会进行实时的过滤。
"BeFilterConfs": [
{
"Name": "UserExposureFilter",
"FilterType": "User2ItemExposureFilter",
"MaxItems": 50,
"TimeInterval": 600,
"WriteLog": true,
"DaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"HologresTableName": "exposure_history_prepub"
}
}
]
这里的曝光过滤和这里的类似,只不过需要定义在 BeFilterConfs 中。
Name 自定义的曝光过滤名称
FilterType 过滤类型,固定值 User2ItemExposureFilter
MaxItems 获取最近的条目批次数量,相当于 limit ${MaxItems}, MaxItems 这里不是指的具体的 item 数量, 而是批次的概念,也就是说一次推荐请求算作是一次,和一次请求里有多个具体的物料 item 无关
TimeInterval 按照时间戳取最近的过滤条目。 create_time >= ${current_time - TimeInterval }
WriteLog 是否写入曝光日志。
DaoConf 曝光表的定义
自定义过滤¶
有些时候,需要自定义过滤规则来通过 BE 实现,过滤规则通过 KV 结构传到 BE 侧。 PAI-REC 引擎支持自定义的过滤规则。需要实现以下接口
type IBeFilter interface {
BuildQueryParams(user *module.User, context *context.RecommendContext) map[string]string
}
实现接口后,通过 AddStartHook 进行注册
pairec.AddStartHook(func() error {
berecall.RegisterFilter("BizBlacklistFilter", &befilter.BizBlacklistFilter{})
return nil
})
BE AB 参数的支持¶
BE 也会支持一些自定义参数来支持召回逻辑的调整。在传给 BE 时,需要设置好相关的 KV 参数。 引擎也支持这类规则的设置。
"BeABParams":{
"click_filter_secs": 3600,
"click_filter_count": 500
}
配置中心AB 实验参数的支持¶
在引擎侧可以配置 BE 相关的配置,但是我们希望在 AB 实验上也能灵活的支持相关的召回实验,在引擎侧,我们也预定了一些实验参数来更方便的设置。
参数名称 |
参数类型 |
参数说明 |
样例 |
---|---|---|---|
“recall.” + be 召回名称 + “.beABParams” |
json object |
BE AB 参数的设置,需要注意的是,这里beABParams 会全面覆盖引擎侧的配置 |
“recall.BeRecallV3.beABParams”:{“expose_filter_count”:5000} |
“recall.” + be 召回名称 + “.includeRecalls” |
json array |
包含的子路召回的列表 |
“recall.BeRecallV3.includeRecalls”:[“etrec_i2i”] |
“recall.” + be 召回名称 + “.excludeRecalls” |
json array |
排除子路召回的列表 |
“recall.BeRecallV3.excludeRecalls”:[“etrec_i2i”] |
“recall.” + be 召回名称 + “.” + 子路召回的名称 |
json object |
某一路子路的召回配置 |
“recall.BeRecallV3.etrec_i2i”:{ |
具体的实例来详细的说明下。
假设 BeRecall 的配置中有 be ab 参数的设置
"BeABParams":{
"click_filter_secs": 3600,
"click_filter_count": 500
}
如果希望在实验中进行调整,可以这样设置
"recall.BeRecall.beABParams":{
"click_filter_secs": 7200,
"click_filter_count": 1000
}
BeRecall 包含很多路召回,但在某个实验中只想包含 retarget_u2i, etrec_u2i, offline_etrec_u2i, global_hot 这几路召回,可以这样设置
"recall.BeRecall.includeRecalls":[
"etrec_i2i",
"retarget_u2i",
"offline_etrec_u2i",
"global_hot"
]
如果只想排除某些路召回,可以这样设置
"recall.BeRecall.excludeRecalls":[
"retarget_u2i",
"global_hot"
]
假设 etrec_u2i 配置如下
{
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "etrec_i2i",
"TriggerType": "u2i_realtime",
"UserTriggerDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"HologresTableName": "user_realtime_behavior_holo",
"WhereClause": "",
"Limit": 50,
"TriggerCount": 20,
"EventPlayTime": "",
"EventWeight": "click:1;pre_go:2;add_collection:3;go:4",
"WeightExpression": "exp(-0.2 * (currentTime-eventTime)/3600/24)",
"NoUsePlayTimeField": true
}
}
但希望在实验中,对 etrec_i2i 这一路召回增加打散相关的配置。我们可以把调整后的配置都放到实验参数里。可以这样设置
"recall.BeRecall.etrec_i2i": {
"Count": 75,
"RecallType": "x2i_recall",
"RecallName": "etrec_i2i",
"TriggerType": "u2i_realtime",
"UserTriggerDaoConf": {
"AdapterType": "hologres",
"HologresName": "pairec-holo",
"HologresTableName": "user_realtime_behavior_holo",
"WhereClause": "",
"Limit": 50,
"TriggerCount": 20,
"EventPlayTime": "",
"EventWeight": "click:1;pre_go:2;add_collection:3;go:4",
"WeightExpression": "exp(-0.2 * (currentTime-eventTime)/3600/24)",
"NoUsePlayTimeField": true
},
"PropertyFields": [
"child_brand_id_new",
"root_brand_id",
"child_category_id",
"vertical_id"
],
"DiversityRules": [
{
"Dimensions": [
"vertical_id"
],
"Size": 10
},
{
"Dimensions": [
"child_category_id"
],
"Size": 5
},
{
"Dimensions": [
"root_brand_id"
],
"Size": 3
},
{
"Dimensions": [
"child_brand_id_new"
],
"Size": 2
}
]
},
"ItemIdName": "item_id",
"TriggerIdName": "trigger_id",
"UserTriggerRulesConf": {
"DefaultValue": 3,
"TriggerCounts": [
7,
7,
6,
5,
5,
3
]
}
}