Come pensare alle query in NoSQL

3

Sto scrivendo un progetto per la scuola - App di tipo Tinder. Ho pensato di implementare il database interamente in RDBMS (PostgreSQL). Ma ora penso che sia una buona occasione per conoscere un po 'i sistemi NoSQL. Sono più vicino all'utilizzo di Redis (sembra veloce e amichevole), ma sto anche pensando a:

  • MongoDB (molto popolare)
  • ElasticSearch (sembra interessante, si dice che gestisca ricerche complesse)
  • Neo4j (solo perché mi piacciono i grafici)

Il problema è che non so come passare dalle query che conosco, all'utilizzo di NoSQL-way.

Cosa ho pensato di fare Per avere un database "core" in Postgres - sono le informazioni sull'utente in più tabelle, magari altre informazioni strutturate. La parte in NoSQL dovrebbe memorizzare la posizione dell'utente corrente e la sua reazione alla raccomandazione del partner.

Location memorizza gli ultimi dati di geolocalizzazione inviati dall'utente (aggiorna la posizione dell'utente o inserisce una nuova riga con posizione)

Suggestion memorizza la reazione dell'utente alla visualizzazione di un altro profilo utente

Quindi, per preparare i suggerimenti dei partner, la query SQL andrebbe così (assumiamo che la query richieda input_user , input_gender_preference e input_location come parametri di bind: è solo un prototipo).

SELECT l.userid
FROM location AS l
WHERE ST_distance(l.location, input_location) < 1000
AND l.gender = input_gender_preference
AND NOT EXISTS (SELECT 'x'
    FROM suggestion s
    WHERE (s.userid = l.userid
        AND s.suggested_userid = input_userid)
    OR (s.user_id = l.input_userid
        AND s.suggested_userid = l.userid
        AND s.approved = TRUE))

Ok, ma come farlo in uno dei sistemi che ho elencato?

Ad esempio

Dovrei:

  1. dividi suggestion in approved_by , rejected_by , voci duplicate nel valore-chiave inverso: user_approved , user_rejected
  2. ottieni un set di utenti visti dall'utente corrente, dall'unione di user_approved , user_rejected
  3. ottieni un set di utenti che hanno rifiutato il profilo utente corrente da rejected_by
  4. unisci i set sopra
  5. ottieni un set di utenti nelle vicinanze da location
  6. sottrarre (5) - (4)
  7. filtro (6) di gender

Sembra che crei un sacco di traffico non necessario.

Cosa ti chiederei

Ti chiedo punti di partenza - come gestire queste situazioni. Vorrei provare alcuni approcci non SQL alla gestione dei dati.

    
posta dreptak 01.11.2018 - 19:47
fonte

1 risposta

2

Non capisco il tuo modello di dati in un design sufficiente per darti un consiglio concreto, ma posso fornire alcuni suggerimenti su come combinare i database. L'utilizzo di più database è perfetto, perché puoi giocare ai loro punti di forza individuali. Eppure ci sono anche una serie di inconvenienti:

  • Combinando più database e altri strumenti, stai introducendo una maggiore complessità nel tuo sistema. Occuparsi di questo costa i tempi di sviluppo e rende il sistema più difficile da configurare: un altro database è un'altra cosa che può fallire.

  • Hai trasformato il tuo sistema in un sistema distribuito . I database potrebbero essere incoerenti tra loro, ad es. non è possibile avere relazioni a chiave esterna che si estendano su DB. La tua applicazione deve implementare in modo esplicito i requisiti di coerenza.

  • Poiché hai più database, il database non può più eseguire join. Invece, devi unire manualmente i dati nella tua applicazione. Questo di solito comporta il trasferimento di più dati di quanto altrimenti richiesto. Questo non è necessariamente un problema, ma rende il tuo lavoro più complicato: stai ri-implementando qualcosa che un database relazionale ti offre "gratuitamente".

  • Allo stesso modo, RDBMS ha un set di funzionalità fantastico e ben compreso. I database NoSQL solitamente rinunciano a alcune di queste funzionalità e garantiscono di ottenere qualcos'altro. È sempre un compromesso.

    es. menzioni MongoDB che è un database di documenti. Invece di tabelle, hai raccolte di documenti con dati in gran parte non strutturati. Ora non puoi avere relazioni tra documenti e i limiti del database che le modifiche verranno eseguite a livello transazionale.

    E si parla di Redis: Redis è molto veloce perché il set di dati completo viene sempre caricato nella RAM. La persistenza è facoltativa. A meno che tu non sappia cosa stai facendo, Redis non è adatto come archivio dati principale.

Nessuno di questi motivi significa che non dovresti aggiungere un componente NoSQL al tuo sistema, ma solo che dovresti considerare i costi prima di farlo.

Per memorizzare le posizioni, puoi fare con qualsiasi tipo di database purché permetta query spaziali efficienti, cioè basate sulla distanza. Nessuna classe di database supporta intrinsecamente questo, ma molti singoli database hanno estensioni GIS. Per esempio. Redis supporta le query spaziali, ma vedi la mia nota sulla persistenza sopra.

Se decidi di memorizzare le posizioni separatamente dagli altri dati utente, ad es. prima query per gli utenti in un raggio specifico dal database delle posizioni, caricare tale elenco nell'applicazione, quindi interrogare il secondo database per filtrare gli utenti su altri criteri.

candidates = []
for candidate_batch in batch(100, locationdb.find_nearby_users(user_id)):
  candidates.add_all(userdb.find_compatible(user_id, candidate_batch))

Per un progetto scolastico va bene, per un prodotto reale le query al secondo database potrebbero essere proibitive: non spostare i dati nel codice, ma il codice nei dati.

Memorizzare rifiuti / approvazioni suona separatamente mi sembra strano perché si tratta di dati molto relazionali, ma potrebbe essere fattibile. Ad esempio, è possibile prima interrogare il database principale per i candidati, quindi interrogare il database di rifiuto / approvazione per l'elenco completo di un utente di suggerimenti applicabili ed eseguire un join nella propria applicazione:

candidates = []
rejections = suggestiondb.find_rejections(user_id)
for candidate in userdb.find_compatible(user_id):
  if not rejections.contains(candidate):
    candidates.add(candidate)

Se uno di questi approcci è ragionevole è un gioco di numeri. Quanti dati produrranno ciascuna query secondaria? Quale frazione dei dati rimarrà alla fine? La tua applicazione dovrà trasferire ed elaborare tutti i risultati delle subquery, che per un'app di produzione potrebbero essere molte. Ancora una volta, questo non è un problema per un progetto studentesco, ma ad es. Stack Overflow ha avuto recentemente un'interruzione perché sono riusciti a saturare la connessione di rete tra i loro server web e il loro database. Non penso che stiano facendo dei join nel codice, hanno semplicemente molto traffico - tuttavia, qualsiasi tecnologia ha dei limiti.

    
risposta data 01.11.2018 - 21:34
fonte

Leggi altre domande sui tag