Come si tiene traccia delle relazioni tra i record in NoSQL?


117

Sto cercando di capire l'equivalente di chiavi e indici esterni in NoSQL KVP o database di documenti. Dal momento che non ci sono tabelle pivot (per aggiungere chiavi che contrassegnano una relazione tra due oggetti), sono davvero perplesso su come potresti recuperare i dati in un modo che sarebbe utile per le normali pagine web.

Diciamo che ho un utente e questo utente lascia molti commenti in tutto il sito. L'unico modo in cui riesco a pensare di tenere traccia dei commenti degli utenti è farlo

  1. Incorporali nell'oggetto utente (che sembra abbastanza inutile)
  2. Crea e mantieni un user_id:commentsvalore che contenga un elenco della chiave di ogni commento [commento: 34, commento: 197, ecc ...] in modo che io possa recuperarli secondo necessità.

Tuttavia, prendendo il secondo esempio ti imbatterai presto in un muro di mattoni quando lo usi per tracciare altre cose come una chiave chiamata "active_comments" che potrebbe contenere 30 milioni di ID al suo interno, il che costa una TONNELLATA interrogare ogni pagina solo per conoscerne alcuni recenti commenti attivi. Sarebbe anche molto soggetto a condizioni di gara poiché molte pagine potrebbero tentare di aggiornarlo contemporaneamente.

Come posso tenere traccia di relazioni come le seguenti in un database NoSQL?

  • Tutti i commenti di un utente
  • Tutti i commenti attivi
  • Tutti i post contrassegnati con [parola chiave]
  • Tutti gli studenti in un club o tutti i club in cui si trova uno studente

O sto pensando a questo in modo errato?


Non c'è un modo per farlo nei database NoSQL, questa domanda è piuttosto simile a chiedersi come dovrei tenere traccia delle relazioni nei programmi C.
pietraia

3
Wow, allora immagino che l'hype su NoSQL che sostituisce RDBMS sia impossibile.
Xeoncross

11
Sì, NoSQL è decisamente sopravvalutato. Non sto dicendo che le nuove tecnologie non siano utili nelle giuste circostanze, ma è ridicolo pensare che sostituiranno l'RDBMS. Vedi en.wikipedia.org/wiki/Hype_cycle
Bill Karwin il

1
Non avresti solo una raccolta di "utenti" e una raccolta di commenti. E poi, ogni commento proprio come una proprietà "autore" il cui valore è un riferimento a un ID utente?
CodeFinity

Risposte:


186

Tutte le risposte su come memorizzare associazioni molti-a-molti in "modo NoSQL" si riducono alla stessa cosa: memorizzare i dati in modo ridondante.

In NoSQL, non si progetta il database in base alle relazioni tra le entità di dati. Progetta il tuo database in base alle query che eseguirai su di esso. Usa gli stessi criteri che useresti per denormalizzare un database relazionale: se è più importante che i dati abbiano coesione (pensa ai valori in un elenco separato da virgole invece che in una tabella normalizzata), fallo in questo modo.

Ma questo inevitabilmente ottimizza per un tipo di query (ad esempio commenti di qualsiasi utente per un dato articolo) a scapito di altri tipi di query (commenti per qualsiasi articolo da un dato utente). Se l'applicazione richiede che entrambi i tipi di query siano ugualmente ottimizzati, non denormalizzare. Allo stesso modo, non dovresti usare una soluzione NoSQL se hai bisogno di usare i dati in modo relazionale.

Con la denormalizzazione e la ridondanza sussiste il rischio che insiemi di dati ridondanti non siano sincronizzati tra loro. Questa è chiamata anomalia . Quando si utilizza un database relazionale normalizzato, l'RDBMS può prevenire le anomalie. In un database denormalizzato o in NoSQL, diventa tua responsabilità scrivere il codice dell'applicazione per prevenire anomalie.

Si potrebbe pensare che sarebbe fantastico per un database NoSQL fare il duro lavoro di prevenire le anomalie per te. C'è un paradigma che può farlo: il paradigma relazionale.


20
"non dovresti usare una soluzione NoSQL se hai bisogno di usare i dati in modo relazionale" - Quindi come fanno gli altri che eseguono NoSQL a farla franca? Come puoi conoscere tutti i modi in cui interrogherai i dati quando progetti la tua applicazione per la prima volta? Ad esempio Fox, potrei volere commenti recenti, commenti per utente, commenti per tag, commenti per un determinato post, commenti contrassegnati come spam, commenti attivi, commenti con il punteggio più alto, ecc.
Xeoncross

14
Esatto: non esiste una cosa come "funziona e basta", come amano affermare i sostenitori di NoSQL. O fai una serie di analisi in anticipo per la modellazione dei dati relazionali, o fai una serie di analisi in anticipo per le tue query con priorità assoluta, oppure esegui un mucchio di refactoring costoso durante tutto il progetto mentre scopri quali parti del tuo progetto non ho ricevuto abbastanza analisi in anticipo.
Bill Karwin

1
Se archiviamo i dati in modo ridondante, come dovremmo aggiornare le cose? Ad esempio, cambia il suo nome e ha scritto alcuni commenti. Il suo nome è già cambiato nella raccolta utenti, ma come modificare tutti i nomi archiviati in modo ridondante nella raccolta dei commenti?
Mohammad Kermani

