Wie verfolgen Sie Datensatzbeziehungen in NoSQL?

117

Ich versuche, das Äquivalent von Fremdschlüsseln und Indizes in NoSQL KVP- oder Dokumentdatenbanken herauszufinden. Da es keine zentralen Tabellen gibt (um Schlüssel hinzuzufügen, die eine Beziehung zwischen zwei Objekten markieren), bin ich wirklich ratlos darüber, wie Sie Daten auf eine Weise abrufen können, die für normale Webseiten nützlich wäre.

Angenommen, ich habe einen Benutzer, und dieser Benutzer hinterlässt auf der gesamten Website viele Kommentare. Der einzige Weg, den ich mir vorstellen kann, um die Kommentare dieser Benutzer zu verfolgen, ist:

  1. Betten Sie sie in das Benutzerobjekt ein (was ziemlich nutzlos erscheint).
  2. Erstellen und pflegen Sie einen user_id:commentsWert, der eine Liste der Schlüssel jedes Kommentars enthält [Kommentar: 34, Kommentar: 197 usw.], damit ich sie nach Bedarf abrufen kann.

Wenn Sie jedoch das zweite Beispiel nehmen, werden Sie bald auf eine Mauer stoßen, wenn Sie sie zum Verfolgen anderer Dinge wie eines Schlüssels namens "active_comments" verwenden, der möglicherweise 30 Millionen IDs enthält, was es eine TON kostet , jede Seite abzufragen, nur um einige aktuelle zu kennen aktive Kommentare. Es wäre auch sehr anfällig für Rennbedingungen, da viele Seiten versuchen könnten, es gleichzeitig zu aktualisieren.

Wie kann ich Beziehungen wie die folgenden in einer NoSQL-Datenbank verfolgen?

  • Alle Kommentare eines Benutzers
  • Alle aktiven Kommentare
  • Alle mit [Stichwort] getaggten Beiträge
  • Alle Studenten in einem Club - oder alle Clubs, in denen ein Student ist

Oder denke ich falsch darüber nach?

Xeoncross
quelle
In NoSQL-Datenbanken gibt es keine Möglichkeit, dies zu tun. Diese Frage ist eher verwandt mit der Frage, wie ich Beziehungen in C-Programmen verfolgen würde.
Steinmetall
3
Wow, dann denke ich, dass der Hype, dass NoSQL RDBMS ersetzt, unmöglich ist.
Xeoncross
11
Ja, NoSQL ist definitiv überzeichnet. Ich sage nicht, dass die neuen Technologien unter den richtigen Umständen nicht nützlich sind, aber es ist lächerlich zu glauben, dass sie das RDBMS ersetzen werden. Siehe en.wikipedia.org/wiki/Hype_cycle
Bill Karwin
1
Hätten Sie nicht einfach eine Sammlung von "Benutzern" und eine Sammlung von Kommentaren? Und dann jeder Kommentar nur als 'Autor'-Eigenschaft, deren Wert ein Verweis auf eine Benutzer-ID ist?
CodeFinity

Antworten:

186

Alle Antworten zum Speichern von Viele-zu-Viele-Assoziationen auf "NoSQL-Weise" beschränken sich auf dasselbe: das redundante Speichern von Daten.

In NoSQL entwerfen Sie Ihre Datenbank nicht basierend auf den Beziehungen zwischen Datenentitäten. Sie entwerfen Ihre Datenbank basierend auf den Abfragen, die Sie für sie ausführen. Verwenden Sie dieselben Kriterien, die Sie zum Denormalisieren einer relationalen Datenbank verwenden würden: Wenn es wichtiger ist, dass Daten zusammenhalten (denken Sie an Werte in einer durch Kommas getrennten Liste anstelle einer normalisierten Tabelle), tun Sie dies auf diese Weise.

Dies wird jedoch zwangsläufig für einen Abfragetyp (z. B. Kommentare eines Benutzers für einen bestimmten Artikel) auf Kosten anderer Abfragetypen (Kommentare für einen Artikel eines bestimmten Benutzers) optimiert. Wenn für Ihre Anwendung beide Abfragetypen gleichermaßen optimiert werden müssen, sollten Sie nicht denormalisieren. Ebenso sollten Sie keine NoSQL-Lösung verwenden, wenn Sie die Daten relational verwenden müssen.

