协作过滤/推荐系统的性能和方法

时间:2012-01-16 11:53:36

标签: php mysql mongodb filtering collaborative

我真的很想知道人们如何处理协作过滤和推荐引擎等等。我的意思是更多的是脚本的性能而不是任何东西。我已经说过阅读编程集体智能,这非常有趣,但往往更多地关注事物的算法方面。

我目前只有2k用户,但我现在的系统证明完全不是未来的证据,而且已经非常对服务器负担。整个系统基于向用户提供帖子的建议。我的应用程序是PHP / MySQL,但我使用一些MongoDB进行协作过滤 - 我在大型Amazon EC2实例上。我的设置实际上是一个两步过程。首先,我计算项目之间的相似性,然后我使用此信息来提出建议。以下是它的工作原理:

首先我的系统计算用户帖子之间的相似性。该脚本运行一个算法,该算法返回每对的相似度分数。该算法检查诸如 - 普通标签,普通评论者和普通评论者之类的信息,并且能够返回相似性分数。过程如下:

  • 每次添加帖子时,都会添加标签,评论或喜欢我将其添加到队列中。
  • 我通过cron处理此队列(每天一次),找出每个帖子的相关信息,例如:评论者和喜欢者的user_id和tag_id的。我以这种结构将此信息保存到MongoDB:{“post_id”:1,“tag_ids”:[12,44,67],“commenter_user_ids”:[6,18,22],“liker_user_ids”:[87, 6]}。这使我最终可以构建一个MongoDB集合,这使我可以轻松快速地访问所有相关信息,以便我在尝试计算相似之处时
  • 然后我再次运行另一个cron脚本(每天一次,但是在前一次之后)。这一次,对于队列中的每个帖子,我从MongoDB集合中获取它们的条目并将其与所有其他条目进行比较。当2个条目具有一些匹配信息时,我在相似性方面给它+1。最后,我对每对帖子都有一个总分。我将分数保存到具有以下结构的不同MongoDB集合中:{“post_id”:1,“similar”:{“23”:2,“2”:5,“7”:2}}('similar'是一个key => value数组,其中post_id为关键字,相似度得分为值。如果为0,我不保存得分。

我有5k的帖子。所以上述所有内容在服务器上都很难。要执行大量的读写操作。现在,这只是问题的一半。然后,我使用此信息来确定哪些帖子对特定用户有用。因此,每小时我运行一个cron脚本,该脚本运行一个脚本,为网站上的每个用户计算1个推荐帖子。过程如下:

  • 脚本首先决定用户将获得哪种推荐。这是一个50-50的变化 - 1.一个帖子类似于你的一个帖子或2.一个类似于你与之互动的帖子的帖子。
  • 如果为1,则脚本从MySQL获取用户post_ids,然后使用它们从MongoDB中获取类似的帖子。该脚本采用最相似且尚未向用户推荐的帖子。
  • 如果为2,脚本会抓取用户在MySQL上评论或喜欢的所有帖子,并使用其ID在上面的1中执行相同的操作。

不幸的是,每小时推荐脚本变得非常耗费资源,并且需要更长时间才能完成...目前10-15分钟。我担心在某些时候我将无法提供每小时推荐。

我只是想知道是否有人觉得我可以更好地接近这个?

2 个答案:

答案 0 :(得分:2)

拥有5000个帖子,即25,000,000个关系,增加了O(n ^ 2)。

您的第一个问题是如何在每次批处理运行时避免检查这么多关系。使用标签或关键字有助于内容匹配 - 您可以使用日期范围来限制常见的喜欢'。除此之外......我们更多地了解很多关于建立关系的方法。

另一个考虑因素是何时建立关系。为什么要等到批处理运行以将新帖子与现有数据进行比较?当然,异步处理这个是有意义的,以确保快速处理请求 - 但(除了您的平台施加的限制)为什么要等到批处理开始建立关系之前?使用异步消息队列。

实际上,根据处理消息所需的时间长短,甚至可能存在在检索项目时而不是在创建项目时重新生成缓存关系数据的情况。

如果我正在编写一个平台来衡量与数据的关系,那么(线索就在名称中)我绝对倾向于一个关系数据库,其中连接很容易,而且很多逻辑都可以在数据库层。

当然可以减少系统交叉引用数据所需的时间。这正是map-reduce旨在解决的问题 - 但这样做的好处主要来自于在许多机器上并行运行算法 - 在一天结束时它需要尽可能多的时钟滴答。 / p>

答案 1 :(得分:1)

我开始计划如何做到这一点。 首先,可能是摆脱您的数据库技术或使用三重存储或图形技术对其进行补充。这应该为分析类似的喜欢或主题提供更好的表现。

接下来是获得一个子集。获取用户拥有的一些兴趣,并获得一小部分具有相似兴趣的用户。

然后以某种有意义的顺序构建喜欢的索引并计算反转(划分和征服 - 这非常类似于合并排序,并且你想要在出路上排序以计算拆分反转)。

我希望有所帮助 - 你不想把所有东西都比作其他东西,或者它肯定是n2。你应该能够用常数和线性之间的东西来代替它,如果你采取了一些有类似喜欢和使用它的人。

例如,从图表的角度来看,采取他们最近喜欢的东西,然后查看边缘,然后追踪它们,然后分析这些用户。也许在一些最近喜欢的文章上做这个,然后从中找到一组共同的用户,并使用它进行协作过滤,以找到用户可能喜欢的文章。然后你处于一个可行的问题规模 - 特别是在没有索引增长的图形中(尽管可能更多的是在文章中进行遍历 - 这只会给你更多的查找可用数据的更改)

更好的方法是自己键入文章,这样如果某篇文章被某人喜欢,你可以根据其他用户看到他们喜欢的文章(即亚马逊的'购买此商品的用户也购买')。

希望能给出一些想法。对于图形分析,有一些框架可能有助于像统计和派生的faunus。