私は、Facebookがどのようにして友人<->ユーザー関係を設計したのかといつも思っていました。
ユーザーテーブルは次のようなものだと思います。
user_email PK
user_id PK
password
ユーザーデータ(性別、年齢など、想定されるユーザーの電子メールを介して接続されている)を含むテーブルを作成します。
すべての友達をこのユーザーにどのように接続しますか?
このようなもの?
user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N
おそらくない。ユーザー数が不明であり、拡大するためです。
UserIDを保持するfriendテーブルを保持し、次に友人のUserIDを保持します(FriendIDと呼びます)。両方の列は、Usersテーブルに戻る外部キーになります。
やや便利な例:
Table Name: User
Columns:
UserID PK
EmailAddress
Password
Gender
DOB
Location
TableName: Friends
Columns:
UserID PK FK
FriendID PK FK
(This table features a composite primary key made up of the two foreign
keys, both pointing back to the user table. One ID will point to the
logged in user, the other ID will point to the individual friend
of that user)
使用例:
Table User
--------------
UserID EmailAddress Password Gender DOB Location
------------------------------------------------------
1 [email protected] bobbie M 1/1/2009 New York City
2 [email protected] jonathan M 2/2/2008 Los Angeles
3 [email protected] joseph M 1/2/2007 Pittsburgh
Table Friends
---------------
UserID FriendID
----------------
1 2
1 3
2 3
これは、ボブがジョンとジョーの両方の友人であり、ジョンもジョーの友人であることを示します。この例では、友情は常に2つの方法であると仮定します。したがって、テーブル内に(2,1)や(3,2)などの行は必要ありません。友情や他の関係が明示的に双方向でない場合の例については、双方向の関係を示すためにそれらの行も必要です。
次のデータベーススキーマ Anatoly Lubarskyによって作成されたリバース をご覧ください。
TL; DR:
スタックのMySQLボトムより上にあるすべてのものに対して、キャッシュされたグラフを持つスタックアーキテクチャを使用します。
ロングアンサー:
膨大な量のデータをどのように処理し、迅速に検索するのか興味があったので、このことについて自分で調査しました。ユーザーベースが拡大すると、カスタムメイドのソーシャルネットワークスクリプトが遅くなることについて不満を言う人を見てきました。 ちょうど10kユーザーと250万人の友人でベンチマークを行った後接続-グループの許可やいいね、壁の投稿を気にすることさえしません-このアプローチには欠陥があることがすぐにわかりました。だから、私はそれを改善する方法についてウェブを検索するのにいくらか時間を費やし、この公式のFacebookの記事に出くわしました:
Ireally読み続ける前に、上記の最初のリンクのプレゼンテーションを見ることをお勧めします。これはおそらく、FBが背後でどのように機能するかについての最良の説明です。
ビデオと記事では、いくつかのことを説明しています。
これを見てみましょう。友達とのつながりは左上です。
まあ、これはグラフです。 :) SQLでビルドする方法はhowではありませんが、それを行う方法はいくつかありますが、 このサイト にはかなりの違いがありますアプローチ。 注意:リレーショナルDBがそれであると考えてください:グラフ構造ではなく、正規化されたデータを保存することを考えています。そのため、専用のグラフデータベースほど優れたパフォーマンスは得られません。
また、友人の友人よりも複雑なクエリを実行する必要があることも考慮してください。たとえば、あなたと友人の友人が好きな特定の座標の周りのすべての場所をフィルタリングする場合です。ここではグラフが完璧なソリューションです。
うまく機能するように構築する方法を説明することはできませんが、明らかに試行錯誤とベンチマークが必要です。
ここに私のがっかりしたjust友達の友達を見つけるためのテスト:
DBスキーマ:
CREATE TABLE IF NOT EXISTS `friends` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`friend_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
Friends of Friendsクエリ:
(
select friend_id
from friends
where user_id = 1
) union (
select distinct ff.friend_id
from
friends f
join friends ff on ff.user_id = f.friend_id
where f.user_id = 1
)
少なくとも1万人のユーザーレコードを持つサンプルデータを作成し、各レコードに少なくとも250人の友人の接続があるようにしてから、このクエリを実行することをお勧めします。私のマシン(i7 4770k、SSD、16GB RAM)では、そのクエリの結果は〜0.18秒でした。最適化できるかもしれませんが、私はDBの天才ではありません(提案を歓迎します)。ただし、ifこれは、すでに100,000人のユーザーに対して1.8秒、100万人のユーザーに対して18秒で線形にスケーリングします。
〜10万人のユーザーにとってはこれで問題ないように聞こえるかもしれませんが、友達の友達を取得したばかりで、「友達の友達からの投稿のみを表示し、それらのいくつかを見ることが許可されているか許可されていないか、サブクエリを実行して、それらのいずれかが好きかどうかを確認します)。すでに投稿が気に入ったかどうか、またはコードで行う必要がある場合、DBにチェックを行わせたいと思います。また、これがあなたが実行する唯一のクエリではなく、多かれ少なかれ人気のあるサイトで同時にアクティブなユーザーがいることを考慮してください。
私の答えは、Facebookが彼らの友人関係をどのように設計したかという質問に答えていると思いますが、それが迅速に機能する方法でそれを実装する方法を伝えることができないのは残念です。ソーシャルネットワークの実装は簡単ですが、それがうまく機能することを確認することは明らかにそうではありません-私見。
OrientDBを使用してグラフクエリを実行し、エッジを基になるSQL DBにマッピングし始めました。完了したら、それについての記事を書きます。
私の最善の策は、彼らが グラフ構造 を作成したことです。ノードはユーザーであり、「フレンドシップ」はエッジです。
1つのユーザーテーブルを保持し、別のエッジテーブルを保持します。その後、「友達になった日」や「承認済みのステータス」など、エッジに関するデータを保持できます。
ほとんどの場合、多対多の関係です。
FriendList(テーブル)
user_id -> users.user_id
friend_id -> users.user_id
friendVisibilityLevel
編集
ユーザーテーブルには、おそらくPKとしてuser_emailがなく、おそらく一意のキーとしてがあります。
ユーザー(表)
user_id PK
user_email
password
LinkedInとDiggの構築方法を説明している以下の記事をご覧ください。
「ビッグデータ:Facebookデータチームからの視点」も役立ちます。
また、非リレーショナルデータベースと、一部の企業によるそれらの使用方法について説明している次の記事があります。
http://www.readwriteweb.com/archives/is_the_relational_database_doomed.php
これらの企業は、データウェアハウス、パーティション化されたデータベース、データキャッシング、および私たちのほとんどが日常的に扱っていない他のより高いレベルの概念を扱っていることがわかります。または、少なくとも、私たちがそうすることを知らないかもしれません。
最初の2つの記事には、より多くの洞察を提供する多くのリンクがあります。
UPDATE 10/20/2014
Murat Demirbas に要約を書いた
http://muratbuffalo.blogspot.com/2014/10/facebooks-software-architecture.html
HTH
一定の時間に5億を超えるデータのユーザーフレンドデータのRDBMSからデータを取得することはできないため、Facebookはハッシュデータベース(SQLなし)を使用してこれを実装し、Cassandraというデータベースをオープンソース化しました。
したがって、すべてのユーザーが独自のキーと友人の詳細をキューに入れています。 cassandraがどのように機能するかを知るには、これを見てください:
この最近の2013年6月の投稿では、関係データベースから一部のデータ型の関連付けを持つオブジェクトへの移行について詳しく説明しています。
https://www.facebook.com/notes/facebook-engineering/tao-the-power-of-the-graph/1015152598399392
Https://www.usenix.org/conference/atc13/tao-facebook’s-distributed-data-store-social-graphに長い論文があります
外部キーを探しています。基本的に、独自のテーブルがない限り、データベースに配列を持つことはできません。
ユーザーテーブル userID PK その他のデータ フレンドテーブル userID-フレンドを持つユーザーを表すユーザーのテーブルへのFK。 friendID-友人のユーザーIDを表すユーザーテーブルへのFK
そのタイプのグラフデータベース: http://components.neo4j.org/neo4j-examples/1.2-SNAPSHOT/social-network.html
リレーショナルデータベースとは関係ありません。
グラフデータベース用のGoogle。
データベーステーブルは、水平方向(列数)ではなく、垂直方向(行数)に拡大するように設計されていることに注意してください。
おそらく、友人 '->ユーザーリレーション、たとえば "frnd_list"を格納するテーブルがあり、フィールド' user_id '、' frnd_id 'があります。
ユーザーが別のユーザーを友達として追加するたびに、2つの新しい行が作成されます。
たとえば、IDが 'deep9c'で、IDが 'akash3b'のユーザーを友達として追加すると、テーブル(frnd_list)に値( 'deep9c'、 'akash3b')および( 'akash3b)を持つ2つの新しい行が作成されます'、' deep9c ')。
特定のユーザーにフレンドリストを表示する場合、単純なsqlで次のようになります。
多対多テーブルのパフォーマンスに関して、ユーザーIDをリンクする32ビットintが2つある場合、平均200人の友人の200,000,000ユーザーの基本データストレージはそれぞれ300GB未満です。
明らかに、パーティション化とインデックス作成が必要になりますが、それをすべてのユーザーのメモリに保持するわけではありません。