ソーシャルアクティビティストリームを実装する最良の方法は何ですか?[閉まっている]


265

ソーシャルアクティビティストリームを実装する最良の方法はどれですか(Facebookが最も有名な例です)。関連する問題/課題は次のとおりです。

  • さまざまな種類のアクティビティ(投稿、コメントなど)
  • さまざまな種類のオブジェクト(投稿、コメント、写真など)
  • さまざまな役割に関与する1-nユーザー(「ユーザーxはユーザーZの投稿に対するユーザーyのコメントに返信しました」)
  • 同じアクティビティアイテムのさまざまなビュー(「あなたがコメントした..」vs.「あなたの友人xがコメントした」vs.「ユーザーxがコメントした..」=>「コメント」アクティビティの3つの表現)

..その他、特にFacebookのように高度なレベルに進んだ場合、たとえば、複数のアクティビティ項目を1つに結合する(「ユーザーx、y、zがその写真にコメントした」)

そのようなシステム、データモデルなどを実装するための最も柔軟で効率的で強力なアプローチについてのパターンや論文などについての考えや指針は、高く評価されます。

ほとんどの問題はプラットフォームに依存しませんが、Ruby on Railsでこのようなシステムを実装する可能性があります

回答:


143

私はそのようなシステムを作成し、私はこのアプローチをとりました:

次の列を持つデータベーステーブル:id、userId、type、data、time。

  • 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)を使用していますが、そのスキーマレスなアプローチにより、このデザインに従ってパフォーマンスの高いソーシャルアクティビティストリームを作成するのに非常に適しています。
ヘイマン

6
TheApprentice:ええ、ユーザー名のフィールドも入れたいかもしれません。私たちのシステムでは、ユーザーの友達によって生成されたイベントのみを表示し、メモリーには友達のユーザーID->ユーザー名のマップがすでにあると思います。したがって、ユーザー名の検索はJOINを必要とせず、高速でした。
ヘイマン

2
その場合は手動で処理する必要があります。写真が削除されたときに実行することをお勧めします(ユーザーのフィードでフィード項目を見つけ、削除/更新します)。
ヘイマン

21
私はこの答えについて何がそんなに素晴らしいのか全く理解できませんか?単純なテーブルを作成すると、facebookと同様の加重アクティビティフィードにどのように変換されますか?彼がしていることはすべて、すべての活動を保存することです。データのテーブルを動的に重み付けされたアクティビティフィードに変換する方法の問題はまだ残っていますか?
ChuckKelly 2013

4
@ChuckKelly:私が正しく思い出せば、2008年に答えを書いたとき、Facebookフィードはまったく重み付けされていませんでした。それはあなたの友人からのすべての活動を含む時系列のフィードでした。
ヘイマン14

117

これは、Etsy.comがアクティビティストリームをどのように構築したかを概説する非常に優れたプレゼンテーションです。これは、このトピックで見つけた最良の例ですが、レール固有ではありません。

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


21
^^サイトを訪れた後、SOに戻る必要があるため。笑
スティーブンコーウィン

1
実際の高トラフィックのWebサイトでシステムがどのように機能するかを詳しく説明する素晴らしいプレゼンテーション。
ramirami 2013年

44

私たちはアプローチをオープンソース化しました:https : //github.com/tschellenbach/Stream-Framework これは現在、この問題の解決を目的とした最大のオープンソースライブラリです。

Stream Frameworkを構築した同じチームは、複雑さを処理するホストされたAPIも提供します。見てgetstream.ioノード、パイソン、RailsとPHPで利用可能なクライアントがあります。

さらに、この高いスケーラビリティに関する投稿を見て、関連する設計上の決定のいくつかを説明します。http//highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feeds.html

このチュートリアルは、PinterestのフィードのようなシステムをRedisを使用して設定するのに役立ちます。始めるのはとても簡単です。

フィードのデザインについて詳しく知るために、Feedlyのベースとなっている記事を読むことを強くお勧めします。

Stream FrameworkはPythonベースですが、Rubyアプリから使用するのはそれほど難しくありません。単にサービスとして実行し、小さなhttp APIをその前に置くことができます。他の言語からFeedlyにアクセスするためのAPIの追加を検討しています。現時点では、自分の役割を担う必要があります。


19

