web-dev-qa-db-ja.com

ソーシャルネットワークでアクティビティストリームを実装する方法

私は自分のソーシャルネットワークを開発していますが、ウェブ上でユーザーのアクションのストリームの実装例を見つけていません...たとえば、各ユーザーのアクションをフィルターする方法は?アクションイベントを保存するには?アクションストリームとアクション自体に使用できるデータモデルとオブジェクトモデルはどれですか?

132
Nicolò Martini

要約:約100万人のアクティブユーザーと1億5000万人の保存されたアクティビティについては、単純にします。

  • 一意のアクティビティの保存にリレーショナルデータベースを使用します(アクティビティごとに1レコード/「発生したこと」)レコードをできるだけコンパクトにします。アクティビティIDによって、または時間制限のあるフレンドIDのセットを使用して、アクティビティのバッチをすばやく取得できるように構成します。
  • アクティビティレコードが作成されるたびにアクティビティIDをRedisに公開し、アクティビティを表示する必要がある友人/購読者であるすべてのユーザーの「アクティビティストリーム」リストにIDを追加します。

Redisにクエリを実行して、任意のユーザーのアクティビティストリームを取得し、必要に応じてdbから関連データを取得します。ユーザーが過去にさかのぼってブラウズする必要がある場合は、時間ごとにデータベースを照会するようにフォールバックします(これを提供する場合でも)


約1500万のアクティビティを処理するために、単純な古いMySQLテーブルを使用します。

次のようになります。

_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)を持つ本(type)に関連していることを教えてくれます

_(user_id, time)_にインデックスを付け、user_id IN (...friends...) AND time > some-cutoff-pointであるアクティビティをクエリします。 IDを捨てて、別のクラスター化インデックスを選択するのは良いアイデアかもしれません-私はそれを試していません。

かなり基本的なものですが、機能し、シンプルで、ニーズの変化に合わせて簡単に操作できます。また、MySQLを使用していない場合は、インデックスごとに改善できる可能性があります。


最新のアクティビティにすばやくアクセスするために、 Redis を試しました。 Redisはすべてのデータをメモリに保存するため、すべてのアクティビティをそこに置くことはできませんが、サイトでよくヒットするほとんどの画面に十分な量を保存できます。各ユーザーまたはそのようなものの最新の100。 Redisが混在している場合、次のように機能します。

  • MySQLアクティビティレコードを作成する
  • アクティビティを作成したユーザーの友人ごとに、RedisのアクティビティリストにIDをプッシュします。
  • 各リストを最後のXアイテムまでトリミングします

Redisは高速で、1つの接続でコマンドをパイプライン化する方法を提供します。そのため、アクティビティを1000人の友人にプッシュするのに数ミリ秒かかります。

私が話していることのより詳細な説明については、RedisのTwitterの例を参照してください。 http://redis.io/topics/Twitter-clone

2011年2月更新現時点では5000万のアクティブなアクティビティがあり、何も変更していません。これに似た何かをすることの良い点の1つは、コンパクトで小さな行を使用することです。私は、より多くのアクティビティとそれらのアクティビティのより多くのクエリを含むいくつかの変更を加えることを計画しています。私は他の分野でRedisを使用していますが、特定の種類の問題には本当にうまく機能します。

2014年7月更新毎月最大70万人のアクティブユーザーがいます。過去数年間、各ユーザーの最近の1000個のアクティビティIDを保存するためにRedisを使用しています(箇条書きのリストを参照)。通常、システムには約1億のアクティビティレコードがあり、それらはまだMySQLに格納されており、同じレイアウトです。これらのレコードにより、Redisのメモリが少なくなり、アクティビティデータのレコードとして機能します。ユーザーが何かを見つけるために時間をさかのぼってページを移動する必要がある場合に使用します。

これは賢い、または特に興味深い解決策ではありませんでしたが、私にはとても役立ちました。

233
casey

これは、mysqlを使用したアクティビティストリームの実装です。 Activity、ActivityFeed、Subscriberの3つのクラスがあります。

アクティビティはアクティビティエントリを表し、そのテーブルは次のようになります。

id
subject_id
object_id
type
verb
data
time

Subject_idはアクションを実行するオブジェクトのID、object_idアクションを受け取るオブジェクトのID。 typeverbはアクション自体を説明します(たとえば、ユーザーが記事にコメントを追加すると、それぞれ「コメント」と「作成」になります)、データには追加データが含まれます。結合を避けます(たとえば、サブジェクト名と姓、記事のタイトルとURL、コメント本文などを含めることができます)。

