Ricerca tipizzata su modello complesso. Possibile soluzione CQRS / NoSQL

5

Dato il seguente modello relazionale:

Devo implementare una ricerca digitata per gli hotel, che dovrebbe essere in grado di eseguire query su nome, città, paese, categoria, tipo di hotel, prezzo della camera, tipo di carattere personalizzato, tipo di camera e tipo di camera o qualsiasi combinazione di questi criteri.

Al momento sto facendo ciò nonostante Entity Framework, costruendo dinamicamente una query sull'entità Hotel (IQueryable). Questo va bene perché attualmente ci sono pochissimi dati. Tuttavia, questo non è molto scalabile e quando ci sono molti dati questo diventerà molto lento in quanto si tratta di una query su 10 tabelle. Nota che ho solo bisogno di caricare i dati dell'hotel, non l'intero grafico.

Sto pensando a modi per migliorare la scalabilità di questa parte. Ho esaminato le soluzioni CQRS e forse NoSQL.

Un approccio che avevo in mente è quello di avere questo modello sul lato scrittura (per rafforzare la coerenza) e avere un modello diverso sul lato di lettura. Su scrivere, vorrei quindi aggiornare il modello di lettura (viewmodel).

Tuttavia, poiché questo è già un modello più o meno complesso in termini di relazioni, vedo alcuni problemi con questo:

  • L'aggiornamento dei metadati (come categoria, tipo di camera, tipo di hotel) richiederebbe l'aggiornamento di tutti gli hotel o stanze del modello di lettura. Questo potrebbe essere piuttosto lento o impossibile una volta che ci sono molti dati.
  • Supponiamo che io usi un database di documenti come MongoDB e salvi un hotel con tutti gli elementi correlati denormalizzati, la query su quella tabella non sarà lenta in quanto deve cercare all'interno di ciascun documento, o è ancora abbastanza veloce in NoSQL?

Per riassumere alcune domande:

  • La denormalizzazione di questo modello è l'approccio giusto e quale sarebbe il modo migliore?
  • Will NoSQL sarà più veloce?
  • Esistono approcci migliori che posso seguire o modi per suddividere la relazione e appiattire la gerarchia, pur continuando a eseguire una ricerca digitata?
  • Idealmente alcuni campi dovrebbero anche supportare la ricerca fuzzy, quale sarebbe il modo migliore per farlo?
posta Kenneth 15.12.2013 - 13:52
fonte

4 risposte

3

Innanzitutto, se questo è il tuo schema attuale, sembra essere eccessivamente normalizzato.

  • Hotel_Category | Categorie
  • Hotel_HotelType | HotelTypes
  • Room_RoomType | RoomTypes
  • Hotel_Room | Camera

sono tutti i candidati per essere uniti dall'accoppiamento. Quindi invece di 8 tabelle avresti 4. Il doppio prefisso su alcune delle tue tabelle è un suggerimento che la normalizzazione è stata presa troppo lontano.

La normalizzazione pratica o pragmatica è sempre un atto di bilanciamento. In questo caso, penso che tu sia andato troppo oltre lungo il percorso di normalizzazione.

Avanti, prestazioni sul lato DB relazionale:

I need to implement a typed search for hotels, which should be able to query on name, city, country, category, hoteltype, roomprice, customtype, room custom type and roomtype or any combination of these criteria.

Ci scusiamo se questo sembra pedante, ma hai indici in atto per tutti questi elementi, giusto? Se lo sharding è la salsa segreta della scala web 1 , gli indici sono un primo passo fondamentale per assicurarsi che il tuo DB relazionale possa scalare.
1 La frase è da un video virale che parodia alcuni motivi nella selezione del database. Basta usare il termine, ma sappi che si tratta di un video NSFW.

Dopodiché, dobbiamo guardare i modelli di scrittura e amp; leggi i modelli.

Con un minimo di questo schema, penso che questo approccio sia eccessivo, specialmente se non desinidializza lo schema che hai fornito nella domanda. Seguire questa strada è solo aggiungere benzina a un fuoco già caldo: tutto ciò che avrai realizzato porterà la tua applicazione più velocemente a causa della complessità.

Questo non vuol dire che le viste di sola lettura non varrebbero la pena di considerare dopo di ridurre lo schema. Pensando ai modi in cui è probabile che le persone facciano domande per le stanze, puoi creare viste per posizione + nome, posizione + prezzo, posizione + tipo, ecc ...

Idealmente, avrai le metriche dall'uso esistente per determinare quali viste dovresti costruire. Ma sembra che tu capisca il dominio abbastanza bene da poter indovinare con ragionevolezza a quali iniziare.

Infine, considera un approccio noSQL. E c'è una ragione per cui l'ho presentato per ultimo.

Se non si tenta prima uno dei precedenti, l'implementazione noSQL avrà prestazioni significativamente peggiori rispetto alla soluzione DB relazionale esistente. La più grande sfida sarà il numero di join che hai nelle tue query. Anche se non è probabile che tu abbia molti join complessi, i sistemi noSQL funzionano meglio con pochi o nessun join nelle query.

Se riduci lo schema come suggerito nel primo segmento, allora potresti avere una discreta possibilità di migrare a noSQL. Probabilmente collocherei Hotel , Country , Room e Room_Type in una tabella. Ciò lascerebbe i join semplici da lì contro Hotel_Category e Hotel_Type , ma suppongo che quelle due tabelle vengano utilizzate meno spesso quando si trovano le stanze.

Oltre a ridurre lo schema, devi indicizzare gli elementi principali su cui desideri eseguire la ricerca. Forse ancor più dei DB relazionali, l'approccio noSQL si basa molto sull'indice predefinito per trovare rapidamente le informazioni necessarie.

