我有兴趣听取您的意见,这是实施社交活动流的最佳方式(Facebook是最着名的例子).涉及的问题/挑战是:
不同类型的活动(发布,评论......)
不同类型的对象(帖子,评论,照片......)
1-n个用户参与不同的角色("用户x回复用户y对用户的Z帖子的评论")
相同活动项目的不同视图("您评论过"与"您的朋友x评论"对比"用户x评论..."=> 3个"评论"活动的表示)
..还有更多,特别是如果你把它带到高水平的复杂程度,例如,Facebook将几个活动项目合并为一个("用户x,y和z评论该照片")
关于实现这样的系统,数据模型等的最灵活,有效和最强大的方法的任何关于模式,论文等的想法或指示将是值得赞赏的.
虽然大多数问题都与平台无关,但我最终可能会在Ruby on Rails上实现这样的系统
我创建了这样的系统,我采用了这种方法:
数据库表包含以下列:id,userId,type,data,time.
userId是生成活动的用户
type是活动的类型(即写博客文章,添加照片,评论用户的照片)
data是一个序列化对象,其中包含活动的元数据,您可以将其放入任何您想要的内容中
这限制了搜索/查找,您可以在Feed,用户,时间和活动类型中进行操作,但在facebook类型的活动Feed中,这并不是真正的限制.并且通过表上的正确索引,查找速度很快.
使用此设计,您必须确定每种类型的事件应该需要哪些元数据.例如,新照片的Feed活动可能如下所示:
{id:1, userId:1, type:PHOTO, time:2008-10-15 12:00:00, data:{photoId:2089, photoName:A trip to the beach}}
你可以看到,虽然照片的名称肯定存储在包含照片的其他一些表中,我可以从那里检索名称,我会在元数据字段中复制名称,因为你不想这样做如果你想要速度,任何其他数据库表上的连接.而为了显示200个来自50个不同用户的不同事件,您需要速度.
然后我有扩展基本FeedActivity类的类,用于呈现不同类型的活动条目.事件的分组也将在渲染代码中构建,以避免数据库的复杂性.
这是一个非常好的演示文稿,概述了Etsy.com如何构建他们的活动流.这是我在这个主题上找到的最好的例子,虽然它不是特定于rails的.
http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture
我们开源了我们的方法:https: //github.com/tschellenbach/Stream-Framework 它是目前最大的开源库,旨在解决这个问题.
构建Stream Framework的同一团队还提供托管API,可以为您处理复杂性.看看getstream.io有Node,Python,Rails和PHP的客户端.
另外看看这个高可扩展性的帖子,我们解释了一些涉及的设计决策:http: //highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feeds.html
本教程将帮助您使用Redis设置Pinterest的Feed这样的系统.开始使用非常简单.
要了解有关Feed设计的更多信息,我强烈建议您阅读我们基于Feedly的一些文章:
雅虎研究论文
Twitter 2013 Redis基于后备
卡桑德拉在Instagram上
Etsy饲料比例
Facebook历史
Django项目,具有良好的命名约定.(但仅限数据库)
http://activitystrea.ms/specs/atom/1.0/(演员,动词,对象,目标)
Quora发布最佳实践
Quora扩展社交网络订阅源
Redis ruby的例子
FriendFeed方法
Thoonk设置
Twitter的方法
虽然Stream Framework是基于Python的,但从Ruby应用程序中使用它并不会太难.您可以将其作为服务运行,并在其前面粘贴一个小的http API.我们正在考虑添加API以从其他语言访问Feedly.目前你将不得不扮演自己的角色.
事件流的最大问题是可见性和性能; 您需要将显示的事件限制为该特定用户的有趣事件,并且您需要保留排序所需的时间并确定可管理的事件.我建立了一个小型的社交网络; 我发现在小规模的情况下,在数据库中保留"事件"表是有效的,但在适度负载下它会成为性能问题.
对于更大的消息和用户流,最好使用消息传递系统,其中事件作为消息发送到各个配置文件.这意味着您无法轻松订阅人员的事件流并轻松查看以前的事件,但是当您需要为特定用户呈现流时,您只需呈现一小组消息.
我相信这是Twitter的原始设计缺陷 - 我记得他们正在阅读他们正在访问数据库以引入和过滤他们的事件.这与建筑有关,与Rails无关,Rails(不幸的是)生成了"红宝石无法扩展"的模因.我最近看到一个演示文稿,其中开发人员使用亚马逊的简单队列服务作为他们的消息传递后端,用于具有更高扩展能力的类似Twitter的应用程序 - 如果您的负载足够高,可能值得将SQS作为系统的一部分进行查看.
如果您愿意使用单独的软件,我建议使用Graphity服务器来解决活动流的问题(建立在neo4j图形数据库之上).
这些算法已作为独立的REST服务器实现,因此您可以托管自己的服务器以提供活动流:http://www.rene-pickhardt.de/graphity-server-for-social-activity-streams-released-gplv3 /
在论文和基准测试中,我展示了检索新闻流只取决于您想要检索的项目数量,而不会从非规范化数据中获得任何冗余:
http://www.rene-pickhardt.de/graphity-an-efficient-graph-model-for-retrieving-the-top-k-news-feeds-for-users-in-social-networks/
在上面的链接中,您可以找到截屏视频和此方法的基准(显示图形能够每秒检索超过10k的流).
// one entry per actual event events { id, timestamp, type, data } // one entry per event, per feed containing that event events_feeds { event_id, feed_id }
创建事件后,确定它出现在哪些Feed中,并将其添加到events_feeds.要获取Feed,请从events_feeds中选择,加入事件,按时间戳排序.然后可以对该查询的结果进行过滤和聚合.使用此模型,您可以在创建后更改事件属性,而无需额外的工作.
昨天我开始实施这样的系统,这是我必须要做的......
我创建了一个StreamEvent类,其属性为Id,ActorId,TypeId,Date,ObjectId以及其他Details键/值对的哈希表.这在数据库中由StreamEvent表(Id,ActorId,TypeId,Date,ObjectId)和StreamEventDetails表(StreamEventId,DetailKey,DetailValue)表示.
所述的actorId,TYPEID和的ObjectId允许被捕获的主语-动词-对象事件(后来查询).每个操作都可能导致创建多个StreamEvent实例.
然后我为StreamEvent创建了一个子类,每种类型的事件,例如LoginEvent,PictureCommentEvent.这些子类中的每一个都具有更多特定于上下文的属性,例如PictureId,ThumbNail,CommenText等(事件需要的任何属性),它们实际上作为键/值对存储在hashtable/StreamEventDetail表中.
当从数据库中提取这些事件时,我使用工厂方法(基于TypeId)来创建正确的StreamEvent类.
StreamEvent的每个子类都有一个Render(context As StreamContext)方法,该方法根据传递的StreamContext类将事件输出到屏幕.StreamContext类允许根据视图的上下文设置选项.例如,如果以Facebook为例,您在主页上的新闻列表会列出每个操作中涉及的每个人的全名(以及指向其个人资料的链接),而查看朋友的Feed只会看到他们的名字(但是其他演员的全名) .
我还没有实现聚合源(Facebook主页),但我想我会创建一个AggregateFeed表,其中包含UserId,StreamEventId字段,这些字段是基于某种'嗯,您可能会发现这个有趣的'算法填充的.
任何评论都会受到大力赞赏.
如果你确定要在Rails中实现,也许你会发现以下插件很有用:
ActivityStreams:http://github.com/face/activity_streams/tree/master
如果没有别的,你将会看到一个实现,包括数据模型,以及为推拉活动提供的API.
我有一个类似于heyman的方法 - 一个非规范化表,包含将在给定活动流中显示的所有数据.它适用于活动有限的小网站.
如上所述,随着网站的增长,它可能会面临可扩展性问题.就个人而言,我现在并不担心缩放问题.我以后会担心的.
Facebook显然做得很好,所以我建议你阅读他们的工程博客,因为它有很多很棒的内容 - > http://www.facebook.com/notes.php?id=9445547199
我一直在研究比上面提到的非规范化表更好的解决方案.我发现实现此目的的另一种方法是将给定活动流中的所有内容压缩成单行.它可以存储为XML,JSON或某些可由应用程序读取的序列化格式.更新过程也很简单.在活动时,将新活动放入队列(可能使用Amazon SQS或其他内容),然后不断轮询队列以查找下一个项目.抓取该项目,对其进行解析,并将其内容放在存储在数据库中的相应Feed对象中.
这种方法的好处是,只需要在请求特定的feed时读取单个数据库表,而不是抓取一系列表.此外,它允许您维护有限的活动列表,因为您可以在更新列表时弹出最旧的活动项.
希望这可以帮助!:)
关于此类活动流有两个railscast:
http://railscasts.com/episodes/406-public-activity(带有gem public_activity的活动供稿)
http://railscasts.com/episodes/407-activity-feed-from-scratch(同样的事情从头开始)
这些解决方案不包括您的所有要求,但它应该给您一些想法.