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


265

我很想听听您的意见,这是实施社交活动流的最佳方法(Facebook是最著名的例子)。涉及的问题/挑战是:

  • 不同类型的活动(发布,评论..)
  • 不同类型的对象(帖子,评论,照片..)
  • 1-n位用户扮演不同的角色(“用户x在用户Z帖子上回复了用户y的评论”)
  • 相同活动项目的不同视图(“您评论..”与“您的朋友x评论”与“用户x评论..” =>“评论”活动的3种表示形式)

等等,尤其是如果您将其高度复杂化时,例如Facebook,例如,将多个活动项合并为一个(“用户x,y和z在该照片上发表了评论”

关于模式,纸张等的任何想法或指针,关于实现这种系统,数据模型等的最灵活,有效和强大的方法。

尽管大多数问题与平台无关,但我最终还是有可能在Ruby on Rails上实现这样的系统

Answers:


143

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

数据库表具有以下列:id,userId,类型,数据,时间。

  • userId是生成活动的用户
  • type是活动的类型(例如,写博客文章,添加照片,对用户的照片发表评论)
  • 数据是带有活动元数据的序列化对象,您可以在其中放入所需的任何内容

这限制了您可以在提要中进行的搜索/查找,用户,时间和活动类型,但是在Facebook型活动提要中,这并不是真正的限制。并且在表上有正确的索引,查找速度很快

使用这种设计,您将不得不决定每种事件类型都需要哪些元数据。例如,一张新照片的供稿活动可能如下所示:

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

您可以看到,尽管最确定的是照片的名称存储在其他包含照片的表中,并且可以从那里检索该名称,但是我会在元数据字段中重复该名称,因为您不想这样做如果需要速度,可以在其他数据库表上进行任何联接。为了显示来自50个不同用户的200个不同事件,您需要速度。

然后,我有一些类扩展了基本的FeedActivity类,以呈现不同类型的活动条目。事件分组也将内置在呈现代码中,以使数据库免于复杂性。


3
是的,没错。最近,我在一些项目中使用了MongoDB(mongodb.org),其无模式方法使其非常适合创建遵循此设计的性能良好的社交活动流。
heyman 2010年

6
TheApprentice:是的,您可能还想输入一个用户名字段。在我们的系统中,我们仅显示由用户的朋友生成的事件,并且我相信我们已经在内存中映射了朋友的userid-> username的映射,因此查找用户名不需要JOIN,而且速度很快。
海曼2010年

2
您将不得不手动处理这种情况。最好在删除照片后执行此操作(在用户的供稿中查找供稿项,然后删除/更新)。
heyman

21
我不太了解这个答案有什么好处?创建简单表格如何转化为类似于Facebook的加权活动供稿?他所做的只是存储所有活动。哪还有一个问题,如何将数据表转换为动态加权活动提要?
ChuckKelly

4
@ChuckKelly:如果我没记错的话,早在2008年,当我写下答案时,Facebook提要根本就没有加权。这只是您的朋友所有活动的按时间顺序排列的提要。
heyman


44

我们已经开源了我们的方法: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的一些文章:

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


19

事件流的最大问题是可见性和性能。您需要将显示的事件限制为仅是该特定用户感兴趣的事件,并且需要保持整理和识别这些事件所需的时间量是可管理的。我建立了一个很小的社交网络;我发现在较小的规模上,在数据库中保留“事件”表是可行的,但是在中等负载下它将成为性能问题。

随着消息和用户流的增加,最好使用消息传递系统,在该系统中,事件作为消息发送到各个配置文件。这意味着您无法轻松地订阅人们的事件流并非常轻松地查看以前的事件,但是当您需要为特定用户呈现流时,您只是呈现一小群消息。

我相信这是Twitter的原始设计缺陷-我记得曾读过他们访问数据库以提取和过滤事件的信息。这与体系结构完全无关,而与Rails无关(不幸的是,Rails产生了“红宝石无法缩放”模因)。我最近看到一个演示,其中开发人员使用Amazon的Simple Queue Service作为类似Twitter的应用程序的消息传递后端,该应用程序具有更高的扩展能力-如果您的负载足够高,则值得将SQS作为系统的一部分进行研究。


蒂姆,您是否还记得演讲者或演讲者的名字?
丹妮塔(Danita)

在Oreilly和Associate的Ignite Boston演讲中,排名第3或第4位。我相信演示者有一本书,内容涉及缩放Oreilly的RoR。对不起,我不能说得更具体!
蒂姆·霍兰德,

谢谢蒂姆:)顺便说一句,“小型社交网络”是什么意思?某个时间有多少用户或活跃用户?
丹妮塔(Danita),2009年

