亿级毫秒响应实时推荐系统-解决方案探索

Posted DB印象

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了亿级毫秒响应实时推荐系统-解决方案探索相关的知识,希望对你有一定的参考价值。

阅读使人充实,讨论使人敏捷,写作使人精确。

>>前    言

最近接触推荐相关业务需求过程中参考了不少德哥的文章,收益良多,强烈推荐德哥文章链接:https://github.com/digoal


 业务应用场景


假如某个主播平台资源中,共有2000w主播,运营关注到Aken在平台上比较喜欢A主播,期盼给他推荐更多和A类似的主播,1个或N多个。


站在技术角度,我们如何去实现?


假如来1个千万级数据全量搜索计算,现有的Mongodb、mysql、Oracle等技术组件毫秒级有没有这个可能?


亿级毫秒响应实时推荐系统-解决方案探索   为什么要讨论这个问题

DT数据时代,通过用户画像条件组合,快速提取精准目标群体进行精准营销,已经是当今行业的普遍需求。例如:


淘宝平台根据用户购买习惯,推荐相关商品。

头条网站根据用户浏览习惯,推荐相关资讯。

网易云音乐根据用户听歌喜好,推荐相关歌曲。


因此这本质上是一个:实时推荐系统的问题。


亿级毫秒响应实时推荐系统-解决方案探索 通用的解决方案


营销推荐基于用户画像,通用解决方案是给用户贴标签,然后根据标签组合,圈出需要的用户。


表现在数据库层面,通常会用到宽表,以及分布式的系统。宽表用于存储用户标签,例如每个字段代表一个标签,业务查询语句通过标签字段进行组合,搜索符合条件的id,即目标用户或推荐对象。


回到上面主播推荐的业务场景,画像表的设计会是下面这个样子:

create table tab_aken_signature (   uid  int primary key,    tag1 float4,  -- 主播属性1  tag2 float4,  -- 主播属性2...   tagn float4   -- 主播属性n  ); 

亿级毫秒响应实时推荐系统-解决方案探索 通用的解决方案的痛点

用户、主播特征属性多,容易突破单表限度

运营为了提 高效率效率,标签数量通常会非常多,行业内有100个标签的算是非常小的了,标签高达千个、上万个已不属罕见。 因此,标签数量往往会突破关系型DB的字段数量或行宽限制,比如MySQL innodb表字1024上限,比如mongodb的单条文档大小16MB,这时候就需要分库分表,将字段拆解到多个表或集合中。 比如目前公司用户画像100多个标签使用Json拆到了多个collection中。 拆分后类似join等逻辑需要依靠应用层实现。

用户喜好类型多样化,单一索引搜索困难

标签的组合具有不固定性,很难通过单一索引或部分字段索引达到高效检索的目的,如果为提高性能,1千个字段就需要创建1千个索引,存储成本非常高。

l  组件不一定支持智能算法相关计算技术

推荐 需要依靠巨大的数据集进行排序,然后去top N,如果数据库组件本身无法高效支持该计算场景 ,需要应用逻 辑计算到具体uid才能进入DB进行key-value进行快速召回。

亿级毫秒响应实时推荐系统-解决方案探索 推荐系统的改进方案

考虑到通 用方案存在的以上问题,我们可以将上游计算和数据读取分为两个独立的链路,利用流水上报服务将用户流水操作flink/spark在DB外围计算得到具体的标签、权重等信息,然后将计算结果回写DB或ES、ClickHou集群,并将具体的uid传给推荐服务作为拉取DB数据的条件,这样就实现了具体key获取对应数据的转化。

但前提是必须由下游数仓DW或其他渠道定期供数到在线系统。


  改进方案的痛点

整套系统需要依赖数据仓库通过etl/spark/flink等定期加载数据到关系型数据库里面,然后数据计算及推荐服务逻辑完全需要依靠DB外围的算法实现。 这里会存在以下几个主要问题:

推荐时效只能做到离线推荐或准时性推荐。
假设画像数据从数仓按天入库,推荐计算至多只能基于昨天的动态进行,时效延迟1天,无法满足用户行为更新频繁、时效要求高的业务场景,从而可能导致错失不少目标用户群体。
比如我昨天在平台浏览并下单购买了笔记本,然后推荐服务今天才对我进行笔记本电脑导购推荐,这个信息完全延迟了一天,哪怕你的推荐算法再精确,我早已经成为了无效目标用户。
数据一致性问题
计算层缓存需定期回写DB,会和数据库存储之间存在一定的延迟,对数据一致性较高的服务,会有更大的挑战,需要加大成本优化。

