【问题标题】:What's the best manner of implementing a social activity stream? [closed]实施社交活动流的最佳方式是什么? [关闭]
【发布时间】:2010-09-17 03:53:38
【问题描述】:

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

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

.. 还有更多,特别是如果您将其提升到高水平,就像 Facebook 所做的那样,例如,将多个活动项目合并为一个(“用户 x、y 和 z 评论了那张照片”

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

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

【问题讨论】:

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


    【解决方案1】:

    我们已经开源了我们的方法: 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。不过目前你必须扮演自己的角色。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

        在上面的链接中,您可以找到截屏视频和此方法的基准(表明 graphity 每秒能够检索超过 10k 个流)。

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

          • PublicActivity 很棒,可以处理问题中的所有用例。
          【解决方案5】:

          这是一个很好的演示文稿,概述了 Etsy.com 如何构建他们的活动流。这是我找到的关于该主题的最佳示例,尽管它不是特定于 Rails 的。

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

          【讨论】:

          • ^^ 因为访问该站点后您必须回到SO。大声笑
          • 很棒的演示文稿,详细解释了系统如何在真正的高流量网站上工作。
          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:
            // 每个实际事件一个条目 事件{ id、时间戳、类型、数据 } // 每个事件一个条目,每个包含该事件的提要 events_feeds { event_id, feed_id }

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

            【讨论】:

            • 假设在添加事件后将其他人添加为朋友,需要在他们的提要中查看此事件吗?那么这将不起作用
            【解决方案8】:

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

            我创建了一个具有 IdActorIdTypeIdDateStreamEvent 类/em>、ObjectId 和附加 Details 键/值对的哈希表。这在数据库中由 StreamEvent 表(IdActorIdTypeIdDate、ObjectId)和一个 StreamEventDetails 表(StreamEventIdDetailKeyDetailValue)。

            ActorIdTypeIdObjectId 允许捕获(并稍后查询)主题-动词-对象事件。每个动作都可能导致创建多个 StreamEvent 实例。

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

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

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

            我还没有实现聚合提要(Facebook 主页),但我想我会创建一个 AggregateFeed 表,其中包含字段 UserIdStreamEventId 它是基于某种“嗯,你可能会发现这个有趣的”算法填充的。

            任何 cmets 都将不胜感激。

            【讨论】:

            • 我正在开发这样的系统,对任何相关知识都非常感兴趣,您完成了吗?
            • 很好的答案!出色的关注点分离,干净优雅!
            • 这是一个好的开始!这与我开始实施我的第一个流的方式非常相似。但是,一旦您到达聚合提要,事情就会开始迅速变得复杂。你是对的,你需要一个健壮的算法。我的搜索使我找到了 Rene Pickhardt 的算法(他在此处的回答中谈到了它),然后我将其实施到了我自己的服务中,该服务现已商业化(请参阅collabinate.com 和我对这个问题的回答了解更多信息)。
            【解决方案9】:

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

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

            如果不出意外,您将了解一个实现,包括数据模型以及为推送和拉取活动提供的 API。

            【讨论】:

              【解决方案10】:

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

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

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

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

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

              希望这会有所帮助! :)

              【讨论】:

              • 正是我的想法,我只需要验证我现在可能得到的想法,干杯!
              【解决方案11】:

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

              具有以下列的数据库表:id、userId、type、data、time。

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

              这限制了搜索/查找,您可以在供稿中对用户、时间和活动类型进行限制,但在 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 类的类,用于呈现不同类型的活动条目。事件分组也将内置在渲染代码中,以避免数据库的复杂性。

              【讨论】:

              • 是的,没错。最近我在一些项目中使用了 MongoDB (mongodb.org),它的无模式方法使其非常适合创建遵循此设计的性能良好的社交活动流。
              • TheApprentice:是的,您可能还想输入用户名字段。在我们的系统中,我们只显示了一个用户的朋友产生的事件,而且我相信我们已经在内存中拥有了一个朋友的 userid->username 的映射,所以查找用户名不需要 JOIN 并且很快。跨度>
              • 您必须手动处理这种情况。最好在照片被删除时执行此操作(在用户的提要中找到提要项,然后删除/更新它)。
              • 我不太明白这个答案有什么了不起的?创建一个简单的表格如何转化为类似于 facebook 的加权活动提要?他所做的只是存储所有的活动。仍然存在如何将数据表转换为动态加权活动提要的问题?
              • @ChuckKelly:如果我没记错的话,早在 2008 年,当我写答案时,Facebook 提要根本没有加权。这只是一个按时间顺序排列的来自您朋友的所有活动的提要。
              【解决方案12】:

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

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

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

              【讨论】:

              • 蒂姆,你还记得演讲或演讲者的名字吗?
              • 这是在 Oreilly 和 Associate 的 Ignite Boston 演示中,第 3 或第 4 次 - 我相信演示者有一本关于使用 Oreilly 扩展 RoR 的书。抱歉,我不能更具体!
              • 谢谢蒂姆 :) 顺便问一下,“小型社交网络”是什么意思?有多少用户,或者某个时间有多少活跃用户?
              • 如果有人需要,我想这就是 Tim 正在谈论的演示文稿:“Dan Chak -- 缩放到你的问题的大小”radar.oreilly.com/2008/09/ignite-boston-4----videos-uplo.html
              • 在这种情况下,“从 event.is 对这个用户可见的事件中选择 *”会在不到一秒或两位数的情况下返回一个结果,即几十万行的事件。
              【解决方案13】:

              我认为Plurk's 的方法很有趣:它们以一种看起来很像 Google Finance 的股票图表的格式提供您的整个时间线。

              可能值得关注Ning 以了解社交网络的工作原理。 developer 页面看起来特别有用。

              【讨论】:

                猜你喜欢
                • 2017-05-17
                • 2010-09-08
                • 2017-11-19
                • 1970-01-01
                • 2017-12-18
                • 2022-11-09
                • 1970-01-01
                • 2013-11-16
                • 1970-01-01
                相关资源
                最近更新 更多