实施社交活动stream的最佳方式是什么?

我有兴趣听取您的意见,其中是实施社交活动stream的最佳方式(Facebook是最有名的例子)。 涉及的问题/挑战是:

  • 不同types的活动(发布,评论..)
  • 不同types的对象(发布,评论,照片..)
  • 参与不同angular色的1-n个用户(“用户x回复用户对用户的Zpost的评论”)
  • 同一活动项目的不同观点(“您评论”与“您的朋友x评论”与“用户x评论”=> 3“评论”活动的表述)

…还有一些,特别是如果你把它带到一个高水平的复杂性,如Facebook所做的,例如,将几个活动项目合并为一个(“用户x,y和z评论该照片”

对于实现这样的系统,数据模型等的最灵活,高效和强大的方法,任何关于模式,论文等的想法或指示将不胜感激。

尽pipe大部分问题都是与平台无关的,但我最终有可能在Ruby on Rails上实现这样一个系统

我已经创build了这样的系统,我采取了这种方法:

包含以下列的数据库表:id,userId,types,数据,时间。

  • userId是生成活动的用户
  • types是活动的types(即写博客文章,添加照片,评论用户的照片)
  • 数据是一个序列化的对象与元数据的活动,你可以放在任何你想要的

这限制了search/查找,您可以在提要,用户,时间和活动types中执行操作,但是在Facebooktypes的活动提要中,这并不是真正的限制。 而且在表格中有正确的索引时,查找速度很快

有了这个devise,你将不得不决定每种types的事件应该需要什么元数据。 例如,新照片的供稿活动可能如下所示:

{id:1, userId:1, type:PHOTO, time:2008-10-15 12:00:00, data:{photoId:2089, photoName:A trip to the beach}} 

你可以看到,虽然照片的名字肯定是存储在其他一些包含照片的表格中的,但是我可以从那里检索这个名字,我将在元数据字段中复制这个名字,因为你不想这样做如果你想加快速度,可以join其他数据库表格。 为了显示来自50个不同用户的200个不同的事件,你需要速度。

然后我有扩展一个基本的FeedActivity类的类来呈现不同types的活动条目。 事件分组也将在渲染代码中build立,以避免数据库的复杂性。

这是一个很好的演示,概述了Etsy.com如何构build他们的活动stream。 这是我在这个主题上find的最好的例子,虽然它不是专门的。

http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture

我们已经开放了我们的方法: https : //github.com/tschellenbach/Stream-Framework它是目前最大的开源库,旨在解决这个问题。

构buildStream Framework的同一团队还提供了一个托pipeAPI,可以为您处理复杂的问题。 看看getstream.io有Node,Python,Rails和PHP的客户端。

另外看看这个高扩展性后,我们解释一些涉及的devise决策: http : //highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feeds.html

本教程将帮助您使用Redis设置像Pinterest Feed一样的系统。 开始很容易。

要了解有关Feeddevise的更多信息,我强烈推荐阅读一些我们基于Feedly的文章:

  • 雅虎研究报告
  • Twitter 2013 Redis的基础 ,与后备
  • 卡桑德拉在Instagram
  • Etsy饲料缩放
  • Facebook的历史
  • Django项目 ,具有良好的命名约定。 (但只有数据库)
  • http://activitystrea.ms/specs/atom/1.0/(actor,verb,object,target
  • Quora发布最佳实践
  • Quora缩放社交networkingFeed
  • Redisruby的例子
  • FriendFeed方法
  • Thoonk设置
  • Twitter的方法

虽然Stream Framework是基于Python的,但是从Ruby应用程序使用它并不难。 您可以简单地将其作为服务运行,并在其前面粘贴一个小的http API。 我们正在考虑添加API以从其他语言访问Feedly。 目前你必须自己扮演angular色。

事件stream最大的问题是可见性和性能; 您需要限制显示的事件只是该特定用户感兴趣的事件,并且您需要保留sorting所需的时间,并确定可pipe理的事件。 我build立了一个小小的社交networking。 我发现,在小规模的情况下,在数据库中保留一个“事件”表是可行的,但是在中等负载下它会成为一个性能问题。

随着消息和用户数量的增加,最好使用消息传递系统,将事件作为消息发送到各个configuration文件。 这意味着您不能轻易订阅人员的事件stream并轻松查看以前的事件,但是当您需要为特定用户呈现stream时,您只需呈现一小组消息。

我相信这是Twitter的原始devise缺陷 – 我记得他们正在触摸数据库来插入和过滤他们的事件。 这一切都与build筑有关,与Rails毫无关系,Rails不幸生成了“ruby不能缩放”的模因。 我最近看到一个演示,开发人员使用Amazon的简单队列服务作为他们的消息传递后端,用于类似twitter的应用程序,这个应用程序具有更高的扩展能力 – 如果您的负载足够高,可能需要将SQS作为系统的一部分。

如果您愿意使用单独的软件,我build议Graphity服务器完全解决活动stream的问题(build立在neo4jgraphics数据库上)。

这些algorithm已经作为独立的REST服务器实现,因此您可以托pipe自己的服务器来提供活动stream: http : //www.rene-pickhardt.de/graphity-server-for-social-activity-streams-released-gplv3 /

在论文和基准testing中,我发现检索新闻stream只取决于您希望检索的项目的数量,而不需要通过反规格化数据获得任何冗余:

http://www.rene-pickhardt.de/graphity-an-efficient-graph-model-for-retrieving-the-top-k-news-feeds-for-users-in-social-networks/

在上面的链接中,您可以find屏幕录像和这种方法的基准(显示graphics能够每秒检索超过10k个stream)。

我昨天开始实施这样的系统,这里是我必须…

我使用属性IdActorIdTypeIdDateObjectId和其他Details键/值对的哈希表创build了一个StreamEvent类。 这在数据库中由StreamEvent表( IdActorIdTypeIdDateObjectId )和StreamEventDetails表( StreamEventIdDetailKeyDetailValue )表示。

ActorIdTypeIdObjectId允许捕获一个Subject-Verb-Object事件(以后再被查询)。 每个操作可能会导致创build多个StreamEvent实例。

然后,我为StreamEvent的每一类事件创build了一个子类,例如LoginEventPictureCommentEvent 。 这些子类中的每一个都有更多的上下文相关的属性,如PictureIdThumbNailCommenText等(事件所需要的),它们实际上是作为键/值对存储在散列表/ StreamEventDetail表中的。

从数据库中取回这些事件时,我使用一个工厂方法(基于TypeId )来创build正确的StreamEvent类。

StreamEvent的每个子类都有一个Render( context As StreamContext )方法,它根据传递的StreamContext类将事件输出到屏幕上。 StreamContext类允许根据视图的上下文来设置选项。 例如,如果你看Facebook,你的主页上的新闻源列出了每个动作所涉及的每个人的全名(和他们的个人资料的链接),而看着朋友的dynamic,你只能看到他们的名字(但是其他演员的全名) 。

我还没有实现聚合饲料(Facebook的家),但我想我会创build一个AggregateFeed表,其中有字段UserIdStreamEventId填充基于某种'嗯,你可能会发现这个有趣的'algorithm填充。

任何意见将大规模赞赏。

 //每个实际事件一个条目
事件{
   ID,时间戳,types,数据
 }

 //每个事件,每个包含该事件的提要一个条目
 events_feeds {
   event_id,feed_id
 }

当事件被创build时,决定它出现在哪个feed中,并将它们添加到events_feeds。 要获取供稿,请从events_feeds中select,join活动,按时间戳sorting。 然后可以对该查询的结果进行过滤和聚合。 使用此模型,您可以在创build后更改事件属性,而无需额外的工作。

如果你确定要在Rails中实现,也许你会发现下面的插件很有用:

ActivityStreams: http : //github.com/face/activity_streams/tree/master

如果没有别的,你将会看到一个实现,无论是在数据模型方面,还是为推拉活动提供的API。

我有一个类似于heyman的方法 – 一个非规范化的表格,包含了所有可以在给定的活动stream中显示的数据。 它适用于活动有限的小型网站。

如上所述,随着网站的发展,可能会面临可扩展性问题。 就我个人而言,我现在并不担心扩展问题。 我以后会担心的。

Facebook显然做了很好的缩放工作,所以我build议你阅读他们的工程博客,因为它有很多很棒的内容 – > http://www.facebook.com/notes.php?id=9445547199

我一直在寻找比上面提到的非规范化表更好的解决scheme。 我发现完成这个的另一个方法是将给定活动stream中的所有内容压缩成单行。 它可以以XML,JSON或一些可以被应用程序读取的序列化格式存储。 更新过程也很简单。 活动之后,将新活动放入队列(可能使用Amazon SQS或其他),然后不断轮询队列中的下一个项目。 抓取该项目,parsing它,并将其内容放置在数据库中存储的适当的提要对象中。

这种方法的好处在于,只要需要特定的提要,您只需要读取一个数据库表,而不是抓取一系列表。 而且,它允许您维护一个有限的活动列表,因为每当您更新列表时,都可能popup最早的活动项目。

希望这可以帮助! 🙂

有两个关于这样一个活动stream的railscast:

这些解决scheme不包括所有的要求,但它应该给你一些想法。

我认为Plurk的方法很有趣:他们提供的整个时间表格式看起来很像Google Finance的股票图表。

看看宁可看社交networking是如何工作的。 开发者页面看起来特别有用。

几个月前我解决了这个问题,但是我觉得我的实现太基础了。
我创build了以下模型:

 HISTORY_TYPE ID - The id of the history type NAME - The name (type of the history) DESCRIPTION - A description HISTORY_MESSAGES ID HISTORY_TYPE - A message of history belongs to a history type MESSAGE - The message to print, I put variables to be replaced by the actual values HISTORY_ACTIVITY ID MESSAGE_ID - The message ID to use VALUES - The data to use 

 MESSAGE_ID_1 => "User %{user} created a new entry" ACTIVITY_ID_1 => MESSAGE_ID = 1, VALUES = {user: "Rodrigo"} 

在实现活动stream以在多个应用程序中启用社交馈送,微博和协作function之后,我意识到基本function相当普遍,并且可以转化为您通过API使用的外部服务。 如果您正在将stream式生成到生产应用程序中,并且没有独特的或者非常复杂的需求,那么使用久经考验的服务可能是最好的select。 我肯定会推荐这个生产应用程序,而不是在关系型数据库上滚动你自己的简单解决scheme。

我的公司Collabinate( http://www.collabinate.com )是从这个实现中产生出来的,我们在一个graphics数据库之上实现了一个可扩展的,高性能的活动stream引擎来实现它。 我们实际上利用了Graphityalgorithm的一个变体(从@RenePickhardt的早期工作中进行了改编,他在这里也提供了答案)来构build引擎。

如果你想自己托pipe引擎或需要专门的function,核心代码实际上是非商业目的的开源,所以欢迎大家看看。