web-dev-qa-db-ja.com

NoSQLでレコード関係をどのように追跡しますか?

NoSQL KVPまたはDocumentデータベースの外部キーとインデックスに相当するものを見つけようとしています。 (2つのオブジェクト間の関係を示すキーを追加するための)ピボットテーブルがないため、通常のWebページに役立つ方法でデータを取得する方法については本当に困惑しています。

ユーザーがいるとします。このユーザーはサイト全体に多くのコメントを残しています。ユーザーのコメントを追跡する唯一の方法は、

  1. ユーザーオブジェクトに埋め込みます(まったく役に立たないようです)
  2. user_id:comments各コメントのキー[コメント:34、コメント:197など...]のリストを含む値。これにより、必要に応じてそれらを取得できます。

ただし、2番目の例では、「active_comments」と呼ばれる3,000万個のIDを含む可能性のあるキーを追跡するために使用するとすぐにレンガの壁にぶつかります最近のアクティブなコメントを知るためだけに各ページを照会します。また、多くのページが同時に更新しようとする可能性があるため、race-conditionsになりやすくなります。

NoSQLデータベースで次のような関係を追跡するにはどうすればよいですか?

  • ユーザーのすべてのコメント
  • すべてのアクティブなコメント
  • [キーワード]でタグ付けされたすべての投稿
  • クラブのすべての学生-または学生が所属するすべてのクラブ

またはこれについて間違って考えていますか?

109
Xeoncross

「NoSQLの方法」で多対多の関連付けを保存する方法に対するすべての答えは、同じものになります。データを冗長に保存します。

NoSQLでは、データエンティティ間の関係に基づいてデータベースを設計することはありません。データベースに対して実行するクエリに基づいてデータベースを設計します。リレーショナルデータベースの非正規化に使用するのと同じ基準を使用します:データが凝集(正規化されたテーブルの代わりにコンマ区切りリストの値を考える)することがより重要な場合は、そのようにします。

しかし、これは必然的に、あるタイプのクエリ(たとえば、特定の記事に対する任意のユーザーによるコメント)に対して最適化されますが、他のタイプのクエリ(特定のユーザーによる任意の記事に対するコメント)は犠牲になります。アプリケーションで両方のタイプのクエリを等しく最適化する必要がある場合は、非正規化しないでください。同様に、リレーショナルな方法でデータを使用する必要がある場合は、NoSQLソリューションを使用しないでください。

非正規化と冗長性には、冗長なデータセットが互いに同期しなくなるというリスクがあります。これはanomalyと呼ばれます。正規化されたリレーショナルデータベースを使用すると、RDBMSは異常を防ぐことができます。非正規化されたデータベースまたはNoSQLでは、異常を防ぐためにアプリケーションコードを記述するのはあなたの責任になります。

NoSQLデータベースが異常を防ぐためのハードワークを行うのは素晴らしいことだと思うかもしれません。これを行うことができるパラダイム、つまりリレーショナルパラダイムがあります。

160
Bill Karwin

CouchDBのアプローチでは、マップフェーズで適切なクラスのクラスを出力し、reduceにまとめることをお勧めします。したがって、すべてのコメントをマップして1指定されたユーザーに対して、後で1つだけを出力します。ただし、couchDBのすべての追跡可能なデータの永続的なビューを構築するには、大量のディスクストレージが必要になります。ところで、彼らは関係に関する次のwikiページも持っています: http://wiki.Apache.org/couchdb/EntityRelationship

一方、Riakには関係を構築するツールがあります。リンクです。リンクされたドキュメント(ここではコメント)のアドレスを「ルート」ドキュメント(ここではユーザードキュメント)に入力できます。トリックが1つあります。配布される場合、多くの場所で一度に変更される可能性があります。それは衝突を引き起こし、その結果、巨大なベクトルクロックツリー:/ ..それほど悪くない、それほど良くない。

リアックにはまた別の「メカニズム」があります。バケットとキーと呼ばれる2層のキー名前空間があります。したがって、学生の例では、クラブA、B、Cと学生StudentX、StudentYがある場合、次の規則を維持できます。

{ Key = {ClubA, StudentX}, Value = true }, 
{ Key = {ClubB, StudentX}, Value = true }, 
{ Key = {ClubA, StudentY}, Value = true }

また、関係を読み取るには、指定されたバケット内のキーをリストします。それのどこが悪いんだい?とても遅いです。 riakにとってバケットのリストは優先事項ではありませんでした。それはどんどん良くなっています。ところで。この例では{true}は、StudentXまたはYの単一の完全なプロファイルにリンクできます(ここでは競合は不可能です)。

ご覧のとおり、NoSQL!= NoSQLです。特定の実装を見て、自分でテストする必要があります。

列ストアがリレーションに適しているように見える前に言及します..それはすべてAとCとPのニーズに依存します;)Aを必要とせず、Petaバイトだけが残っている場合それは、MySqlまたはPostgresに進みましょう。

がんばろう

4
user425720
  1. user:userid:commentsは合理的なアプローチです。これは、SQLの列インデックスに相当するものと考えてください。インデックスのない列ではクエリできないという要件が追加されています。

  2. ここで、要件について考える必要があります。 3,000万個のアイテムを含むリストは、速度が遅いため不合理ではありませんが、リストを使用して何かを行うのは実用的ではありません。実際の要件が最近のコメントを表示することである場合、コメントが追加されるたびに更新される非常に短いリストを保持することをお勧めします。NoSQLには正規化要件がないことに注意してください。競合状態は、基本的なキーバリューストアのリストに関する問題ですが、一般に、プラットフォームがリストを適切にサポートしている、ロックを使用して何かを実行できる、または実際に更新の失敗を気にしません。

  3. ユーザーのコメントと同じ-インデックスキーワードを作成:投稿

  4. もっと同じ-おそらく学生の財産としてのクラブのリストと、クラブのすべてのメンバーを取得するためのその分野のインデックス

4
Tom Clarkson

あなたが持っている

"user": {
    "userid": "unique value",
    "category": "student",
    "metainfo": "yada yada yada",
    "clubs": ["archery", "kendo"]
}

"comments": {
    "commentid": "unique value",
    "pageid": "unique value",
    "post-time": "ISO Date",
    "userid": "OP id -> THIS IS IMPORTANT"
}

"page": {
    "pageid": "unique value",
    "post-time": "ISO Date",
    "op-id": "user id",
    "tag": ["abc", "zxcv", "qwer"]
}

リレーショナルデータベースでは、通常の1対多の関係は、データを正規化することです。これは、NoSQLデータベースでも同じことです。情報を取得するフィールドにインデックスを付けるだけです。

たとえば、あなたにとって重要なインデックスは

  • Comment.UserID
  • Comment.PageID
  • Comment.PostTime
  • Page.Tag []

NosDB(SQLをサポートする.NETベースのNoSQLデータベース) を使用している場合、クエリは次のようになります

 SELECT * FROM Comments WHERE userid = ‘That user’;

 SELECT * FROM Comments WHERE pageid = ‘That user’;

 SELECT * FROM Comments WHERE post-time > DateTime('2016, 1, 1');

 SELECT * FROM Page WHERE tag = 'kendo'

SQLチートシート またはドキュメントから、サポートされているすべてのクエリタイプを確認してください。

1
Basit Anwer