如何改善此PHP / MySQL新闻提要?


74

让我马上说,我知道这不是最佳解决方案。我知道这很糊涂并且是功能的骇客。但这就是为什么我在这里!

这个问题/工作建立在与Facebook新闻提要的创建者Andrew Bosworth在Quora上的一些讨论之上

我正在建立各种各样的新闻提要。它仅内置于PHP和中MySQL

替代文字


MySQL的

提要的关系模型由两个表组成。一个表用作活动日志。实际上,它的名称为activity_log。另一个表是newsfeed这些表几乎相同。

日志架构activity_log(uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)

...和进料模式newsfeed(uid INT(11), poster_uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)

每当用户执行与新闻提要相关的操作(例如询问问题)时,它将立即记录到活动日志中


生成新闻提要

然后每隔X分钟(此刻为5分钟,之后将更改为15-30分钟),我运行了一个cron作业,该作业执行以下脚本。该脚本循环遍历数据库中的所有用户,查找该用户所有朋友的所有活动,然后将这些活动写入新闻提要。

目前,出于性能*的原因SQL,对活动进行剔除(称为中ActivityLog::getUsersActivity())已被LIMIT 100强加。*不是我知道我在说什么。

<?php

$user = new User();
$activityLog = new ActivityLog();
$friend = new Friend();
$newsFeed = new NewsFeed();

// Get all the users
$usersArray = $user->getAllUsers();
foreach($usersArray as $userArray) {

  $uid = $userArray['uid'];

  // Get the user's friends
  $friendsJSON = $friend->getFriends($uid);
  $friendsArray = json_decode($friendsJSON, true);

  // Get the activity of each friend
  foreach($friendsArray as $friendArray) {
    $array = $activityLog->getUsersActivity($friendArray['fid2']);

    // Only write if the user has activity
    if(!empty($array)) {

      // Add each piece of activity to the news feed
      foreach($array as $news) {
        $newsFeed->addNews($uid, $friendArray['fid2'], $news['activity'], $news['activity_id'], $news['title'], $news['time']);
      }
    }
  }
}

显示新闻提要

在客户端代码中,获取用户的新闻提要时,我会执行以下操作:

$feedArray = $newsFeed->getUsersFeedWithLimitAndOffset($uid, 25, 0);

foreach($feedArray as $feedItem) {

// Use a switch to determine the activity type here, and display based on type
// e.g. User Name asked A Question
// where "A Question" == $feedItem['title'];

}

改善新闻提要

现在,请原谅我对开发新闻提要的最佳实践的有限理解,但是我知道我所使用的方法是所谓的书面扇出的有限版本,在我执行cron工作的意义上是有限的作为中间步骤,而不是直接写入用户的新闻提要。但是,这与拉动模型有很大不同,在某种意义上说,用户的新闻提要不是按负载编译,而是按常规编译。

这是一个很大的问题,可能值得进行大量的来回讨论,但是我认为它可以作为许多新的对话的试金石,像我这样的新开发人员需要进行这些对话。我只是想弄清楚自己在做错什么,如何改进,或者甚至应该从头开始尝试另一种方法。

使我感到困扰的另一件事是,该模型基于新近性而不是相关性工作。如果有人可以提出如何改进它以使其与工作相关的建议,我将不胜感激。我正在使用Directed Edge的API来生成推荐,但似乎对于新闻提要之类的推荐器将不起作用(因为以前没有喜欢任何东西!)。


什么?这次没有幽默的影像吗?您可以做得更好!:P
alex


1
@Josh Smith每个用户都有新闻源表吗?
chromedude 2011年

1
@josh smith如果您重建上述算法,请发布它。谢谢
namal 2015年

1
@JoshSmith,您是否为每个朋友执行一个SQL查询以获取他们的活动?
约翰·史密斯

Answers:


15

真的很酷的问题。我实际上正在自己实施这样的事情。所以,我要大声考虑一下。

这是我目前使用的实现方法在我脑海中看到的缺陷:

  1. 您正在为所有用户处理所有朋友,但是由于同一组人具有相似的朋友,您最终将多次处理同一用户。

  2. 如果我的一个朋友发布了某项内容,则该消息最多不会出现在我的新闻提要中5分钟。它应该立即显示出来,对吧?

  3. 我们正在为用户阅读整个新闻提要。自上次处理日志以来,我们是否仅需要进行新活动?

  4. 这不能很好地扩展。

新闻提要看起来和活动日志完全一样,我会坚持使用那个活动日志表。