Bei Denormalisierung und Redundanz besteht das Risiko, dass redundante Datensätze nicht mehr miteinander synchronisiert werden. Dies wird als Anomalie bezeichnet . Wenn Sie eine normalisierte relationale Datenbank verwenden, kann das RDBMS Anomalien verhindern. In einer denormalisierten Datenbank oder in NoSQL liegt es in Ihrer Verantwortung, Anwendungscode zu schreiben, um Anomalien zu vermeiden.

Man könnte meinen, dass es für eine NoSQL-Datenbank großartig wäre, die harte Arbeit zu leisten, um Anomalien für Sie zu verhindern. Es gibt ein Paradigma, das dies kann - das relationale Paradigma.

Bill Karwin
quelle
20
"Sie sollten keine NoSQL-Lösung verwenden, wenn Sie die Daten relational verwenden müssen." - Wie kommen andere, die NoSQL ausführen, damit durch? Wie können Sie möglicherweise alle Möglichkeiten kennen, wie Sie Daten abfragen, wenn Sie Ihre Anwendung zum ersten Mal entwerfen? Fox Beispiel, ich möchte möglicherweise aktuelle Kommentare, Kommentare von Benutzern, Kommentare von Tags, Kommentare für einen bestimmten Beitrag, Kommentare als Spam markiert, aktive Kommentare, Kommentare mit der höchsten Bewertung usw.
Xeoncross
14
Genau - es gibt kein "es funktioniert einfach", wie die Befürworter von NoSQL gerne behaupten. Entweder führen Sie im Vorfeld eine Reihe von Analysen für Ihre relationale Datenmodellierung durch, oder Sie führen im Vorfeld eine Reihe von Analysen für Ihre Abfragen mit höchster Priorität durch, oder Sie führen während des gesamten Projekts eine Reihe kostspieliger Umgestaltungen durch, während Sie herausfinden, welche Teile Ihres Entwurfs vorhanden sind habe im Vorfeld nicht genug Analyse bekommen.
Bill Karwin
1
Wie sollten wir Dinge aktualisieren, wenn wir Daten redundant speichern? Zum Beispiel ändert sich sein Name und er schrieb einige Kommentare. Sein Name wurde bereits in der Benutzersammlung geändert, aber wie kann man alle redundant gespeicherten Namen in der Kommentarsammlung ändern?
Mohammad Kermani
3
@ M98, Ah, du hast die Schwäche in dieser Strategie gefunden. Sie müssen alle Stellen kennen, die Sie aktualisieren müssen, und dann Code in Ihre Anwendung schreiben, um alle zu aktualisieren, wenn Sie eine aktualisieren. Viel Glück!
Bill Karwin
2
Das gleiche Problem besteht für eine denormalisierte relationale Datenbank.
Bill Karwin
5

Der CouchDB-Ansatz schlägt vor, in der Kartenphase die richtigen Klassen von Dingen auszugeben und diese in "Reduzieren" zusammenzufassen. Sie können also alle Kommentare zuordnen und 1für den angegebenen Benutzer ausgeben und später nur diejenigen ausdrucken. Es würde jedoch viel Festplattenspeicher erfordern, um dauerhafte Ansichten aller verfolgbaren Daten in couchDB zu erstellen. Übrigens haben sie auch diese Wiki-Seite über Beziehungen: http://wiki.apache.org/couchdb/EntityRelationship .

Riak hingegen hat ein Werkzeug, um Beziehungen aufzubauen. Es ist Link. Sie können die Adresse eines verknüpften Dokuments (hier Kommentar) in das Stammdokument (hier Benutzerdokument) eingeben. Es hat einen Trick. Wenn es verteilt wird, kann es an vielen Orten gleichzeitig geändert werden. Es wird Konflikte verursachen und infolgedessen einen riesigen Vektoruhrbaum: / ..nicht so schlecht, nicht so gut.

Riak hat noch einen weiteren "Mechanismus". Es verfügt über einen zweischichtigen Schlüsselnamenraum, den sogenannten Bucket and Key. Beispiel: Wenn wir Club A, B und C und StudentX, StudentY haben, können Sie die folgende Konvention beibehalten:

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

und um die Beziehung zu lesen, listen Sie einfach die Schlüssel in bestimmten Eimern auf. Was stimmt damit nicht? Es ist verdammt langsam. Das Auflisten von Eimern hatte für riak nie Priorität. Es wird immer besser. Übrigens. Sie verschwenden keinen Speicher, da dieses Beispiel {true}mit einem einzelnen vollständigen Profil von StudentX oder Y verknüpft werden kann (hier sind Konflikte nicht möglich).

