如何在社交网络中实现活动流

Posted

技术标签:

【中文标题】如何在社交网络中实现活动流【英文标题】:How to implement the activity stream in a social network 【发布时间】:2010-11-29 11:03:24 【问题描述】:

我正在开发自己的社交网络,但我在网络上没有找到用户操作流的实现示例...例如,如何过滤每个用户的操作?如何存储动作事件?我可以为动作流和动作本身使用哪种数据模型和对象模型?

【问题讨论】:

祝你好运,这是我们都想知道的永无止境的问题,facebook 是如何做到的,答案非常复杂,我们可能永远不知道最有效的方法。如果您找到了一个好的方法,请在此处发布以供其他人查看,顺便说一句,这已经在 SO 上讨论了很多次,所以只需搜索,您会发现一些提示 Stream Framework 是使用最广泛的解决方案:github.com/tschellenbach/Stream-Framework 另请参阅此软件包列表:djangopackages.com/grids/g/activities 在个性化方面它基于分析和机器学习,另见getstream.io/personalization 【参考方案1】:

总结:对于大约 100 万活跃用户和 1.5 亿存储活动,我保持简单:

使用关系数据库来存储唯一活动(每个活动 1 条记录/“发生的事情”) 使记录尽可能紧凑。结构,以便您可以通过活动 ID 或使用一组有时间限制的朋友 ID 快速抓取一批活动。 每当创建活动记录时,将活动 ID 发布到 Redis,将 ID 添加到应该看到该活动的每个朋友/订阅者的“活动流”列表中。

查询 Redis 以获取任何用户的活动流,然后根据需要从数据库中获取相关数据。如果用户需要及时浏览(如果你甚至提供这个),则回退到按时间查询数据库


我使用一个普通的旧 mysql 表来处理大约 1500 万个活动。

看起来像这样:

id             
user_id       (int)
activity_type (tinyint)
source_id     (int)  
parent_id     (int)
parent_type   (tinyint)
time          (datetime but a smaller type like int would be better) 

activity_type 告诉我活动的类型,source_id 告诉我活动相关的记录。因此,如果活动类型表示“添加收藏”,那么我知道 source_id 是指收藏记录的 ID。

parent_id/parent_type 对我的应用很有用 - 它们告诉我活动与什么相关。如果收藏了一本书,则 parent_id/parent_type 会告诉我该活动与具有给定主键 (id) 的一本书 (类型) 相关

我在(user_id, time) 上建立索引并查询user_id IN (...friends...) AND time > some-cutoff-point 的活动。放弃 id 并选择不同的聚集索引可能是个好主意 - 我还没有尝试过。

相当基本的东西,但它很有效,很简单,并且随着您的需求变化很容易使用。此外,如果您不使用 MySQL,您可能会在索引方面做得更好。


为了更快地访问最新活动,我一直在尝试使用Redis。 Redis 将其所有数据存储在内存中,因此您不能将所有活动都存储在其中,但您可以存储足够多的内容以供您网站上的大多数常用屏幕使用。每个用户的最近 100 个或类似的东西。混合使用 Redis,它可能会像这样工作:

创建您的 MySQL 活动记录 对于创建活动的用户的每个朋友,将 ID 推送到他们在 Redis 中的活动列表中。 将每个列表修剪到最后 X 项

Redis 速度很快,并且提供了一种通过一个连接传递命令的方法 - 因此将活动推送给 1000 个朋友需要几毫秒。

有关我所说的内容的更详细说明,请参阅 Redis 的 Twitter 示例:http://redis.io/topics/twitter-clone

2011 年 2 月更新我目前有 5000 万个活跃活动,我没有改变任何东西。做与此类似的事情的一件好事是它使用紧凑的小行。我计划进行一些更改,这些更改将涉及更多活动和对这些活动的更多查询,我肯定会使用 Redis 来保持速度。我在其他领域使用 Redis,它确实适用于某些类型的问题。

2014 年 7 月更新我们每月有大约 70 万活跃用户。在过去的几年里,我一直在使用 Redis(如项目符号列表中所述)来存储每个用户的最后 1000 个活动 ID。系统中通常有大约 1 亿条活动记录,它们仍然存储在 MySQL 中,并且仍然是相同的布局。这些记录让我们摆脱了更少的 Redis 内存,它们作为活动数据的记录,如果用户需要进一步回溯以查找某些内容,我们会使用它们。

这不是一个聪明或特别有趣的解决方案,但它对我很有帮助。

【讨论】:

+1 用于 Redis。 v2 使用虚拟内存,所以应该可以完全依赖 Redis 如果有多个活动来源(添加、评论、点赞等),如何将这个表与实际活动连接起来?您是否使用多个左连接(每个用于一个活动表)? @casey 回应@JohnS 的问题——你如何在各种activity_type 表上执行JOIN?这些连接在性能方面是否昂贵? 有人回答 JohnS 关于“JOIN”的问题吗?任何人都可以发布一个可以解释的链接吗?我必须做类似的事情,这对我很有帮助。 无连接。每个唯一的activity_type 进行一次查询,以获取您需要的其他数据。【参考方案2】:

这是我使用 mysql 实现的活动流。 共有三个类:Activity、ActivityFeed、Subscriber。