性能可能比较低
完整的推荐逻辑需要多个架构层及系统进行交互,目前接触的系统如果推荐请求可以直接命中推荐服务本地cache,则完整的推荐逻辑大概耗时300~400ms,当推荐请求无法命中本地cache,重走召回逻辑,则耗时大概700~800ms甚至更高

独立的智能算法团队支持,比如向量计算相关的开发技术。

  基于PostgreSQL的新方案探索


首先,对于推荐系统,我理解的核心思想有两点:

1.给用户推荐那些和他们喜欢物品相似的物品。

2.喜欢物品怎么表示,以及物品之间相似度怎么计算是需要我们重点考虑的。


新方案探索-数据表示
画像属性: 从多列标签或多key设计方式,将特征数据位图化、向量化(内容、用户、环境等)
uid  int    ---primary key,每个uid代表一个推荐对象tagval bit(64) ---文本标签转位图tagarr text[]  ---元素列表或元组加权

新方案探索-数据存储
当特征数据位图和向量化之后,我们并不需要传统的宽表模式
akendb=# \d+ tab_aken_signature Table "public.tab_aken_signature" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------+-----------+----------+---------+----------+--------------+------------- id | integer | | | | plain | |  tagval  | bit(64) |           |          |         | extended |               tagarr  | text[]  |           |          |         | extended |              | Indexes:    "idx_tagarr" gin (tagarr _text_sml_ops)    Access method: heapakendb=

新方案探索-索引方式

Btree 改为 g in 索引 (G eneralized Inverted Index)。 gin 存储 ( key, posting list ), Bt ree 相比 gin 索引更适合多值类型的元素搜索
akendb=# create extension smlar;CREATE EXTENSIONakendb=# create index idx_signature on tab_aken_signature using gin(tagarr _text_sml_ops )

新方案探索-数据计算
于向量矩阵,使用相似算法,如: Euclidean Distance n、 overlap distance 等。
select id,tagarr from tab_aken_signature where tagarr % '{1_0110110101111001,2_0111100111100000,3_1010110010111110,4_1011111011110100}' limit 10;
关于PostgreSQL兼容的更多相似算法,参考:
https://github.com/eulerto/pg_similarity

新方案探索-测试模型
随机1亿主播,设置64个主播特征,向量化。
insert into tab_aken_signature   select id,val::bit(64),regexp_split_to_array('1_'||substring(val,1,16)||',2_'||substring(val,17,16)||',3_'||substring(val,33,16)||',4_'||substring(val,41,16), ',')    from (select id, (sqrt(random())::numeric*9223372036854775807*2-9223372036854775807::numeric)::int8::bit(64)::text as val from generate_series(1,156250) t(id)) t;   nohup pgbench -h 9.107.133.92 -p 11005 -U tbase -d akendb -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 10 -t 10 &
测试数据验证:
akendb=# select count(*) from tab_aken_signature; count ----------- 100000000(1 row)akendb=# select * from tab_aken_signature limit 10;  id | tagval | tagarr ----+------------------------------------------------------------------+------------------------------------------------------------------------------- 1 | 0101011101100100100101111001000100010110101011101111111001100111 | {1_0101011101100100,2_1001011110010001,3_0001011010101110,4_1010111011111110} 2 | 1110001100010000101010110010010000111110110000011000100001001011 | {1_1110001100010000,2_1010101100100100,3_0011111011000001,4_1100000110001000} 3 | 0110111011001011001101110111111111001000011101010010010000100100 | {1_0110111011001011,2_0011011101111111,3_1100100001110101,4_0111010100100100}

推荐测试1-以点搜点
场景: 以歌搜单曲、以人搜人(主播)等。
如下根据用户喜好,在1亿主播中推荐最类似的主播,耗时Time: 2.643 ms。
akendb=# set smlar.type = overlap; akendb=# set smlar.threshold = 2;  --在相似度超过50%的主播中推荐完全相似的1个akendb=# select smlar( tagarr, '{1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101}')  as similarity,length(replace(bitxor(bit'0100001010100000010011111000111101001111111011010010110100101111', tagval)::text,'0','')) hm_distance,*  from tab_aken_signature  where tagarr % '{1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101}'      and length(replace(bitxor(bit'0100001010100000010011111000111101001111111011010010110100101111', tagval)::text,'0','')) < 2  limit 100;
similarity | hm_distance | id | tagval | tagarr ------------+-------------+----+------------------------------------------------------------------+------------------------------------------------------------------------------- 4 | 0 | 8 | 0100001010100000010011111000111101001111111011010010110100101111 | {1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101}(1 row)Time: 2.643 msakendb=