3
万一有人需要,我想这是蒂姆正在谈论的演示文稿:“ 丹泽
Danita,2009年

在这种情况下很小,因此“从对用户可见event ..的事件中选择*”可在不到一秒或两位数的时间内返回价值数十万行的事件。
蒂姆·豪兰

12

如果您愿意使用单独的软件,我建议使用Graphity服务器,它可以完全解决活动流的问题(在neo4j图形数据库的基础上构建)。

该算法已实现为独立的REST服务器,因此您可以托管自己的服务器以交付活动流: http //www.rene-pickhardt.de/graphity-server-for-social-activity-streams-released-gplv3 /

在论文和基准测试中,我表明检索新闻流仅线性依赖于要检索的项目数量,而不会因对数据进行非规范化而产生任何冗余:

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

在上面的链接中,您可以找到此方法的截屏视频和基准(显示图形性每秒可以检索1万多个流)。


10

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

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

actorId来TYPEID的ObjectId允许被捕获的主语-动词-对象事件(后来查询)。每个操作可能导致创建几个StreamEvent实例。

然后,我为每种事件类型的StreamEvent创建了一个子类,例如LoginEventPictureCommentEvent。这些子类中的每一个都有更多特定于上下文的属性,例如PictureIdThumbNailCommenText等(事件需要什么),这些属性实际上作为键/值对存储在hashtable / StreamEventDetail表中。

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

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

我尚未实现聚合供稿(Facebook主页),但我想我将创建一个具有字段UserIdStreamEventIdAggregateFeed基于某种“嗯,您可能会发现这个有趣的”算法填充的。

任何评论将不胜感激。


我正在研究这样的系统,对其中的任何知识都非常感兴趣,您是否完成过您的研究?
杰森·戴维斯(JasonDavis)2009年

好答案!完美分离关注点,干净优雅!
莫什(Mosh)2012年

这是一个好的开始!这与我开始实施第一流的方式非常相似。但是,一旦获得了汇总提要,事情就会开始变得很快变得复杂。没错,您需要一个可靠的算法。我的搜索使我想到了Rene Pickhardt的算法(他在此处的答案中谈到了该算法),然后将其实现到自己的服务中,该服务现已投入商业使用(有关更多信息,请参阅collabinate.com和我对这个问题的回答)。
马富巴

10
//每个实际事件一个条目
事件{
  id,时间戳,类型,数据
}

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

创建事件后,请确定事件显示在哪个供稿中,并将其添加到events_feeds中。要获取供稿,请从events_feeds中选择,加入事件,并按时间戳排序。然后可以对该查询的结果进行过滤和聚合。使用此模型,您可以在创建后更改事件属性,而无需进行额外的工作。


1
假设在添加事件后将其他人添加为朋友,需要在其供稿中查看此事件吗?那么这将行不通
约书亚·基斯顿


6

我有一个与Heyman类似的方法-一个非规范化表,其中包含将在给定活动流中显示的所有数据。对于活动受限的小型站点,它工作正常。

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

Facebook显然在扩展方面做得很出色,所以我建议您阅读他们的工程博客,因为它有很多很棒的内容-> http://www.facebook.com/notes.php?id=9445547199

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

这种方法的好处是,只要请求特定的提要,您就只需要读取一个数据库表,而不用获取一系列表。而且,它允许您维护活动的有限列表,因为每当更新列表时,都可能会弹出最旧的活动项目。

希望这可以帮助!:)


正是我的想法,我只需要验证一下我现在可能已经得到的想法,加油!
Sohail


3

我认为Plurk的方法很有趣:它们以类似于Google财经的股票图表的格式提供您的整个时间表。

这可能是值得考虑的看到了社交网络是如何工作的。该开发者页面看起来特别有帮助。


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

2

在实现活动流以在多个应用程序中启用社交提要,微博和协作功能之后,我意识到基本功能非常普遍,可以通过API转化为外部服务。如果您要将流构建到生产应用程序中,并且没有独特或非常复杂的需求,则使用行之有效的服务可能是最好的方法。我绝对建议在生产应用程序中使用它,而不是在关系数据库之上滚动自己的简单解决方案。

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

如果您想自己托管引擎或需要特殊功能,那么核心代码实际上是出于非商业目的的开源代码,因此欢迎您查看。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.