3

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

我目前只有 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为key,以相似度得分为value。如果是0,我不保存分数。

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

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

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

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

4

2 回答 2

2

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

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

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

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

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

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

于 2012-01-16T13:53:46.540 回答
1

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

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

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

我希望这会有所帮助-您不想将所有内容与其他所有内容进行比较,或者肯定是 n2。如果你让一群有相似喜好的人使用它,你应该能够用介于常数和线性之间的东西来代替它。

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

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

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

于 2013-02-04T18:10:54.033 回答