Activity代表一个Activity入口,它的表格如下所示:

id
subject_id
object_id
type
verb
data
time

Subject_id是执行动作的对象的id,object_id是接收动作的对象的id。 typeverb 描述操作本身(例如,如果用户向文章添加评论,他们将分别是“评论”和“创建”),数据包含额外的数据以避免连接(例如,可以包含主题名和姓氏、文章标题和网址、评论正文等)。

每个 Activity 属于一个或多个 ActivityFeed,它们通过如下所示的表关联:

feed_name
activity_id

在我的应用程序中,每个用户都有一个提要,每个项目(通常是博客文章)都有一个提要,但它们可以是您想要的任何内容。

订阅者通常是您网站的用户,但也可以是您的对象模型中的任何对象(例如,一篇文章可以订阅其创建者的 feed_action)。

每个订阅者都属于一个或多个 ActivityFeed,并且像上面一样,它们通过这种链接表相关:

feed_name
subscriber_id
reason

此处的reason 字段解释了订阅者订阅源的原因。例如,如果用户为博客文章添加书签,则原因是“书签”。这有助于我稍后过滤通知用户的操作。

为了检索订阅者的活动,我对三个表进行了简单的连接。由于 WHERE 条件现在看起来像 - time > some hours,我选择了很少的活动,因此加入速度很快。由于 Activity 表中的数据字段,我避免了其他联接。

关于reason 字段的进一步说明。例如,如果我想过滤发送给用户的电子邮件通知的操作,并且用户为博客文章添加了书签(因此他以“书签”的原因订阅了帖子提要),我不希望用户收到有关该项目操作的电子邮件通知,而如果他对帖子进行了 cmets(因此它以“评论”的原因订阅了帖子提要),我希望在其他用户将 cmets 添加到同一个帖子时通知他。原因字段帮助我进行这种区分(我通过 ActivityFilter 类实现了它),以及用户的通知偏好。

【讨论】:

Nicolo martini 我想添加对活动的回复评论并在其下方显示,您的结构怎么可能?我应该添加另一个表还是只使用相同的表,如果相同,那么您有什么建议? 这个实现的性能如何?对大表进行任何测试?【参考方案3】:

目前有一种由一群知名人士开发的活动流格式。

http://activitystrea.ms/。

基本上,每个活动都有一个参与者(执行该活动)、一个动词(该活动的动作)、一个对象(参与者在其上执行)和一个目标。

例如:Max 发布了指向 Adam 的墙的链接。

在撰写本文时,他们的 JSON 规范已达到 1.0 版,它显示了您可以应用的活动模式。

它们的格式已被 BBC、Gnip、Google Buzz Gowalla、IBM、MySpace、Opera、Socialcast、Superfeedr、TypePad、Windows Live、YIID 和许多其他公司采用。

【讨论】:

嗨@sntran 我知道这篇文章是几年前的,但我有更多关于活动流的问题。有什么办法可以帮忙吗? 当然。你有什么问题? 我的问题居然贴在这里! link。我想我对活动流有基本的了解,但我真的不太确定如何实现它(即我应该使用 angular 还是 node.js?)从那里,我如何实际创建一个活动流传入的 API JSON?这些都是如此基本的问题,但我在网上找不到任何答案。如果您能提供帮助,我将不胜感激。谢谢!【参考方案4】:

我认为关于通知系统如何在大型网站上工作的解释可以在堆栈溢出问题how does social networking websites compute friends updates? 中找到,在Jeremy Wall 的答案中。他建议使用 Message Queue,并指出了两个实现它的开源软件:

    RabbitMQ Apache QPid

另见问题What’s the best manner of implementing a social activity stream?

【讨论】:

【参考方案5】:

您绝对需要一个高性能的分布式消息队列。但这并不止于此,您必须决定将哪些存储为持久数据以及哪些存储为瞬态数据等。

无论如何,我的朋友,如果您追求高性能和可扩展的系统,这确实是一项艰巨的任务。但是,当然,一些慷慨的工程师分享了他们在这方面的经验。 LinkedIn 最近将其消息队列系统 Kafka 开源。在此之前,Facebook 已经向开源社区提供了 Scribe。 Kafka 是用 Scala 编写的,起初它需要一些时间才能运行,但我用几个虚拟服务器进行了测试。它真的很快。

http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/

http://incubator.apache.org/kafka/index.html

【讨论】:

【参考方案6】:

您可以寻找通过 API 使用的第三方服务,而不是自己动手。我开始了一个名为 Collabinate (http://www.collabinate.com) 的项目,它有一个图形数据库后端和一些相当复杂的算法,用于以高并发、高性能的方式处理大量数据。虽然它没有 Facebook 或 Twitter 那样广泛的功能,但对于大多数需要在应用程序中构建活动流、社交源或微博功能的用例来说,它已经足够了。

【讨论】:

以上是关于如何在社交网络中实现活动流的主要内容,如果未能解决你的问题,请参考以下文章

社交网络数据库模式中的活动流/提要/新闻

如何在 Groovy/Grails 上实现社交网络登录? [关闭]

如何在社交网络上实现一个可以让不同人获得 5 次奖励的链接?

如何在 Kivy 中实现社交分享按钮

开放流 API

社交网络场景中的 Azure 通知中心最佳实践