イベントストリームの最大の問題は、可視性とパフォーマンスです。表示されるイベントを、その特定のユーザーにとって興味深いイベントだけに制限する必要があり、それらのイベントを整理して特定するのにかかる時間を管理しやすくする必要があります。小さめのソーシャルネットワークを構築しました。小規模では、データベースに「イベント」テーブルを保持することは機能しますが、中程度の負荷ではパフォーマンスの問題になることがわかりました。

メッセージとユーザーのストリームが大きい場合、イベントがメッセージとして個々のプロファイルに送信されるメッセージングシステムを使用するのがおそらく最善です。つまり、ユーザーのイベントストリームを簡単にサブスクライブして以前のイベントを簡単に確認することはできませんが、特定のユーザーに対してストリームをレンダリングする必要がある場合は、メッセージの小さなグループをレンダリングするだけです。

これはTwitterの元々の設計上の欠陥だったと思います-彼らがデータベースにアクセスしてイベントを取得し、フィルタリングしていたことを読んだことを覚えています。これはアーキテクチャーとすべて関係があり、Railsとは関係がありませんでした。(残念ながら)「ルビーはスケーリングしない」ミームを生み出しました。私は最近、開発者がAmazonのSimple Queue ServiceをTwitterのようなアプリケーションのメッセージングバックエンドとして使用し、はるかに高いスケーリング機能を備えたプレゼンテーションを見ました-負荷が十分に高い場合、システムの一部としてSQSを調べる価値があるかもしれません。


ティムさん、プレゼンテーションの名前やプレゼンターの名前を覚えていますか?
ダニタ

それはOreillyとアソシエイトのIgnite Bostonプレゼンテーション3または4のどちらかでした。申し訳ありませんが、具体的には言えません。
ティムハウランド

ありがとうティム:)ところで、「小さめのソーシャルネットワーク」とはどういう意味ですか?何人のユーザー、または特定の時間のアクティブユーザー?
ダニタ

3
誰かがそれを必要とする場合、私はこれがティムが話しているプレゼンテーションだと思います:「ダンチャク
ダニタ

この場合の小ささは、「select * from event。is visible for this user」が1秒または2桁未満、数十万行のイベントに相当する結果を返すようなものです。
Tim Howland、

12

別のソフトウェアを使用する場合は、アクティビティストリーム(neo4jグラフデータベースの上に構築)の問題を正確に解決するGraphityサーバーをお勧めします。

独自のサーバーをホストしてアクティビティストリームを配信できるように、アルゴリズムはスタンドアロン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は1秒あたり10kを超えるストリームを取得できることを示しています)。


10

私は昨日このようなシステムを実装し始めました、ここで私がしなければならないところです...

プロパティIdActorIdTypeIdDateObjectIdと追加の詳細キー/値ペアのハッシュテーブルを使用してStreamEventクラスを作成しました。これは、データベースではStreamEventテーブル(IdActorIdTypeIdDateObjectId)およびStreamEventDetailsテーブル(StreamEventIdDetailKeyDetailValue)によって表されます。

アクターID型IDのObjectIdは、件名、動詞オブジェクトイベントがキャプチャ(およびそれ以降の照会)することを可能にします。各アクションにより、複数のStreamEventインスタンスが作成される場合があります。

次に、EventEventの各タイプのイベント(LoginEventPictureCommentEventなど)のサブクラスを作成しました。これらの各サブクラスには、PictureIdThumbNailCommenTextなどのよりイベント固有のプロパティ(イベントに必要なもの)があり、実際にはハッシュテーブル/ StreamEventDetailテーブルにキー/値のペアとして格納されます。

これらのイベントをデータベースからプルバックするとき、ファクトリーメソッド(TypeIdに基づく)を使用して正しいStreamEventクラスを作成します。

StreamEventの各サブクラスには、渡されたStreamContextクラスに基づいてイベントを画面に出力するRender(context As StreamContext)メソッドがあります。StreamContextクラスを使用すると、ビューのコンテキストに基づいてオプションを設定できます。たとえば、Facebookを見ると、ホームページのニュースフィードには各アクションに関与する全員のフルネーム(およびそのプロフィールへのリンク)が表示されますが、友達のフィードを見ると、ファーストネームしか表示されません(他の俳優のフルネームは表示されます)。 。

