【问题标题】:Collaborative Filtering / Recommendation System performance and approaches协同过滤/推荐系统性能和方法
【发布时间】:2012-02-11 08:55:11
【问题描述】:

我真的很想知道人们是如何处理协同过滤和推荐引擎等的。我的意思是脚本的性能比什么都重要。我已经说过阅读编程集体智能,这真的很有趣,但往往更多地关注事物的算法方面。

我目前只有 2000 个用户,但事实证明,我目前的系统完全不能满足未来的需求,并且已经对服务器造成了很大的负担。整个系统基于向用户推荐帖子。我的应用程序是 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 为 key,相似度得分为 value。如果是 0,我不保存分数。

我有 5k 个帖子。因此,以上所有内容在服务器上都相当困难。有大量的读取和写入需要执行。现在,这只是问题的一半。然后,我使用这些信息来确定特定用户会感兴趣的帖子。因此,我每小时运行一次 cron 脚本,该脚本运行一个脚本,为网站上的每个用户计算 1 个推荐帖子。流程是这样的:

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

不幸的是,每小时的推荐脚本会占用大量资源,而且完成的时间越来越长……目前需要 10 到 15 分钟。我担心在某些时候我将无法再提供每小时建议。

我只是想知道是否有人觉得我可以更好地解决这个问题?

【问题讨论】:

  • 这是一个相当复杂的问题,可能超出了 SO 提供的 Q&A 范围。无论如何,我不确定直接的职位关系是否完全可行。帖子相似总是有原因的(在您的情况下,例如共享标签)。例如,加权 tag->post(W) 集合将允许您在给定特定输入帖子的情况下快速找到最相关的相似帖子。这也映射了 A 与 B 相似的情况,B 与 C 相似,因此 A 很可能与 C 相似。在标签库聚合 A 中,B 和 C 都将通过共享标签相关联。跨度>

标签: php mysql mongodb filtering collaborative


【解决方案1】:

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

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

然后以某种有意义的顺序构建喜欢的索引并计算反转(分而治之 - 这与合并排序非常相似,无论如何您都希望在输出时进行排序以计算拆分反转)。

我希望这会有所帮助 - 您不想将所有内容与其他所有内容进行比较,否则肯定是 n2。如果您选择一组具有相似喜好的人并使用它,您应该能够将其替换为介于常数和线性之间的某种东西。

例如,从图的角度来看,获取他们最近喜欢的东西,查看边缘,然后追踪它们并分析这些用户。也许对一些最近喜欢的文章执行此操作,然后从中找到一组共同的用户,并将其用于协同过滤以查找用户可能会喜欢的文章。那么你的问题规模是可行的——尤其是在没有索引增长的图中(尽管可能在文章中遍历更多的边——但这只会让你在寻找可用数据方面做出更多改变)

更好的办法是自己键入文章,这样如果某篇文章被某人点赞,您可以根据其他用户查看他们可能喜欢的文章(即亚马逊的“购买此商品的用户也购买了”)。

希望能提供一些想法。对于图形分析,有一些框架可能有助于统计和推导,例如 faunus。

【讨论】:

    【解决方案2】:

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

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

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

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

    如果我正在编写一个平台来测量与数据的关系,那么(线索就在名称中)我肯定会倾向于关系数据库,其中连接很容易,并且大部分逻辑都可以在数据库层上实现.

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

    【讨论】:

    • 你的第一个假设是真的吗?并非所有帖子都与所有帖子相关/相似,因此帖子和关系之间的关系不是(必然)O(n ^ 2),而是更接近O(n)假设每个帖子平均具有相同数量的关系其他。请记住,您将删除许多帖子共享的相似之处,因为这些相似之处不会为他们的帖子提供足够的差异化。我完全同意消息队列与定时批处理。
    猜你喜欢
    • 2010-12-03
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2012-07-15
    相关资源
    最近更新 更多