Bootnotes:

Per quanto sarebbe più veloce (relazionale vs noSQL), davvero non lo so e non penso che nessuno possa saperlo finché non avrai speso un po 'di tempo per costruire e sintonizzare entrambi. Lavorare su uno non si applica all'altro, quindi devi raddoppiare i tuoi sforzi per rispondere veramente a quella parte della tua domanda. Se hai già investito sul lato relazionale, non vedo nulla di interessante nella tua domanda per passare a noSQL.

La ricerca fuzzy può essere una sfida indipendentemente dal tipo di database sottostante. La cosa migliore che puoi fare qui è guardare le opzioni fornite dalla piattaforma che scegli e iniziare a provare a implementare la ricerca fuzzy. Profilo che; continua a rivedere; e vedi dove ti portano le tue iterazioni.

    
risposta data 20.12.2013 - 20:30
fonte
1

Dai un'occhiata a Solr . Può fare tutto quello che vuoi e molto altro, fuori dalla scatola. Un possibile svantaggio è che devi trasferire i tuoi dati nel server ogni volta che hai un aggiornamento (o farlo in gruppi a intervalli specifici) ma poiché Solr supporta le importazioni delta, non dovrebbe essere un problema.

    
risposta data 20.12.2013 - 16:44
fonte
1

Se le tue query complesse si basano sempre su camere d'albergo, direi che è necessario per l'escalation è denormalizzare (o altrimenti costruire un indice).

Se denormalizzi su SQL, opterei per un approccio OLAP . Una semplice tabella indicizzata denormalizzata sembra essere sufficiente per eseguire l'escalation a milioni di righe.

NoSQL (cioè MongoDB) può anche essere usato per questo. Il principio di progettazione è simile a un approccio OLAP, ma supportato da un database NoSQL.

In ogni caso, suggerirei di utilizzare un tale back-end OLAP / denormalizzato solo per la parte di ricerca indicizzata, mantenendo la struttura SQL per la parte di elaborazione transazionale (esattamente come si menziona, usando un "read-model") .

Puoi usare un motore di ricerca come Solr (o Lucene nel tuo caso) come suggerito, che può forse essere visto anche come un modo di denormalizzare. Tendo a non gradire questo approccio quando non ho bisogno di ricerca fuzzy / basata sul punteggio / basata sul testo. A seconda del tipo di ricerca fuzzy di cui hai bisogno, puoi evitare Lucene e risolvere la ricerca fuzzy con una custom (cioè utilizzando algoritmi a distanza stringa). Come esempio concreto: prenderei in considerazione un motore di ricerca come Lucene se devo fare una ricerca fuzzy basata su "City" o altri campi di testo, ma forse con qualcosa di personalizzato basato sulla "distanza di Levenshtein" se ho solo bisogno fare semplici ricerche fuzzy su "Paese". Se, tuttavia, hai bisogno di una ricerca basata sui punteggi (come: alcuni attributi della stanza non sono molto importanti e non squalificano la stanza dall'essere elencati) quindi vai con un motore di ricerca come Lucene.

Infine, si noti che quando si esegue una query sul database, il numero di tabelle non rappresenta un grosso problema se si utilizzano colonne indicizzate per unire le tabelle e la loro cardinalità non è troppo grande (ovvero, una tabella "paese" può essere contenuta in memoria, e unirlo alla sua chiave primaria normalmente non ha impatto sulle prestazioni). Tali join sono molto comuni nei sistemi Relational-OLAP.

    
risposta data 20.12.2013 - 17:13
fonte
-2

Quello che ho fatto per query complesse su dataset di grandi dimensioni è questo:

  • Esegui una query semplice che include solo una o due tabelle
  • Troncare il numero di risultati a un importo ragionevole (500k?)
  • Esegui una query più complicata per restringere le opzioni in base ai record troncati

Questa è una soluzione scalabile al tuo problema. Dopo aver iniziato a unire molte tabelle con milioni di record, moltiplica le dimensioni della tabella temporanea utilizzata nel join. Troncando i risultati a un importo gestibile, le query continueranno a essere eseguite rapidamente e, nella maggior parte dei casi, otterrete il 100% dei risultati. Nel caso in cui il tuo troncare rimuova gli hotel validi, scoprirai che otterrai comunque decine di migliaia di risultati. È una questione di essere a posto con non ottenere una soluzione perfettamente completa al fine di ottenere risultati in modo tempestivo.

Per quanto riguarda la ricerca fuzzy, potresti parlare di implementazioni del Semantic Web. Questo è un compito difficile, ma i risultati raffinati potrebbero essere superiori a quelli di altri siti concorrenti. Dai un'occhiata a Gate per un'idea (è Java). In sostanza, genera annotazioni su blocchi di testo che ti permetteranno di effettuare ulteriori ricerche di termini. Una volta aggiunto stemming e un'ontologia completa all'annotator, diventa uno strumento di ricerca molto potente.

Non ho provato a passare a NoSQL. Trovo che i modelli relazionali abbiano più strumenti e più sviluppatori a loro agio. Appiattire e distribuire i dati non è sempre la scelta migliore, ma se si dispone di più di 10 sistemi che possono partecipare a un modello di dati distribuiti, è possibile che le ricerche vengano eseguite più rapidamente. Questo è solo se hai le risorse per farlo accadere. Sicuramente appiattendo il database con un singolo server in quanto l'origine dei dati sarebbe un errore.

Spero che questo aiuti!

    
risposta data 20.12.2013 - 15:58
fonte

Leggi altre domande sui tag