私はまだ集約フィード(Facebookホーム)を実装していませんが、ある種の「Hmmmに基づいて入力されるフィールドUserIdStreamEventIdを持つAggregateFeedテーブルを作成すると思います。この興味深いアルゴリズムが見つかるかもしれません。

コメントをいただければ幸いです。


私はこのようなシステムに取り組んでいますが、それに関する知識に非常に興味があります。
JasonDavis、2009

正解です。懸念の分離、クリーンでエレガント!
Mosh 2012

これは良いスタートです!これは、最初のストリームの実装を開始した方法と非常によく似ています。ただし、集約フィードに到達すると、状況は急速に複雑化し始めます。確かに、堅牢なアルゴリズムが必要です。私の検索により、Rene Pickhardtのアルゴリズム(彼はここで彼の答えでそれについて語っています)に導きました。それを私は自分のサービスに実装しましたが、現在は商用です(詳細については、collabinate.comとこの質問に対する私の答えを参照してください)。
マフバ2013

10
//実際のイベントごとに1つのエントリ
イベント{
  ID、タイムスタンプ、タイプ、データ
}

//イベントごとに、そのイベントを含むフィードごとに1つのエントリ
events_feeds {
  event_id、feed_id
}

イベントが作成されたら、表示するフィードを決定し、それらをevents_feedsに追加します。フィードを取得するには、events_feedsから選択し、イベントに参加し、タイムスタンプ順に並べます。次に、そのクエリの結果に対してフィルタリングと集計を実行できます。このモデルでは、追加の作業なしで、作成後にイベントプロパティを変更できます。


1
イベントの追加後に他の誰かが友達として追加され、フィードでこのイベントを確認する必要があるとします。その後、これは機能しません
Joshua Kissoon、2012年

8

Railsに実装することに決めた場合、おそらく次のプラグインが役立つでしょう。

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

他に何もない場合は、データモデルと、プッシュおよびプルアクティビティ用に提供されるAPIの両方の観点から、実装を確認できます。


6

私はheymanのアプローチと同様のアプローチをとりました-特定のアクティビティストリームに表示されるすべてのデータを含む非正規化テーブル。活動が限られている小さなサイトでは問題なく機能します。

上記のように、サイトの拡大に​​伴い、スケーラビリティの問題に直面する可能性があります。個人的には、今のところスケーリングの問題は心配していません。後で心配します。

Facebookはスケーリングの優れた仕事をしているので、すばらしいコンテンツがたくさんあるので、エンジニアリングブログを読むことをお勧めします-> http://www.facebook.com/notes.php?id=9445547199

私は、上で述べた非正規化されたテーブルよりも優れたソリューションを検討してきました。これを達成するために私が見つけた別の方法は、特定のアクティビティストリームに含まれるすべてのコンテンツを単一の行に圧縮することです。アプリケーションで読み取ることができるXML、JSON、またはシリアル化された形式で保存できます。更新プロセスも簡単です。アクティビティが発生したら、新しいアクティビティをキューに入れ(おそらくAmazon SQSまたは他の何かを使用)、次にキューをポーリングして次のアイテムを探します。そのアイテムを取得して解析し、データベースに保存されている適切なフィードオブジェクトにそのコンテンツを配置します。

この方法の良い点は、一連のテーブルを取得するのではなく、特定のフィードが要求されたときに単一のデータベーステーブルを読み取るだけでよいことです。また、リストを更新するたびに最も古いアクティビティアイテムをポップアウトできるため、アクティビティの有限リストを維持できます。

お役に立てれば!:)


まさに私の考えです。おそらく今得た私の考えの検証が必要でした、乾杯!
Sohail 2016年

5

このようなアクティビティストリームについては、2つのレールキャストがあります。

これらのソリューションにはすべての要件が含まれているわけではありませんが、いくつかのアイデアが得られるはずです。


1
PublicActivityは優れており、問題のすべてのユースケースを処理できます。
DaveStephens 2013

3

Plurkのアプローチは興味深いと思います。タイムライン全体を、Google Financeの株価チャートによく似た形式で提供します。

ソーシャルネットワーキングネットワークがどのように機能するかを確認するには、Ningを検討する価値があります。開発者のページには、特に便利に見えます。


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の初期の作業から適応したもの)を実際に使用してエンジンを構築しました。

エンジンを自分でホストする場合、または特殊な機能が必要な場合、コアコードは実際には非営利目的のオープンソースであるため、ぜひご覧ください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.