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


117

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

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

  1. それらをユーザーオブジェクトに埋め込む(かなり役に立たないようです)
  2. user_id:comments各コメントのキーのリスト[コメント:34、コメント:197など...]を含む値を作成して維持し、必要に応じてそれらをフェッチできるようにします。

しかし、第二の例を取って、あなたはすぐに作るの3000万IDが含まれている場合があります「active_comments」と呼ばれるキーのような他のものを追跡するためにそれを使用するときにレンガの壁にヒットするTONの費用だけでいくつかの最近のを知って、各ページを照会しますアクティブなコメント。また、多くのページが同時に更新を試みる可能性があるため、競合状態が発生しやすくなります。

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

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

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


NoSQLデータベースでこれを行う方法は1つではありません。この質問は、Cプログラムで関係を追跡する方法を尋ねるのと同じようなものです。
ストーンメタル2010年

3
うわー、RDBMSを置き換えるNoSQLについての誇大宣伝は不可能だと思います。
Xeoncross、2010年

11
はい、NoSQLは間違いなく誇張されています。新しいテクノロジーが適切な状況で役に立たないと言っているわけではありませんが、それらがRDBMSに置き換わると考えるのはばかげています。en.wikipedia.org/wiki/Hype_cycleを
ビルカーウィン

1
「ユーザー」のコレクションとコメントのコレクションだけではないでしょうか。そして、各コメントは、値がユーザーIDへの参照である「author」プロパティと同じですか?
CodeFinity

回答:


186

多対多の関連付けを「NoSQLの方法」で格納する方法に対するすべての答えは、同じこと、つまりデータを冗長に格納することになります。

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

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

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

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


20
「リレーショナルな方法でデータを使用する必要がある場合は、NoSQLソリューションを使用しないでください」-では、NoSQLを実行している他の人はどうやってそれを回避できるのでしょうか。アプリケーションを最初に設計するときに、データを照会するすべての方法をどのようにして知ることができるでしょうか?フォックス例、私はなど、最近のコメント、ユーザーのコメント、タグのコメント、与えられたポストのコメント、スパムとしてマークされたコメントは、アクティブなコメント、最高の定格のコメントを、お勧めします
Xeoncross

14
正確に言えば、NoSQLの支持者が主張したいように、「機能するだけ」というものはありません。リレーショナルデータモデリングのために一連の分析を事前に実行するか、最優先のクエリのために一連の分析を事前に実行するか、または設計のどの部分を見つけたら、プロジェクト全体でコストのかかるリファクタリングを実行します。十分な分析を事前に得ることができませんでした。
ビルカーウィン2010年

1
データを重複して保存する場合、どのように更新する必要がありますか?例えば、彼の名前を変更し、彼はいくつかのコメントを書いた。彼の名前はすでにユーザーコレクションで変更されていますが、コメントコレクションに重複して保存されているすべての名前を変更するにはどうすればよいですか?
Mohammad Kermani

3
@ M98、ああ、あなたはこの戦略の弱点を見つけました。更新する必要のあるすべての場所について知っている必要があり、アプリケーションでコードを記述して、いずれか1つを更新するときにそれらすべてを更新する必要があります。幸運を!
ビルカーウィン2018年

2
非正規化されたリレーショナルデータベースにも同じ問題があります。
ビルカーウィン2018年

5

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

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

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のニーズによって異なります。

幸運を


1
Riakは最近v1.0をリリースしました。これは、LevelDBバックエンドを使用するときにセカンダリインデックスのサポートを追加します。非常に貴重な機能。
ジョンL.

4
  1. user:userid:commentsは合理的なアプローチです。これは、SQLの列インデックスと同等であり、インデックス付けされていない列に対してクエリを実行できないという要件が追加されたものと考えてください。

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

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

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


それで、基本的にすべてがリストを必要とするだけですか?IDの文字列を手動で追跡するだけではなく、より洗練されたアプローチがあるはずです。一つには、彼らが役に立つために大きくなる前に、あなたはこれまでしか行くことができません。繰り返しになりますが、NoSQLテクノロジーの主な子プロジェクト(MongoDB、CouchDB、Membaseなど)はすべて新しいプロジェクトであるため、関係を追跡するためのより良い方法を思いつくために、さらに時間をかける必要があります。
Xeoncross、

NoSQL(別名非リレーショナルデータストア)を使用している場合は、リレーショナル用語で考えるのをやめる必要があります。使用されるアプローチはプラットフォームによって異なりますが、インデックスを管理する必要があるという基本的な考え方はかなり普遍的です。指定したリレーションシップの例は、NoSQLで2つの異なる方法でモデル化されています。1)ストレージ-SQLとは異なり、列は複数/複雑な値を持つことができるため、子オブジェクトは親オブジェクトの一部にすぎません。2)検索-長いリストは実際には検索可能性の要件です。つまり、インデックス付けです。シンプルなカスタムリストまたはより完全な検索エンジンを使用できます。
トムクラークソン

2

あなたが持っている

"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チートシートまたはドキュメントから、サポートされているすべてのクエリタイプを確認してください。

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