web-dev-qa-db-ja.com

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

ソーシャルアクティビティストリームを実装する最良の方法であるあなたの意見を聞くことに興味があります(Facebookが最も有名な例です)。関連する問題/課題は次のとおりです。

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

..その他、特にFacebookのように高度に洗練されている場合は、たとえばFacebookがいくつかのアクティビティアイテムを1つに結合します(「ユーザーx、y、zがその写真にコメントしました」

そのようなシステム、データモデルなどを実装するための最も柔軟で効率的かつ強力なアプローチに関するパターン、論文などに関する考えや指針をいただければ幸いです。

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

264
mort

そのようなシステムを作成し、このアプローチを取りました。

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

  • serIdはアクティビティを生成したユーザーです
  • typeはアクティビティのタイプです(つまり、ブログ投稿の書き込み、写真の追加、ユーザーの写真へのコメント)
  • dataは、必要なものを入力できるアクティビティのメタデータを含むシリアル化されたオブジェクトです

これにより、検索、ルックアップが制限され、フィード、ユーザー、時間、アクティビティタイプで実行できますが、Facebookタイプのアクティビティフィードでは、これは実際には制限されません。また、テーブルの正しいインデックスを使用すると、ルックアップはfastになります。

この設計では、各タイプのイベントに必要なメタデータを決定する必要があります。たとえば、新しい写真のフィードアクティビティは次のようになります。

{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クラスを拡張するクラスがあります。データベースの複雑さを避けるために、イベントのグループ化もレンダリングコードに組み込まれます。

143
heyman

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

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

116
Mark Kennedy

アプローチをオープンソースにしました: 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のフィードのようなシステムをセットアップするのに役立ちます。始めるのはとても簡単です。

フィード設計の詳細については、Feedlyの基になっている記事のいくつかを読むことを強くお勧めします。

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

44
Thierry

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

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

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

19
Tim Howland

別のソフトウェアを使用する場合は、アクティビティストリーム(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/

上記のリンクには、スクリーンキャストとこのアプローチのベンチマークがあります(グラフが1秒あたり1万以上のストリームを取得できることを示しています)。

12
Rene Pickhardt
 //実際のイベントごとに1つのエントリ
 events {
 id、timestamp、type、data 
} 
 
 // oneイベントごと、そのイベントを含むフィードごとのエントリ
 events_feeds {
 event_id、feed_id 
} 

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

10
jedediah

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

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

ActorIdTypeId、およびObjectIdでは、Subject-Verb-Objectイベントをキャプチャ(および後でクエリ)できます。各アクションにより、複数のStreamEventインスタンスが作成される場合があります。

次に、StreamEventの各タイプのイベントのサブクラスを作成しました。 LoginEventPictureCommentEvent。これらの各サブクラスには、PictureIdThumbNailCommenTextなど(イベントに必要なものは何でも)実際にあるコンテキスト固有のプロパティがあります。 hashtable/StreamEventDetailテーブルにキー/値のペアとして保存されます。

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

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

集計フィード(Facebookホーム)はまだ実装していませんが、AggregateFeedフィールドを持つテーブルを作成すると思いますserIdStreamEventId =ある種の「うーん、この面白い」アルゴリズムに基づいて作成されます。

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

10
jammus

Railsに実装することに決めた場合は、おそらく次のプラグインが便利です。

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

それ以外の場合は、データモデルの観点と、アクティビティのプッシュおよびプルのために提供されるAPIの両方の観点から、実装を確認します。

8
Alderete

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

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

5

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

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

3
warren

アクティビティストリームを実装して複数のアプリケーションでソーシャルフィード、マイクロブログ、およびコラボレーション機能を有効にした後、基本機能は非常に一般的であり、APIを介して利用する外部サービスに変換できることに気付きました。本番アプリケーションにストリームを構築していて、固有のニーズや非常に複雑なニーズがない場合は、実績のあるサービスを利用するのが最善の方法です。リレーショナルデータベース上で独自のシンプルなソリューションを展開するよりも、実稼働アプリケーションにこれをお勧めします。

私の会社Collabinate( http://www.collabinate.com )はこの実現から生まれたものであり、それを達成するためにグラフデータベースの上にスケーラブルで高性能なアクティビティストリームエンジンを実装しました。実際に、Graphityアルゴリズムのバリエーション(ここでも回答を提供してくれた@RenePickhardtの初期の作業から適応)を使用してエンジンを構築しました。

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

2
Mafuba

数か月前にこれを解決しましたが、実装が基本的すぎると思います。
次のモデルを作成しました。

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
Rodrigo