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

时间:2008-10-14 18:07:37

标签: ruby-on-rails android-activity social-networking

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

  • 不同类型的活动(发布,评论......)
  • 不同类型的对象(帖子,评论,照片......)
  • 参与不同角色的1-n个用户(“用户x回复用户y对用户的Z帖子的评论”)
  • 同一活动项目的不同观点(“您评论过”与“您的朋友x评论”对比“用户x评论...”=>“评论”活动的3个表示形式)

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

对于实施此类系统,数据模型等最灵活,最有效和最强大的方法的模式,论文等的任何想法或指示都将不胜感激。

虽然大多数问题都与平台无关,但我最终可能会在Ruby on Rails上实现这样的系统

13 个答案:

答案 0 :(得分:143)

我创建了这样的系统,我采用了这种方法:

包含以下列的数据库表:id,userId,type,data,time。

  • userId 是生成活动的用户
  • 类型是活动的类型(即撰写博文,添加照片,评论用户的照片)
  • 数据是一个序列化对象,其中包含活动的元数据,您可以将其放入任何您想要的内容

这限制了搜索/查找,您可以在Feed,用户,时间和活动类型中进行操作,但在facebook类型的活动Feed中,这并不是真正的限制。并且在表格上有正确的索引,查找 fast

使用此设计,您必须确定每种类型的事件应该需要哪些元数据。例如,新照片的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类的类,用于呈现不同类型的活动条目。事件的分组也将在渲染代码中构建,以避免数据库的复杂性。

答案 1 :(得分:116)

这是一个非常好的演示文稿,概述了Etsy.com如何构建他们的活动流。这是我在这个主题上找到的最好的例子,虽然它不是特定于轨道的。

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

答案 2 :(得分:42)

我们开源采用我们的方法: 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

This tutorial将帮助您使用Redis设置类似Pinterest的Feed。开始使用非常简单。

要了解有关饲料设计的更多信息,我强烈建议您阅读我们基于Feedly的一些文章:

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

答案 3 :(得分:19)

事件流的最大问题是可见性和性能;您需要将显示的事件限制为该特定用户的有趣事件,并且您需要保留排序所需的时间并确定可管理的事件。我建立了一个小型的社交网络;我发现在小规模的情况下,在数据库中保留“事件”表是有效的,但在适度负载下它会成为性能问题。

对于更大的消息和用户流,最好使用消息传递系统,其中事件作为消息发送到各个配置文件。这意味着您无法轻松订阅人员的事件流并轻松查看以前的事件,但是当您需要为特定用户呈现流时,您只需呈现一小组消息。

我相信这是Twitter的原始设计缺陷 - 我记得他们正在阅读他们正在访问数据库以吸引和过滤他们的事件。这与建筑有关,与Rails无关,Rails(不幸的是)生成了“红宝石无法扩展”的模因。我最近看到一个演示文稿,其中开发人员使用亚马逊的Simple Queue Service作为他们的消息传递后端,用于具有更高扩展能力的类似Twitter的应用程序 - 如果您的负载是负载,则可能值得将SQS视为系统的一部分。足够高。

答案 4 :(得分:12)

如果您愿意使用单独的软件,我建议使用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的流)。

答案 5 :(得分:10)

// 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中选择,加入事件,按时间戳排序。 然后可以对该查询的结果进行过滤和聚合。 使用此模型,您可以在创建后更改事件属性,而无需额外的工作。

答案 6 :(得分:10)

我昨天开始实施这样的系统,这是我必须要做的......

我创建了一个 StreamEvent 类,其属性为 Id ActorId TypeId Date < / em>, ObjectId 以及其他详细信息键/值对的哈希表。这在数据库中由 StreamEvent 表( Id ActorId TypeId Date < / em>, ObjectId )和 StreamEventDetails 表( StreamEventId DetailKey DetailValue )。

ActorId TypeId ObjectId 允许捕获(稍后查询)Subject-Verb-Object事件。每个操作都可能导致创建多个StreamEvent实例。

然后我为StreamEvent创建了一个子类,每个类型的事件,例如 LoginEvent PictureCommentEvent 。这些子类中的每一个都有更多特定于上下文的属性,例如 PictureId ThumbNail CommenText 等(事件需要的任何内容)存储为哈希表/ StreamEventDetail表中的键/值对。

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

StreamEvent的每个子类都有一个Render( context As StreamContext )方法,该方法根据传递的 StreamContext 类将事件输出到屏幕。 StreamContext类允许根据视图的上下文设置选项。例如,如果以Facebook为例,您在主页上的新闻列表会列出每个操作中涉及的每个人的全名(以及指向其个人资料的链接),而查看朋友的Feed只会看到他们的名字(但是其他演员的全名)

我还没有实现聚合Feed(Facebook主页),但我想我会创建一个 AggregateFeed 表,其中包含 UserId StreamEventId字段根据某种“嗯,您可能会发现这个有趣的算法”填充。

任何评论都会受到高度赞赏。

答案 7 :(得分:8)

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

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

如果没有别的,你将会看到一个实现,包括数据模型,以及为推拉活动提供的API。

答案 8 :(得分:6)

我有类似于heyman的方法 - 一个非规范化表,包含将在给定活动流中显示的所有数据。它适用于活动有限的小网站。

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

Facebook显然做得很好,所以我建议你阅读他们的工程博客,因为它有很多很棒的内容 - &gt; http://www.facebook.com/notes.php?id=9445547199

我一直在研究比上面提到的非规范化表更好的解决方案。我发现实现此目的的另一种方法是将给定活动流中的所有内容压缩成单行。它可以存储为XML,JSON或某些可由应用程序读取的序列化格式。更新过程也很简单。在活动时,将新活动放入队列(可能使用Amazon SQS或其他内容),然后不断轮询队列以查找下一个项目。抓取该项目,对其进行解析,并将其内容放在存储在数据库中的相应Feed对象中。

这种方法的好处在于,您只需要在请求特定订阅源时读取单个数据库表,而不是抓取一系列表。此外,它允许您维护有限的活动列表,因为您可以在更新列表时弹出最旧的活动项目。

希望这有帮助! :)

答案 9 :(得分:5)

有关此类活动流的两个轨道广播:

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

答案 10 :(得分:3)

我认为Plurk's方法很有意思:它们提供的整个时间表格式与Google财经的股票图表非常相似。

可能值得查看Ning以了解社交网络的运作方式。 developer页面看起来特别有用。

答案 11 :(得分:2)

几个月前我解决了这个问题,但我认为我的实施太基础了 我创建了以下模型:

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"}

答案 12 :(得分:2)

在实现活动流以在多个应用程序中启用社交订阅源,微博和协作功能后,我意识到基本功能非常普遍,可以转换为您通过API使用的外部服务。如果要将流构建到生产应用程序中并且没有独特或非常复杂的需求,那么使用经过验证的服务可能是最佳方法。对于生产应用程序,我肯定会建议在关系数据库之上滚动您自己的简单解决方案。

我的公司Collabinate(http://www.collabinate.com)源于此实现,我们在图形数据库之上实现了可扩展的高性能活动流引擎来实现它。我们实际上使用了Graphity算法的一种变体(改编自@RenePickhardt的早期工作,也在这里提供了答案)来构建引擎。

如果您想自己托管引擎或需要专门的功能,核心代码实际上是非商业用途的开源,所以欢迎您来看看。