Wie Sie es sehen NoSQL! = NoSQL. Sie müssen sich eine bestimmte Implementierung ansehen und diese selbst testen.

Erwähnt, bevor Column Stores gut für Beziehungen geeignet sind. Aber alles hängt von Ihren A- und C- und P-Anforderungen ab. Wenn Sie A nicht benötigen und weniger als Peta-Bytes haben, lassen Sie es einfach, fahren Sie mit MySql oder Postgres fort.

Viel Glück

user425720
quelle
1
Riak hat kürzlich Version 1.0 veröffentlicht, die Unterstützung für Sekundärindizes bei Verwendung des LevelDB-Backends hinzufügt. Sehr wertvolles Feature.
Jon L.
4
  1. user: userid: comment ist ein vernünftiger Ansatz - stellen Sie sich das als Äquivalent eines Spaltenindex in SQL vor, mit der zusätzlichen Anforderung, dass Sie nicht nach nicht indizierten Spalten abfragen können.

  2. Hier müssen Sie über Ihre Anforderungen nachdenken. Eine Liste mit 30 Millionen Elementen ist nicht unangemessen, weil sie langsam ist, sondern weil es unpraktisch ist, jemals etwas damit zu tun. Wenn Ihre eigentliche Anforderung darin besteht, einige aktuelle Kommentare anzuzeigen, ist es besser, eine sehr kurze Liste zu führen, die aktualisiert wird, wenn ein Kommentar hinzugefügt wird. Denken Sie daran, dass für NoSQL keine Normalisierungsanforderungen bestehen. Rennbedingungen sind ein Problem mit Listen in einem grundlegenden Schlüsselwertspeicher, aber im Allgemeinen unterstützt Ihre Plattform Listen ordnungsgemäß, Sie können etwas mit Sperren tun oder Sie kümmern sich nicht wirklich um fehlgeschlagene Updates.

  3. Wie bei Benutzerkommentaren - Erstellen Sie ein Index-Schlüsselwort: posts

  4. Mehr vom Gleichen - wahrscheinlich eine Liste von Clubs als Eigentum von Studenten und ein Index auf diesem Feld, um alle Mitglieder eines Clubs zu erhalten

Tom Clarkson
quelle
Also braucht im Grunde alles nur Listen? Es scheint, als ob es einen ausgefeilteren Ansatz geben sollte, als nur die ID-Zeichenfolgen manuell zu verfolgen. Zum einen kann man nur so weit gehen, bevor sie zu groß werden, um nützlich zu sein. Andererseits sind die wichtigsten Poster-Child-Projekte der NoSQL-Technologie (MongoDB, CouchDB, Membase usw.) allesamt neue Projekte. Vielleicht muss ich ihnen nur mehr Zeit geben, um einen besseren Weg zu finden, um Beziehungen zu verfolgen.
Xeoncross
Wenn Sie NoSQL (nicht relationale AKA-Datenspeicher) verwenden, müssen Sie aufhören, relational zu denken. Der verwendete Ansatz unterscheidet sich zwischen den Plattformen, aber die Grundidee, dass Sie Indizes verwalten müssen, ist ziemlich universell. Die von Ihnen angegebenen Beziehungsbeispiele werden in NoSQL auf zwei verschiedene Arten modelliert: 1) Speicher - Im Gegensatz zu SQL können Spalten mehrere / komplexe Werte haben, sodass das untergeordnete Objekt nur ein Teil des übergeordneten Objekts ist. 2) Suche - Ihre langen Listen sind tatsächlich eine Voraussetzung für die Suchbarkeit, was eine Indizierung bedeutet. Sie können eine einfache benutzerdefinierte Liste oder eine vollständigere Suchmaschine verwenden.
Tom Clarkson
2

Du hast

"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"]
}

Nun, in einer relationalen Datenbank wäre es normal, die Daten in einer Eins-zu-Viele-Beziehung zu normalisieren. Das ist das gleiche, was Sie auch in einer NoSQL-Datenbank tun würden. Indizieren Sie einfach die Felder, mit denen Sie die Informationen abrufen möchten.

Zum Beispiel sind die für Sie wichtigen Indizes

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

Wenn Sie NosDB (eine .NET-basierte NoSQL-Datenbank mit SQL-Unterstützung) verwenden, sind Ihre Abfragen wie folgt

 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'

Überprüfen Sie alle unterstützten Abfragetypen anhand ihres SQL-Spickzettel oder ihrer Dokumentation.

Basit Anwer
quelle