本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。
PAI-Rec 引擎已经内置了多个过滤模板,包括曝光过滤、状态过滤、数量调整过滤等。
如何配置
过滤的配置对应配置总览中的 FilterConfs,FilterConfs 是一个[]object 结构,可以定义多个过滤策略。
过滤公共配置一览
每种召回配置,都会用到公共配置中的一部分,在此统一解释,单独的召回配置中则不再赘述。
配置示例:
{
"FilterConfs": [
{
"Name": "",
"FilterType": "",
"Dimension": "",
"DaoConf": {},
"AdjustCountConfs": [],
"ItemStateDaoConf": {},
"FilterParams": [],
"DiversityDaoConf": {},
"FilterVal": {}
}
]
}
字段 | 类型 | 是否必填 | 描述 |
Name | string | 是 | 过滤的自定义名称,可以在 FilterNames 中引用 |
FilterType | string | 是 | 引擎内置过滤类型,枚举值,目前支持:
|
Dimension | string | 否 | item 的维度字段 |
DaoConf | DaoConfig | 否 | 数据源表的一些信息 |
AdjustCountConfs | 否 | 优先级数量调整过滤的配置 | |
ItemStateDaoConf | 否 | 状态过滤的配置 | |
FilterParams | 否 | 上下文条件的配置 |
曝光过滤(User2ItemExposureFilter)
很多业务场景都需要曝光过滤来避免重复推荐,通常的曝光过滤做法是伪曝光和真实曝光的组合。
伪曝光:因为实时日志有延时等原因,我们并不能立刻知道哪些 item 被曝光,所以我们把推荐引擎返回的 item 列表作为伪曝光列表。
真实曝光:需要客户的实时日志,通过Flink 这种实时计算引擎写入数据库,然后被PAI-Rec 引擎消费。
不同数据源的曝光过滤有以下几个公共参数配置:
字段名 | 类型 | 是否必填 | 描述 |
Name | string | 是 | 自定义过滤名称 |
FilterType | string | 是 | 过滤类型,固定值 User2ItemExposureFilter |
MaxItems | int | 是 | 获取最近的条目批次数量,相当于 limit ${MaxItems}, MaxItems 这里不是指的具体的 item 数量, 而是批次的概念,也就是说一次推荐请求算作是一次,和一次请求里有多个具体的物料 item 无关 |
TimeInterval | int | 是 | 按照时间戳取最近多长时间内的条目,单位秒 |
WriteLog | bool | 是 | 是否写入曝光日志 |
ClearLogIfNotEnoughScene | string | 否 | 对某个场景下曝光表中的数据进行删除 |
GenerateItemDataFuncName | string | 否 | 构造写入曝光表item数据的函数,为空时,会使用 PAI-Rec内置的函数,内置函数只返回 item_id |
WriteLogExcludeScenes | []string | 否 | 哪些场景不进行曝光日志的写入 |
Hologres
{
"FilterConfs": [
{
"Name": "holo_exposure_filter",
"FilterType": "User2ItemExposureFilter",
"MaxItems": 100,
"TimeInterval": 172800,
"WriteLog": true,
"DaoConf": {
"AdapterType": "hologres",
"HologresName": "holo_info",
"HologresTableName": "exposure_history"
}
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,取值 hologres |
HologresName | string | 是 | 在数据源配置(HologresConfs)中配置好的 holo 的自定义名称,如数据源配置中的 holo_info |
HologresTableName | string | 是 | 曝光表名称 |
曝光表定义注意这里可以 按照实际的情况设置 time_to_live_in_seconds 。
BEGIN;
CREATE TABLE "exposure_history" (
"uid" text NOT NULL,
"item" text NOT NULL,
"create_time" int4 NOT NULL
);
CALL SET_TABLE_PROPERTY('"exposure_history"', 'orientation', 'column');
CALL set_table_property('"exposure_history"', 'distribution_key', 'uid');
CALL SET_TABLE_PROPERTY('"exposure_history"', 'clustering_key', '"uid","create_time"');
CALL SET_TABLE_PROPERTY('"exposure_history"', 'segment_key', '"create_time"');
CALL SET_TABLE_PROPERTY('"exposure_history"', 'bitmap_columns', '"uid","item"');
CALL SET_TABLE_PROPERTY('"exposure_history"', 'dictionary_encoding_columns', '"uid","item"');
CALL SET_TABLE_PROPERTY('"exposure_history"', 'time_to_live_in_seconds', '172800');
comment on table "exposure_history" is '曝光记录表';
COMMIT;
PAI-FeatureStore
FeatureStore 内置的在线数据源 FeatureDB使用布隆过滤器算法支持PAI-Rec 的曝光过滤的需求。
FeatureStore 通过创建实时FeatureView来支持曝光表。设置参考如下:
重点参数说明下:
类型选择 实时 。
特征实体 选择 user 。
特征字段需要填入 user_id、item_id、timestamp。 其中 user_id 为主键, timestamp 勾选 事件时间。 主键 和 事件时间是必须选择的。 数据类型上, user_id、item_id 都是 string , timestamp 是 int64 。
特征生命周期,这里默认是 2 天。 需要按实际情况调整。 对于一个用户来说, 曝光的条目需要保留多长时间。
高级配置必填, 输入 {"table_type":"bloom", "expose_count":5000},table_type 说明创建的是支持 bloom filter 的 table 。 expose_count 是对于单个用户来说,保留的曝光条目的最大数量。
PAI-Rec 引擎中的曝光过滤配置参考如下:
{
"FilterConfs": [
{
"Name": "fs_exposure_filter",
"FilterType": "User2ItemExposureFilter",
"TimeInterval": 300,
"WriteLog": true,
"DaoConf": {
"AdapterType": "featurestore",
"FeatureStoreName": "fs_pairec",
"FeatureStoreViewName": "user_expose"
}
}
]
}
TimeInterval 单位是秒。 这块是引擎写入伪曝光条目的最大保留时间。当 WriteLog = true时是有效的。上面是伪曝光的配置,如果是真实曝光,PAI-Rec 引擎不负责写入数据,设置WriteLog为false,并且TimeInterval可以不设置。
真实曝光的配置如下:
"FilterConfs": [
{
"Name": "fs_exposure_filter2",
"FilterType": "User2ItemExposureFilter",
"WriteLog": false,
"DaoConf": {
"AdapterType": "featurestore",
"FeatureStoreName": "fs_pairec",
"FeatureStoreViewName": "user_expose"
}
}
]
我们可以使用同一个FeatureView表来支持伪曝光和真实曝光。
真实曝光的数据写入可以参考写入特征。
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,取值 featurestore |
FeatureStoreName | string | 是 | 在数据源配置(FeatureStoreConfs)中配置好的 FeatureStore 的自定义名称,如数据源配置中的 fs_pairec |
FeatureStoreViewName | string | 是 | 曝光表FeatureView名称 |
Redis
{
"FilterConfs": [
{
"Name": "redis_exposure_filter",
"FilterType": "User2ItemExposureFilter",
"MaxItems": 100,
"TimeInterval": 172800,
"WriteLog": true,
"DaoConf": {
"AdapterType": "redis",
"RedisName": "redis_info",
"RedisPrefix": "exposure_"
}
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,取值 redis |
RedisName | string | 是 | 在数据源配置(RedisConfs)中配置好的 Redis 的自定义名称,如数据源配置中的 redis_info |
RedisPrefix | string | 否 | 曝光数据的 key 前缀,key = RedisPrefix + uid |
TableStore
{
"FilterConfs": [
{
"Name": "ots_exposure_filter",
"FilterType": "User2ItemExposureFilter",
"MaxItems": 100,
"TimeInterval": 172800,
"WriteLog": true,
"DaoConf": {
"AdapterType": "tablestore",
"TableStoreName": "tablestore_info",
"TableStoreTableName": "exposure_history"
}
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,枚举值,如 hologres、mysql、tablestore 等 |
TableStoreName | string | 是 | 在数据源配置(TableStoreConfs)中配置好的 tablestore 的自定义名称,如数据源配置中的 tablestore_info |
TableStoreTableName | string | 是 | 曝光表名称 |
曝光表定义如下:
生命周期:(用户需要自定义,必须有一个明确的周期)
maxVersion: 1
字段 | 类别 | 类型 | 说明 | 示例 |
user_id | 主键 | string | 用户唯一id | 10944750 |
auto_id | 主键 | integer | 自增列 | |
item_ids | 属性 | string | item 唯一id 列表,多个以 ',' 分隔, 如果一次曝光可以包含多个 item_id 的话,可以插入一行数据即可 | 17019277,17019278 |
User2Item自定义过滤(User2ItemCustomFilter)
Hologres
用户需要提供一个自定义的 user2item 的过滤表,进行数据过滤。过滤表一般是离线产出,例如每天凌晨汇总每个用户过去15天看过的物品(即有曝光行为的物品),按照逗号分隔放在一个字段item_ids中。
{
"FilterConfs": [
{
"Name": "u2i_custom_filter",
"FilterType": "User2ItemCustomFilter",
"DaoConf": {
"AdapterType": "hologres",
"HologresName": "holo_info",
"HologresTableName": "u2i_custom_filter"
},
"ItemStateCacheSize": 10000,
"ItemStateCacheTime": 3600
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,固定值 hologres 。 |
HologresName | string | 是 | 在数据源配置(HologresConfs)中配置好的 hologres 的自定义名称,如数据源配置中的 holo_info。 |
HologresTableName | string | 是 | 自定义曝光表名称。 |
ItemStateCacheSize | int | 否 | 开启缓存的情况下,可以缓存的条目数量。如果此值大于0, 默认会开启缓存。 |
ItemStateCacheTime | int | 否 | 开启缓存的情况下,缓存条目的生命周期。默认值为 3600, 单位:秒。 |
表定义如下:
字段 | 类别 | 类型 | 说明 | 示例 |
user_id | 主键 | string | 用户唯一id | 10944750 |
item_ids | 属性 | string | item 唯一id 列表,多个以 ',' 分隔 | 17019277,17019278 |
TableStore(OTS)
用户需要提供一个自定义的 user2item 的过滤表,进行数据过滤。
{
"FilterConfs": [
{
"Name": "u2i_custom_filter",
"FilterType": "User2ItemCustomFilter",
"DaoConf": {
"AdapterType": "tablestore",
"TableStoreName": "tablestore_info",
"TableStoreTableName": "u2i_table"
}
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,固定值 tablestore |
TableStoreName | string | 是 | 在数据源配置(TableStoreConfs)中配置好的 tablestore 的自定义名称,如数据源配置中的 tablestore_info |
TableStoreTableName | string | 是 | 自定义曝光表名称 |
表定义如下:
字段 | 类别 | 类型 | 说明 | 示例 |
user_id | 主键 | string | 用户唯一id | 10944750 |
item_ids | 属性 | string | item 唯一id 列表,多个以 ',' 分隔 | 17019277,17019278 |
PAI-FeatureStore
仅支持在线数据源为FeatureDB的FeatureView。
和上文提到的曝光过滤类似,也是提供一个实时的FeatureView, 通过 java sdk 或者 flink connector 写入数据,数据写入可以参考写入特征。PAI-Rec 引擎通过读取这里的数据进行过滤。FeatureView 的配置如下:
重点参数说明下:
类型选择 实时 。
特征实体 选择 user 。
特征字段需要填入 user_id、item_id、timestamp。 其中 user_id 为主键, timestamp 勾选 事件时间。 主键和事件时间是必须选择的。 数据类型上, user_id、item_id 都是 string , timestamp 是 int64 ,这里timestamp代表时间戳,单位毫秒。
特征生命周期,这里默认是 2 天。 需要按实际情况调整。这里可以理解成某一行数据的TTL,是根据timestamp字段传入的数值计算生命周期的。
高级配置必填, 输入 {"table_type":"bloom"},table_type 说明创建的是支持 bloom filter 的 table 。
PAI-Rec 引擎中的配置参考如下:
{
"FilterConfs": [
{
"Name": "u2i_custom_filter",
"FilterType": "User2ItemCustomFilter",
"DaoConf": {
"AdapterType": "featurestore",
"FeatureStoreName": "fs_pairec",
"FeatureStoreViewName": "u2icustom_filter"
}
}
]
}
DaoConf 配置说明
字段 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,固定值 featurestore 。 |
FeatureStoreName | string | 是 | 在数据源配置(FeatureStoreConfs)中配置好的 featurestore 的自定义名称。 |
FeatureStoreViewName | string | 是 | 自定义过滤表的featureview 名称。 |
数量调整过滤(AdjustCountFilter)
简单的调整数量,把召回数量随机打散,然后保留需要控制的数量。
配置示例:
{
"FilterConfs": [
{
"Name": "adjust_count_filter",
"FilterType": "AdjustCountFilter",
"ShuffleItem": true,
"RetainNum": 500
}
]
}
字段名 | 类型 | 是否必填 | 描述 |
ShuffleItem | string | 是 | 是否打散 |
RetainNum | string | 是 | 打散之后保留的数量 |
优先级数量调整过滤(PriorityAdjustCountFilter)
优先级过滤可以对各路召回进行数量控制,每路召回都会根据召回的 score 进行排序
配置示例:
{
"FilterConfs": [
{
"Name": "priority_adjust_count_filter",
"FilterType": "PriorityAdjustCountFilter",
"AdjustCountConfs": [
{
"RecallName": "recall_1",
"Count": 125,
"Type": "accumulator"
},
{
"RecallName": "recall_2",
"Count": 250,
"Type": "accumulator"
},
{
"RecallName": "recall_3",
"Count": 400,
"Type": "accumulator"
}
]
}
]
}
字段名 | 类型 | 是否必填 | 描述 |
Name | string | 是 | 自定义的过滤名称 |
FilterType | string | 是 | 过滤类型,固定值 PriorityAdjustCountFilter |
RecallName | string | 是 | 召回源名称 |
AdjustCountConfs | json array | 是 | 优先级配置 |
| int | 是 | 此路召回限制的数量 |
| string | 否 | Type 限制类型,枚举值:accumulator 或 fix。 accumulator 为累加限制。
fix 为固定限制:
|
状态过滤(ItemStateFilter)
我们经常需要对召回的数据,进行状态过滤。item 的状态有可能会实时变动的,一般会有专有的表存储 item 状态。 此过滤流程需要实时获取 item 状态信息,然后进行过滤。
hologres
{
"FilterConfs": [
{
"Name": "ItemStateFilter",
"FilterType": "ItemStateFilter",
"ItemStateDaoConf": {
"AdapterType": "hologres",
"HologresName": "",
"HologresTableName": "",
"ItemFieldName": "",
"WhereClause": "",
"SelectFields": ""
},
"ItemStateCacheSize": 50000,
"ItemStateCacheTime": 3600,
"FilterParams": [
]
}
]
}
如果item的状态不经常变化,可以配置缓存选项。
字段名 | 类型 | 是否必填 | 描述 |
ItemStateCacheSize | int | 否 | 要缓存数量。 |
ItemStateCacheTime | int | 否 | 缓存的时间,单位:秒。 |
ItemStateDaoConfig 定义如下:
字段名 | 类型 | 是否必填 | 描述 |
AdapterType | string | 是 | 数据源的类型,枚举值,如 hologres、mysql、tablestore 等 |
HologresName | string | 是 | 在数据源配置(HologresConfs)中配置好的 holo 的自定义名称,如数据源配置中的 holo_info |
HologresTableName | string | 是 | holo 中 item 状态表的表名 |
ItemFieldName | string | 是 | item 状态表的主键 |
WhereClause | string | 否 | 条件过滤语句 |
SelectFields | string | 是 | 需要获取的字段 |
FilterParams 定义如下:
{
"FilterParams": [
{
"Name": "publicStatus",
"Type": "int",
"Operator": "equal",
"Value": 0
},
{
"Name": "state",
"Type": "int",
"Operator": "equal",
"Value": 1
},
{
"Name": "checkStatus",
"Type": "int",
"Operator": "not_equal",
"Value": 2
},
{
"Name": "norec",
"Type": "int",
"Operator": "not_equal",
"Value": 1
}
]
}
字段名 | 类型 | 是否必填 | 描述 |
Name | string | 是 | 特征名 |
Domain | string | 否 | 特征所属,枚举值:user/item |
Operator | string | 是 | 操作符,支持 equal、not_equal、in, greater , greaterThan , less, lessThan |
Type | string | 是 | 特征的类型 |
Value | object | 是 | 条件值 |
注:WhereClause 和 FilterParams都可以过滤,WhereClause 是在查询的时候过滤,FilterParams是在本地过滤。
具体的 Operator 的使用,可以参考附录。
CompletelyFairFilter
根据召回条目的 score 进行排序,然后公平的从每一路召回获取数据
{
"FilterConfs": [
{
"Name": "CompletelyFairFilter",
"FilterType": "CompletelyFairFilter",
"RetainNum": 500
}
]
}
DimensionFieldUniqueFilter
和 UniqueFilter 不同, 根据 item 的某个字段进行去重过滤
{
"FilterConfs": [
{
"Name": "DimensionFieldUniqueFilter",
"FilterType": "DimensionFieldUniqueFilter",
"Dimension": ""
}
]
}
字段名 | 类型 | 是否必填 | 描述 |
Name | string | 是 | 自定义的过滤名称。 |
FilterType | string | 是 | 过滤类型,固定值DimensionFieldUniqueFilter。 |
Dimension | string | 是 | item属性字段,根据这个字段进行去重。如果 item 的这个属性字段为空,则会保留这个item 。 |
UniqueFilter
唯一性过滤,保证 item id 是唯一的,如果两路召回包含同一个 item id,哪路召回先返回,取哪一路的 item id。
无需配置,可直接在 FilterNames 中引用。
如何使用
过滤配置和召回配置类似,配置好后,提供一个分场景使用的 FilterNames,FilterNames 是一个 Map[string]object 结构,其中 key 是场景,每个场景对应一组过滤策略
"FilterNames": {
"${scene_name}": [
"UniqueFilter"
]
}
${scene_name} 为场景名,如果多个场景想使用同一个配置,则可以使用 "default"。
UniqueFilter: 此参数为在 FilterConfigs 中定义的过滤自定义名称。
附录
条件匹配 Operator 示例
equal (相等 ==)
{
"Name": "publicStatus",
"Type": "int",
"Operator": "equal",
"Value": 0
}
not_equal (不等于 !=)
{
"Name": "checkStatus",
"Type": "int",
"Operator": "not_equal",
"Value": 2
}
greater (大于 >)
{
"Name": "checkStatus",
"Type": "int",
"Operator": "greater",
"Value": 2
}
greaterThan (大于等于 >=)
{
"Name": "checkStatus",
"Type": "int",
"Operator": "greaterThan",
"Value": 2
}
less (小于 <)
{
"Name": "checkStatus",
"Type": "int",
"Operator": "less",
"Value": 2
}
lessThan (小于等于 <=)
{
"Name": "checkStatus",
"Type": "int",
"Operator": "lessThan",
"Value": 2
}
in (与数组中某个条目匹配)
{
"Name": "state",
"Type": "int",
"Operator": "in",
"Value": [2,4,6]
}
string 类型
{
"Name": "state",
"Type": "string",
"Operator": "in",
"Value": ["success","ok"]
}