推荐测试1-以点搜群
场景: 以文章搜文章集合、以歌曲搜歌单列表、以人搜社交群体等。
下根据用户喜好,在1亿数据中且相似度超过50%的主播中推荐30个(或N个)主播,耗时 Time: 2.797 ms
akendb=# set smlar.type = overlap; akendb=# set smlar.threshold = 2;    --在相似度超过50%的主播中推荐最相似的30个akendb=#select smlar( tagarr, '{1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101}')  as similarity ,  length(replace(bitxor(bit'0100001010100000010011111000111101001111111011010010110100101111', tagval)::text,'0','')) as hm_distance,id,tagarrfrom tab_aken_signature    where tagarr % '{1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101}' order by similarity desc,hm_distance  limit 30  similarity | hm_distance | id | tagarr ------------+-------------+--------+------------------------------------------------------------------------------- 4 | 0 | 8 | {1_0100001010100000,2_0100111110001111,3_0100111111101101,4_1110110100101101} 2 | 13 | 73473 | {1_0101001001100010,2_0100011000001110,3_0100111111101101,4_1110110100101101} 2 | 16 | 27276 | {1_0101001111000101,2_0101010000001111,3_0100111111101101,4_1110110100101101} 2 | 16 | 82574 | {1_0101010011110001,2_0111001101001010,3_0100111111101101,4_1110110100101101} 2 | 18 | 55714 | {1_0111110101111011,2_1100111110111110,3_0100111111101101,4_1110110100101101} 2 | 18 | 68023 | {1_0101101010001100,2_1000111111110011,3_0100111111101101,4_1110110100101101} 2 | 20 | 153629 | {1_0111001011001110,2_0001100111111010,3_0100111111101101,4_1110110100101101} 2 | 20 | 100863 | {1_0100100000101101,2_1011101101101110,3_0100111111101101,4_1110110100101101} 2 | 24 | 149608 | {1_1010110011111011,2_0011001010000001,3_0100111111101101,4_1110110100101101} 2 | 24 | 56512 | {1_0010101100010110,2_1001101000100010,3_0100111111101101,4_1110110100101101} 2 | 26 | 78559 | {1_1011001010001110,2_0011010101000000,3_0100111111101101,4_1110110100101101}(11 rows)Time: 2.797 msakendb=#

新方案探索-效果对比
1.相对于通用流行方案,新方案可以将服务时效从秒级的离线推荐晋级到毫秒级实时推荐。
2.索相对于通用流行方案,新方案在索引及数据计算上,在传统btree基础丰富了如gin、gist等索引技术,通过简单extension扩展即可支持多种相似算法,无需依赖独立的向量计算技术攻坚团队。
当然,如果公司内有专业算法团队,能将相关算法扩展到pg则会更好。
3. 相对于 通用 流行方案,新方案在整体的架构和组件复合上会显得更加精简,对组件的运维复杂度及运营成本也会随之下降,而在架构上给系统加持cache来解决高并发问题,将会使基于pg的方案显得更加强健。

>>>

参考资料

1.https://github.com/digoal

2.https://github.com/jirutka/smlar

3.https://github.com/eulerto/pg_similarity


        
          
          
        

往期推荐

1.

2.

                               

                         ------让学习成为一种习惯-Aken

以上是关于亿级毫秒响应实时推荐系统-解决方案探索的主要内容,如果未能解决你的问题,请参考以下文章

推荐系统[九]项目技术细节讲解z4:向量检索技术工程上实践,曝光去重实践以及检索引擎该如何选择:支撑亿级索引5毫秒级的检索[elasticsearchmilvus]

亿级用户,腾讯看点信息流推荐系统的架构挑战

查询亿级数据毫秒级返回!Elasticsearch 是如何做到的?丨极客时间

mysql搭建亿级cmd5数据库,毫秒级查询 完全过程

Redis百亿级Key存储方案

有赞亿级订单同步的探索与实践