各アクティビティは1つ以上のActivityFeedに属し、次のようなテーブルで関連付けられます。

feed_name
activity_id

私のアプリケーションでは、ユーザーごとに1つのフィードと、アイテム(通常はブログ記事)ごとに1つのフィードがありますが、それらは何でも構いません。

通常、サブスクライバーはサイトのユーザーですが、オブジェクトモデル内の任意のオブジェクトにすることもできます(たとえば、作成者のfeed_actionに記事をサブスクライブできます)。

すべてのサブスクライバーは1つ以上のActivityFeedに属し、上記のように、これらはこの種類のリンクテーブルによって関連付けられます。

feed_name
subscriber_id
reason

ここのreasonフィールドは、購読者がフィードを購読した理由を説明しています。たとえば、ユーザーがブログ投稿をブックマークする場合、理由は「ブックマーク」です。これは、後でユーザーに通知するアクションをフィルタリングする際に役立ちます。

サブスクライバーのアクティビティを取得するには、3つのテーブルを単純に結合します。今のように見えるWHERE条件のおかげで、いくつかのアクティビティを選択しているため、結合は高速です-time > some hours。 Activityテーブルのデータフィールドのおかげで、他の結合を回避できます。

reasonフィールドの詳細説明。たとえば、ユーザーへの電子メール通知のアクションをフィルターし、ユーザーがブログ投稿をブックマークした場合(そして彼が「ブックマーク」の理由で投稿フィードを購読した場合)、ユーザーが受け取ることを望みませんそのアイテムに対するアクションに関する電子メール通知、彼が投稿にコメントする場合(そして、それが理由 'comment'で投稿フィードにサブスクライブする場合)、他のユーザーが同じ投稿にコメントを追加したときに通知されるようにします。 reasonフィールドは、ユーザーの通知設定とともに、この差別化に役立ちます(ActivityFilterクラスを介して実装しました)。

21
Nicolò Martini

現在、アクティビティストリームの形式は、多くの有名な人々によって開発されています。

http://activitystrea.ms/

基本的に、すべてのアクティビティには、アクター(アクティビティを実行する)、動詞(アクティビティのアクション)、オブジェクト(アクターが実行するオブジェクト)、およびターゲットがあります。

例:MaxがAdamのウォールへのリンクを投稿しました。

執筆時点で、JSONの仕様はバージョン1.0に達し、適用可能なアクティビティのパターンを示しています。

それらのフォーマットはすでにBBC、Gnip、Google Buzz Gowalla、IBM、MySpace、Opera、Socialcast、Superfeedr、TypePad、Windows Live、YIIDなどで採用されています。

14

大きなウェブサイトでの通知システムの動作に関する説明は、スタックオーバーフローの質問 ソーシャルネットワーキングウェブサイトは友人の更新をどのように計算しますか?Jeremy Wall '答え。彼はMessage Qeueの使用を提案し、それを実装する2つのオープンソースソフトウェアを示しています。

  1. RabbitMQ
  2. Apache QPid

質問もご覧ください ソーシャルアクティビティストリームを実装する最良の方法は何ですか?

13
Nicolò Martini

パフォーマンスと分散メッセージキューが絶対に必要です。しかし、それで終わりではありません。永続データとして保存するものと一時データなどとして保存するものについて決定する必要があります。

とにかく、高性能でスケーラブルなシステムを求めているなら、私の友人は本当に難しい仕事です。しかし、もちろん、一部の寛大なエンジニアがこれについての経験を共有しています。 LinkedInは最近、メッセージキューシステムKafkaをオープンソースにしました。その前に、FacebookはすでにScribeをオープンソースコミュニティに提供していました。 KafkaはScalaで記述されており、最初は実行に時間がかかりますが、いくつかの仮想サーバーでテストしました。本当に速いです。

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

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

1
Cagatay Kalan

独自のロールを作成する代わりに、APIを介して使用されるサードパーティのサービスを参照できます。 Collabinate( http://www.collabinate.com )と呼ばれるものを開始しました。これは、グラフデータベースのバックエンドと、大量のデータを高度に同時かつ高性能に処理するためのかなり洗練されたアルゴリズムを備えています。 FacebookやTwitterほどの機能はありませんが、アクティビティストリーム、ソーシャルフィード、またはマイクロブログ機能をアプリケーションに組み込む必要があるほとんどのユースケースでは十分です。

0
Mafuba