[Paper阅读] TencentRec: 实时流推荐实践(一)

动机

  • 传统推荐系统(定期分析数据和更新模型)无法满足现代网络应用的需求
  • 本文主要解决实时推荐中的“大型”/“实时”/“精准”等挑战,从三个方面(“系统”/“算法”/“数据”)提出了一个通用的实时流推荐系统
  • 实现了几个经典/使用的推荐算法,包括:基于物品的协同过滤/基于内容的算法以及基于人口统计的算法
  • 详细介绍了实用/可扩展的基于物品的协同过滤及其非常特别的特性:例如对隐式反馈问题/渐增更新/实时剪枝等方面的健壮性

解决方案

  • “大型”——“系统”,利用storm来支持实时计算,利用它的计算能力来分析大量数据流;为了解决大量的数据存储和状态数据存储,开发了两个组件,分别被称为:TDAccessTDStore
  • “算法”——为了适用于不同的应用需求,基于storm实现了一系列经典的推荐算法,包括:基于物品的协同过滤/基于人口统计的算法以及基于内容的算法
  • “数据”——通过实时收集和处理数据,能够实时获取用户的喜好和兴趣变化

架构概述

平台选择

  • Storm 支持实时数据流计算
  • Storm拥有较好的扩展性,可以动态增加或删除集群中的节点
  • Storm拥有一定的容错性,可以快速进行灾难恢复
  • Storm拥有其它的优势,例如简单的编程模型,支持一系列编程语言

数据读取

开发了一个TDAccess提供大量数据集合和分布的同意接口,将数据源和数据处理系统解耦。TDAccess从不同的应用手机数据,然后数据处理系统可以实时从TDAccess消费数据。
考虑因素
– 数据服务器不需要共享数据,它们的主机服务器管理状态;因此非常容易进行大数据集合和分布式集群的线性扩展
– 数据服务器很重要的一个角色是生产者和消费者之间的消息队列,但是与传统的消息队列不同,它并不存储消息数据。为了实现绝对的可用性,TDAccess将数据缓存在磁盘中,以避免实时计算系统的短暂不可用,或者要求历史数据的离线计算。这毫无疑问将增加实时数据读写的难度。我们最大范围内利用序列操作来加速读写的速度
– 为了实现更好的并发,我们将一个应用中的数据分布到数据服务器集群的多个分区;当生产者或消费者集群希望生产或消费数据时,它首先与主机服务器进行通信。主机服务器将会对数据服务器进行均衡。

状态数据存储

方案1:和程序一样在worker的内存中存储状态数据
– 限制了程序的设计,一下额状态数据被多个worker使用或更新,因此需要在程序中管理状态数据的分发和转化
– 需要维护程序中的数据一致性
– 降低了系统的鲁棒性

算法设计

目标
– 实时
– 精确
– 大型

基础的基于物品的协同过滤

主要包含两个部分:
– 相似度计算:通过计算每个物品对之间的相似分数来构建一个相似物品表(余弦相似度):$$sim(i_p, i_q)=\frac{\vec{i_p} \cdot \vec{i_q}}{||\vec{i_p}|| \cdot ||\vec{i_q}||}=\frac{\sum_{u\in U} {r_{u,p}} r_{u,q}}{\sqrt{\sum {r^2_{u,p}}}\sqrt{\sum {r^2_{u,q}}}}$$
– 预测计算:通过计算给定用户邻居用户的加权评分来计算:$$\hat{r}_{u,v}=\frac{\sum_{i_q\in{N^k(i_p)}}sim(i_p,i_q)r_{u,i_q}}{\sum_{i_q\in{N^k(i_p)}}sim(i_p,i_q)}$$
其中,$$N^k(i_p)$$表示邻居用户的集合,与$$i_p$$最相近的前$$k$$个物品。

隐式反馈问题解决方案

  • 对不同的操作类型赋予不同的权重,用户对于同一个物品有不同类型的操作,取权重最大的那个,减少不同的隐式反馈带来的噪音。
  • 某个用户给物品i_pi_q的共同评分定义为:用户-物品频分的较小权重:$$co-rating(i_p,i_q)=min(r_{u,p}, r_{u,q})$$,其中$$r_{u,p}$$为用户$$u$$对物品$$i_p$$的最大行为权重。
  • 为了保证相似度分数介于[0,1]之间,我们使用下面的公式进行计算:$$sim(i_p, i_q)=\frac{\sum_{u\in U} min({r_{u,p}} r_{u,q})}{\sqrt{\sum {r_{u,p}}}\sqrt{\sum {r_{u,p}}}}$$,其中$$||\vec{i_p}||$$被设置为$$\sqrt{\sum {r_{u,p}}}$$而不使用标准的L2范数。

可扩展的增量更新

除了隐式反馈问题,由于用户评分的变化,实时的基于物品的协同过滤算法也面临着相似物品表的频繁更新问题。在传统的推荐系统中,一般会采用定期更新策略。然而,定期更新无法满足实时推荐的需求,它是一个会快速变化的场景。为了获取用户的实时兴趣,在我们的基于物品的协同过滤算法中更倾向于选择增量更新的策略。
考虑到增量更新的机制,将物品对之间的相似性分数分为三个部分,如下所示:
$$sim(i_p,i_q)=\frac{pairCount(i_p,i_q)}{\sqrt{itemCount(i_p)}\sqrt{itemCount(i_q)}}$$
其中,$$itemCount(i_p)=\sum{r_{u,p}}$$,$$pairCount(i_p,i_q)=\sum_{u\in U}co-rating(i_p,i_q)$$。在这种情况下,物品对的相似度分数可以通过计算$$pairCount(i_p,i_q)$$,$$itemCount(i_p)$$和$$itemCount(i_q)$$增量的值得到,然后将这些值组合为新的相似性分数。因此,相似性分数可以使用如下的公式进行增量更新:
$$sim(i_p,i_q)’=\frac{pairCount(i_p,i_q)’}{\sqrt{itemCount(i_p)’}\sqrt{itemCount(i_q)’}}=\frac{pairCount(i_p,i_q)+\delta co-rating(i_p, i_q)}{\sqrt{itemCount(i_p)+\delta r_{u_p}}\sqrt{itemCount(i_q) + \delta r_{u_q}}}$$
其中,$$sim(i_p,i_q)’$$表示在新的(用户,物品,评分)接收到之后得到的新的相似性分数。在这里,为了方便计算,设计了一个三层的并行结构:
– 第一层是(用户,物品,评分)对
– 根据用户ID进行组合之后会进入到下一阶段,输入到不同的用户历史中
– 然后分别更新$$itemCount$$ 和$$pairCount$$,得到最终的相似性分数

实时剪枝

大量的数据在实时的基于物品的协同过滤算法中带来了严峻的挑战。在基于物品的协同过滤中,如果用户倾向于对它们一起评分的话,则这两个物品通常会被认为是相似的。
为了解决这个问题,利用Hoeffding界限理论开发了一个实时的剪枝计数。

本周有点忙,基本上主要看了这些比较基础的东西,感觉实时剪枝这一部分的原理还是挺有意思的,需要再花些时间了解下。下周的博客会继续把这篇paper的内容补齐。

打赏

mickey

记录生活,写给几十年后的自己。