实现实时个性化推荐_左高玩的推荐系统(一):一天就能搞定的实时个性化推荐系统...

6f082cc76cf4dea8d495033b1c21fbd9.png

左高玩是我的大学同学,编程界的高端玩家,江湖人称左高玩。先爆个照,是不是艺术气息浓重。

0bcf1024bda1bea42cdf27053e26c89b.png

最近左高玩创业了,做内容社区,有一天约我出来吃饭,说内容量过万了,想做个推荐系统,不用特别牛逼,关键是要快,先run起来。

我:“做一个item-base的协同过滤,把用户的消费行为实时记录好,你就拥有了一个实时反馈用户行为的推荐系统了。”

左高玩:“一个星期搞得定么?”

我:“你一天就能搞定。”

左高玩:“我数学不好,算法不行啊。。。”

我:“会打代码就行。”

一天就搞定的推荐系统架构

af2e20acbdfa74eb2633b4628fd93594.png

埋点:用户在app上的行为,内容的曝光,用户的点击,进行记录并上报到服务端,最终储存在数据库中。另外行为数据也可以转储到文件系统中,用于内容协同过滤的计算。

用户实时行为:把每一个用户的点击行为实时存储起来,查询的时候可以拿到用户近期点击过的内容集合。

item-to-item(I2I):计算内容之间的相关度,存储成倒排索引的形式,当用户消费过内容

,系统通过倒排链找到
就是I2I。

每一个用户请求,先查询用户的实时历史行为,然后在以点击过的内容id作为key查询对应相似内容,将候选相似内容分数加起来,按照分数从高到低排序,就生成了推荐列表。

左高玩:“你说的这个埋点?我内容的详情页打开的时候,写一下数据库是不是就可以?”

我:“可以!不过当你有一天体量更大了,用户行为直接写数据库成本太高了,吞吐量低,大体量下成熟的架构是写入消息队列,如kafka。行为数据有两个用途,一个用于索引和查询实时用户行为,另一个是离线计算tem-to-item。前者你再加一个进程去消费队列,把数据平缓而均匀地写入数据库”

左高玩:“好麻烦。。。我决定10wDAU之前,还是直接写数据库。你说的I2I咋算?”

计算item-to-item

这个算法叫做Item-base的协同过滤,最终得到内容间的相似关系,它是稀疏的,可以组织成倒排索引的形式。

拿到了用户行为,每一个内容对应一个消费过它的用户集合,假设你的用户有100个,每一个内容就表示成了一个100维的向量,这个向量很稀疏,大多数位置都是0。现在计算向量的距离,代表他们之间的相似度。下图红线圈住的就是物品的向量表示。

bc1f7cfaf670b7ddd11856d121c4684b.png

就以余弦距离为例子吧。分母上边是内积,两个向量对应位置相乘再把每一位加起来,对应的意义就是用户同时点击两篇内容的次数;分母是两篇内容的模的乘机,模也就是内容的用户消费人数开平方。

74470b3e0c34aa6454bafcedda27034f.png

左高玩:“打断一下?我现在1万个内容,两两计算要循环1亿次,还可以接受,有一天10万了,要循环100亿次,算不过来了啊?”

利用稀疏性简化计算

83bbc214f28dc797647fa2c326bc4d4e.png

先说分母,你有

条内容,你计算每个内容的模,复杂度是

e5c8a6e6be2d5e17b02f4600072cd81b.png

对于分子你换一个角度,用户的行为量是有限的,即便有些用户会大量的点击,你可以截断到几百个,保留最近期的。然后,那个分子的意义是用户同时点击两篇内容的次数,直接在用户的点击集合里,两两构造,然后聚合计数。

73573d3fea09e4c386c77110c31a8f29.png

我们最终要存储成倒排索引的形式,截断余弦距离最大的k个,按照每个内容聚合,它和其他物品对应的余弦距离的分子和分母都分别算好了,除一下排序取top即可了。实际中,内容pair也是稀疏的,复杂度就降下来了。

abaea49ecc3340f0d26133f9986f3cf9.png

我讲的时候,左高玩快速地敲击着键盘,记得如此认真,我不禁成就感十足。他抬头一句:“我写完了,看这I2I结果还挺相似的。”

我:“我准备说开源工具呢。男人不能太快的。。。”

左高玩:”。。。“

打底召回

左高玩:”有一个问题,如果用户之前没有点过,那么不就什么都召回不出来了?“

这个时候,也就只能拿全局最热门的内容推荐给用户了,全局热门就是那些历史统计点击率最高的内容。

左高玩:”但是有一个问题,假如一个内容只曝光了一次,就被点击率,那点击率不就100%了。当内容曝光量少的时候,计算出来的点击率是没有意义的。怎么办?“

我:”可以做一个贝叶斯平滑。“

左高玩:”说人话。。。“

假设曝光数为PV,点击数为CLK,所谓的贝叶斯平滑,最终的形式就是在计算点击率的时候给分子和分母各加了一个值,形式为

。直观理解上它的作用是,当曝光量小的时候,结果更趋近于
,它是内容的平均点击率,当该内容的曝光量逐渐增多,它自身的点击率就突出了。

左高玩:”这么算有什么道理?“

我们假设点击率满足beta分布,

就是beta分布的参数。在观察这个内容的点击与否的数据之前,我们有其他内容的点击率经验,这个叫做先验信息,而该内容的点击率是一个未知参数,它满足一个分布,这个叫做先验分布。我们观察到该的内容的数据后,可以对先验分布进行修正,得到后验分布。在这里先验和后验分布都是beta分布(共轭),我们要求的就是后验分布,它的期望就是

左高玩:”当我没问。。。你直接说

咋算的吧“

使用矩估计,已知beta分布的期望

和方差
,又知道点击率的均值
和方差
,样本均值替代期望,样本方差替代总体方差。

工程实现

计算好I2I倒排索引,左高玩把数据塞到了他的MongoDB里。行为数据里也实时地写入了MongoDB。

每一个用户请求,先以用户id为key查询MongoDB对应的实时点击行为数据,然后在以点击过的内容id作为key查询MongoDB的I2I索引表,取回后将候选相似内容分数加起来(不同的行为会召回到相同的候选内容),按照分数从高到低排序,就生成了推荐列表。

如果这个推荐列表数量不足,就补充按照贝叶斯平滑点击率最大的热门内容。

后记

左高玩的推荐系统上线,点击率提升了一大波。但是他发现,那些新的内容更难出现了,有些时效性很高的内容,推出晚了,作用就不大了,创作者投诉变多了。没有什么是一顿饭解决不了的,如果有那左高玩就请我吃两顿。

《左高玩的推荐系统(二):content-base解决内容的冷启动问题》敬请期待

引用

贝叶斯平滑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值