我怎样才能改进这个PHP / MySQL新闻提要?

让我立即开始说,我知道这不是最好的解决scheme。 我知道这是一个function和黑客的function。 但这就是我来这里的原因!

这个问题/工作与 Facebook的新闻提供者的创build者Andrew Bosworthbuild立了一些关于Quora的讨论 。

我正在build立一个新闻饲料的种类。 它完全由PHPMySQL构build。

替代文字


MySQL

Feed的关系模型由两个表组成。 一个表格用作活动日志; 实际上,它被命名为activity_log 。 另一个表是newsfeed这些表格几乎完全相同。

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

…以及feed架构newsfeed(uid INT(11), poster_uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)

任何时候用户做一些与新闻提要有关的事情 ,例如问一个问题, 都会立即logging到活动日志中


生成新闻提要

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

目前,剔除Activity(在ActivityLog::getUsersActivity()调用)的SQL有一个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 // eg User Name asked A Question // where "A Question" == $feedItem['title']; } 

改进新闻提要

现在原谅我对开发新闻馈送的最佳实践的理解有限,但是我理解我使用的方法是限制版本的所谓扇形写 ,限于我正在运行cron作业作为一个中间步骤,而不是直接写给用户的新闻馈送。 但这与拉式模型有很大不同,因为用户的新闻馈送不是在加载时编译的,而是定期编译的。

这是一个很大的问题,可能需要大量的来回,但我认为它可以作为像我这样的新开发人员需要具备的许多重要对话的试金石。 我只是想弄清楚我做错了什么,我怎么可以改进,或者我应该甚至从头开始,尝试一种不同的方法。

另外一个让我误解这个模型的东西是,它是基于新近而不是相关的。 如果任何人都可以build议如何改进工作相关性,我会大家耳熟能详。 我正在使用Directed Edge的API来生成推荐,但是对于像新闻提要这样的内容,推荐人似乎无法正常工作(因为以前没有人喜欢过)。

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

以下是我目前在实施中遇到的缺陷:

  1. 您正在处理所有用户的所有朋友,但由于同一组人拥有相似的朋友,因此您最终会多次处理同一用户。

  2. 如果我的一个朋友发布了一些内容,它将不会在我的新闻Feed中显示最多5分钟。 而它应该立即显示,对吗?

  3. 我们正在阅读用户的整个新闻提要。 自从我们上次logging日志以来,我们不需要抓住新的活动吗?

  4. 这不能很好地扩展。

新闻推送看起来像活动日志完全相同的数据,我会坚持使用一个活动日志表。

如果您在数据库中分割您的活动日志,它将允许您轻松扩展。 如果你愿意的话,你也可以分割你的用户,但是即使你在一个表中有1000万个用户logging,mysql也应该可以读取。 所以每当你查找一个用户,你就知道从哪个分片访问用户的日志。 如果您经常存档较旧的日志,并且只保留一组新的日志,则不必分割太多。 或者甚至可能。 如果您调整得相当好,您可以在MySQL中pipe理数百万条logging。

我会利用memcached为您的用户表,甚至可能是日志本身。 Memcached允许caching条目大小为1MB,如果您在组织密钥方面很聪明,则可以从caching中检索所有最新的日志。

就build筑而言,这将是更多的工作,但是它可以让你在未来实时工作和扩大规模,特别是当你希望用户开始评论每一篇文章的时候。 ;)

你看到这篇文章了吗?

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

你会添加统计关键字? 我通过爆炸文档的主体,剥离HTML,删除常用词汇,并计算最常见的词语来做出粗略的实现。 几年前,我为了好玩(就像任何这样的项目一样,源代码已经不存在了),但是它在我的临时testing博客/论坛设置中起作用。 也许它会适用于你的新闻提要…

你可以使用用户标志和caching。 比方说,有一个新的领域为用户last_activity。 每当用户input任何活动时更新此字段。 保持一个标志,直到你什么时候提取饲料让我们说它feed_updated_on。

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

您也可以使用caching,如memcache或文件级caching。

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

我正尝试自行构build一个Facebook风格的新闻提要。 我没有创build另一个表来logging用户的活动,而是计算了post,评论等联盟的“边缘”。

用一点math,我使用指数衰减模型来计算“边缘”,时间是自variables,考虑到注释,喜欢等数量,每个post都必须制定拉姆达常数。 边缘起初会下降,但在几天之后会逐渐变平,几乎为零(但是永远不会达到0)

显示进给时,每条边都使用RAND()相乘。 边缘较高的post会更频繁地出现

这样,更多的热门post出现在新闻馈送中的可能性就会更高。

不是运行cron作业,而是运行某种types的post-commit脚本。 我不明白PHP和MySQL在这方面的function是什么 – 如果我正确地记得MySQL的InnoDB允许更多的高级function比其他品种,但我不记得是否有像最新版本的触发器的东西。

无论如何,简单的变化就是不依赖于很多数据库的魔术:

当用户X添加内容时:

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

调用启动您的逻辑脚本的一个实例。

2)逻辑脚本通过提交新内容的用户的好友[A,B,C]列表(而不是DB中的每个人的列表!),并将用户X的动作追加到每个的这些用户。

您可以将这些提要存储为直接的JSON文件,并将新数据添加到每个提要的末尾。 当然,更好的方式是保持饲料caching与备份到文件系统或BerkeleyDB或Mongo或任何你喜欢的。

这只是根据新近程度而不是相关性的基本概念。 您可以以这种方式按顺序存储数据,然后在每个用户的基础上进行额外parsing,以便按相关性进行过滤,但这在任何应用程序中都是一个难题,并且可能不是一个匿名Web用户可以轻松解决的问题了解你的要求;)

JSH

Interesting Posts