让我从蝙蝠开始,说我知道这不是最好的解决方案.我知道这是一个kludgy和一个功能的黑客.但那就是我在这里的原因!
这个问题/工作建立了与 Facebook的新闻提要的创建者安德鲁博斯沃思讨论Quora.
我正在构建各种新闻源.它完全是在PHP
和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)
.
每当用户执行与新闻源相关的操作时,例如询问问题,它将立即记录到活动日志中.
然后每隔X分钟(此刻5分钟,将改为15-30分钟后),我运行一个执行下面脚本的cron作业.此脚本循环遍历数据库中的所有用户,查找该用户的所有朋友的所有活动,然后将这些活动写入新闻源.
目前SQL
,剔除活动(被称为ActivityLog::getUsersActivity()
)有一个LIMIT 100
强加性能*的原因.*不是我知道我在说什么.
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来生成推荐,但似乎对于像新闻源这样的东西,推荐者将无法工作(因为之前没有任何优势!).
真的很酷的问题.我实际上正在实现这样的事情.所以,我要大声思考一下.
以下是我在您的脑海中看到的当前实现的缺陷:
您正在处理所有的朋友为所有用户,但你最终会处理同一用户多次因事实的人是一样的群体有相似的朋友.
如果我的一个朋友发布了某些内容,它将不会在我的新闻Feed中显示最多5分钟.它应该立即出现,对吗?
我们正在为用户阅读整个新闻Feed.自从上次我们碾碎日志以来,我们是否只需要抓住新的活动?
这不能很好地扩展.
新闻源看起来与活动日志完全相同,我会坚持使用那个活动日志表.
如果您跨数据库对活动日志进行分片,则可以更轻松地进行扩展.如果您愿意,也可以对用户进行分片,但即使您在一个表中有1000万个用户记录,mysql应该可以正常进行读取.因此,无论何时查找用户,您都知道从哪个分片访问用户的日志.如果您经常存档旧日志并且只维护一组新的日志,则不必进行多少分片.或者甚至可能.如果您调整得非常好,您可以在MySQL中管理数百万条记录.
我会为你的users表利用memcached,甚至可能利用日志本身.Memcached的允许缓存条目高达1MB大小,如果你组织你的钥匙很聪明,你可能会检索所有最新的日志从缓存中.
就架构而言,这将是更多的工作,但它将允许您实时工作并在未来扩展...尤其是当您希望用户开始评论每个帖子时.;)
你看到这篇文章了吗?
http://bret.appspot.com/entry/how-friendfeed-uses-mysql