如果您在数据库之间共享活动日志,则可以轻松扩展。您也可以根据需要对用户进行分片,但是即使在一个表中有1000万条用户记录,mysql也可以很好地进行读取。因此,无论何时查找用户,都知道从哪个碎片访问用户的日志。如果您经常存档较旧的日志,而只维护一组新的日志,则无需分片那么多。甚至根本没有。如果调整得当,就可以在MySQL中管理数百万条记录。

我会为您的用户表甚至日志本身利用memcached。Memcached允许高速缓存条目的大小最大为1mb,如果您很聪明地组织密钥,则有可能从高速缓存中检索所有最新日志。

就架构而言,这将是更多工作,但它将允许您实时工作并在将来扩展……尤其是当您希望用户开始对每个发布发表评论时。;)

您看到这篇文章了吗?

http://bret.appspot.com/entry/how-friendfeed-uses-mysql


1

之间可以使用用户标志和缓存。假设有一个新的用户字段last_activity。每当用户输入任何活动时,都要更新此字段。保留一个标志,直到您提取提要什么时间为止,将其称为feed_updated_on。

现在更新函数$ user-> getAllUsers(); 仅返回last_activity时间晚于feed_updated_on的用户。这将排除所有没有任何活动日志的用户:)。对于用户朋友类似的过程。

您也可以使用缓存,例如内存缓存或文件级缓存。

或者使用一些nosql DB将所有提要存储为一个文档。


1

我正在尝试自己建立一个Facebook风格的新闻提要。我没有创建另一个表来记录用户的活动,而是从帖子,评论等的UNION中计算了“ edge”。

通过一些数学运算,我使用指数衰减模型来计算“边”,其中经过时间是自变量,同时考虑了每个帖子必须公式化lambda常数的评论,喜欢的次数等。边缘起初会快速减小,但几天后逐渐变平为几乎为0(但永远不会达到0)

显示提要时,每个边都会使用RAND()相乘。具有较高优势的帖子会更频繁地出现

这样,更多受欢迎的帖子在较长时间中更有可能出现在新闻提要中。


4
您没有提到Edge是预先计算的还是运行时计算的?
meson10

1

而不是执行cron作业,而是某种形式的提交后脚本。我不特别了解PHP和MySQL在这方面的功能-如果我没记错的话,MySQL InnoDB比其他版本提供了更多的高级功能,但是我不记得最新版本中是否有触发器之类的东西。

无论如何,这是一个不依赖很多数据库魔术的简单变体:

用户X添加内容时:

1)在数据库提交后从您的PHP页面进行异步调用(当然是异步的,以便查看该页面的用户不必等待它!)

该调用将启动您的逻辑脚本的实例。

2)逻辑脚本只能执行遍历提交新内容的用户的朋友列表[A,B,C](而不是数据库中所有人的列表!),并将用户X的操作附加到每个提要的提要中这些用户中。

您可以将这些提要存储为简单的JSON文件,并将新数据附加到每个末尾。当然,最好通过将备份保存到文件系统或BerkeleyDB或Mongo或任何您喜欢的内容来将提要保留在缓存中。

这只是基于新近度而非相关性的Feed的基本思想。您可以以这种方式顺序存储数据,然后在每个用户的基础上进行其他解析以按相关性进行过滤,但这在任何应用程序中都是一个难题,并且可能不是匿名Web用户可以轻松解决的一个问题,而无需详细说明了解您的要求;)

sh


0

您会添加统计关键字吗?我通过分解文档正文,剥离HTML,删除常用单词并计算最常用单词来实现(粗略的)实现。几年前,我只是出于娱乐目的而创建了它(就像其他任何项目一样,源代码都消失了),但是它可以用于我的临时测试博客/论坛设置。也许它将对您的新闻源有用...


3D实际上,使用FULLTEXTSphinx这样的搜索引擎可以更轻松地实现此功能,这是另一种可能的方法。我对这样的事情或@stillstanding建议的方法感到担心的是,感觉就像是在hack之上的hack。我真正想确定相关性的是计算用户与内容创建者的总和亲和力得分,内容类型的权重和时间衰减因子。但还不太确定该怎么做...
Josh Smith,2010年

您会让这种情况发展到什么程度的复杂性?这似乎是一个很大的重量分布,但这是可行的。您可能需要对与年龄的相关性添加一些对数衰减,但是获取“内容类型”非常模糊。您必须设置一个关键字数组来进行匹配以确定该关键字(作为一种快速解决方案。这在大型应用程序中并不理想)。这需要大量的统计数据和计算机阅读能力...
Blender

这可能会相当复杂。想想Facebook的新闻提要。但是,这可能需要超出我在这里所进行的范围内的重新思考。
乔什·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.