3
@ M98, Ah, hai trovato il punto debole di questa strategia. Devi conoscere tutti i posti che devi aggiornare, quindi scrivere codice nella tua applicazione per aggiornarli tutti quando ne aggiorni uno. In bocca al lupo!
Bill Karwin

2
Lo stesso problema esiste per un database relazionale denormalizzato .
Bill Karwin

5

L'approccio couchDB suggerisce di emettere classi appropriate di cose in fase di mappa e di riassumerle in riduzione. Quindi si possono mappare tutti i commenti ed emetterli 1per un dato utente e successivamente stampare solo quelli. Tuttavia, richiederebbe molto spazio su disco per creare visualizzazioni persistenti di tutti i dati tracciabili in couchDB. btw hanno anche questa pagina wiki sulle relazioni: http://wiki.apache.org/couchdb/EntityRelationship .

Riak d'altra parte ha uno strumento per costruire relazioni. È un collegamento. È possibile inserire l'indirizzo di un documento collegato (qui commento) al documento 'radice' (qui documento utente). Ha un trucco. Se è distribuito, può essere modificato contemporaneamente in molte posizioni. Causerà conflitti e di conseguenza un enorme albero di clock vettoriale: / ..non così male, non così buono.

Riak ha anche un altro "meccanismo". Ha uno spazio per i nomi delle chiavi a 2 livelli, i cosiddetti bucket e key. Quindi, ad esempio uno studente, se abbiamo il club A, B e C e lo studente StudentX, StudentY potresti mantenere la seguente convenzione:

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

e per leggere la relazione è sufficiente elencare le chiavi in ​​determinati bucket. Cosa c'è che non va? È dannatamente lento. L'elenco dei bucket non è mai stato prioritario per riak. Sta migliorando sempre di più. btw. non sprechi memoria perché questo esempio {true}può essere collegato al singolo profilo completo di StudentX o Y (qui i conflitti non sono possibili).

Come lo vedi NoSQL! = NoSQL. È necessario esaminare l'implementazione specifica e testarla di persona.

Menzionato prima che i negozi Column sembrano adatti alle relazioni .. ma tutto dipende dalle tue esigenze A e C e P;) Se non hai bisogno di A e hai meno di byte Peta, lascialo, vai avanti con MySql o Postgres.

in bocca al lupo


1
Riak ha recentemente rilasciato la v1.0, che aggiunge il supporto per gli indici secondari quando si utilizza il backend LevelDB. Caratteristica molto preziosa.
Jon L.

4
  1. user: userid: comments è un approccio ragionevole: pensalo come l'equivalente di un indice di colonna in SQL, con l'ulteriore requisito che non puoi eseguire query su colonne non indicizzate.

  2. Qui è dove devi pensare alle tue esigenze. Un elenco con 30 milioni di elementi non è irragionevole perché è lento, ma perché non è pratico farci qualcosa. Se la tua vera esigenza è quella di visualizzare alcuni commenti recenti, è meglio tenere un elenco molto breve che viene aggiornato ogni volta che viene aggiunto un commento: ricorda che NoSQL non ha requisiti di normalizzazione. Le condizioni di gara sono un problema con gli elenchi in un archivio di valori chiave di base, ma generalmente la tua piattaforma supporta gli elenchi correttamente, puoi fare qualcosa con i blocchi o in realtà non ti interessano gli aggiornamenti non riusciti.

  3. Come per i commenti degli utenti: crea una parola chiave di indice: post

  4. Più o meno lo stesso - probabilmente un elenco di club come proprietà degli studenti e un indice su quel campo per ottenere tutti i membri di un club


Quindi, in pratica, tutto ha solo bisogno di elenchi? Sembra che dovrebbe esserci un approccio più sofisticato rispetto al semplice tenere traccia delle stringhe di ID manualmente. Per uno, puoi solo andare così lontano prima che diventino troppo grandi per essere utili. Inoltre, i principali progetti poster-child della tecnologia NoSQL (MongoDB, CouchDB, Membase, ecc.) Sono tutti nuovi progetti, quindi forse ho solo bisogno di dare loro più tempo per trovare un modo migliore per tenere traccia delle relazioni.
Xeoncross

Se stai usando NoSQL (AKA non-relational data store) devi smettere di pensare in termini relazionali. L'approccio utilizzato differirà tra le piattaforme, ma l'idea di base che devi gestire gli indici è abbastanza universale. Gli esempi di relazione che hai fornito sono modellati in due modi diversi in NoSQL: 1) Archiviazione: a differenza di SQL, le colonne possono avere valori multipli / complessi, quindi l'oggetto figlio è solo una parte dell'oggetto padre. 2) Ricerca: i tuoi elenchi lunghi sono in realtà un requisito per la ricerca, il che significa indicizzazione: potresti utilizzare un semplice elenco personalizzato o un motore di ricerca più completo.
Tom Clarkson

2

Hai

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

Bene, in un database relazionale la cosa normale da fare sarebbe in una relazione uno-a-molti è normalizzare i dati. Questa è la stessa cosa che faresti anche in un database NoSQL. Indicizza semplicemente i campi con cui recupererai le informazioni.

Ad esempio, gli indici importanti per te sono

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

Se stai usando NosDB (un database NoSQL basato su .NET con supporto SQL) le tue domande saranno come

 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'

Controlla tutti i tipi di query supportati dal loro cheat sheet o documentazione SQL .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.