MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Ottimizzazione delle query MongoDB

Quello che vuoi è un risultato di "ricerca sfaccettata" in cui tieni le statistiche sui termini corrispondenti nel set di risultati corrente. Di conseguenza, mentre ci sono prodotti che "sembrano" fare tutto il lavoro in un'unica risposta, devi considerare che la maggior parte dei motori di archiviazione generici richiederà più operazioni.

Con MongoDB puoi utilizzare due query per ottenere i risultati stessi e un'altra per ottenere le informazioni sui facet. Ciò darebbe risultati simili ai risultati sfaccettati disponibili da prodotti di motori di ricerca dedicati come Solr o ElasticSearch.

Ma per farlo in modo efficace, vuoi includerlo nel tuo documento in modo che possa essere utilizzato in modo efficace. Un modulo molto efficace per ciò che desideri è utilizzare una matrice di dati tokenizzati:

 {
     "otherData": "something",
     "facets": [
         "country:UK",
         "city:London-UK",
         "genre:Student"
     ]
 }

Quindi "factets" è un singolo campo nel documento e non in più posizioni. Questo rende molto facile indicizzare e interrogare. Quindi puoi aggregare in modo efficace i tuoi risultati e ottenere i totali per ogni aspetto:

User.aggregate(
    [
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

O più idealmente con alcuni criteri in $match :

User.aggregate(
    [
        { "$match": { "facets": { "$in": ["genre:student"] } } },
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

Alla fine dando una risposta del tipo:

{ "_id": "country:FR", "count": 50 },
{ "_id": "country:UK", "count": 300 },
{ "_id": "city:London-UK", "count": 150 },
{ "_id": "genre:Student": "count": 500 }

Tale struttura è facile da attraversare e ispezionare per elementi come il "paese" discreto e la "città" che appartiene a un "paese" poiché i dati sono semplicemente separati in modo coerente da un trattino "-".

Cercare di combinare documenti all'interno di array è una cattiva idea. C'è anche un limite di dimensione BSON di 16 MB da rispettare, da cui il mashing insieme dei risultati (soprattutto se stai cercando di mantenere il contenuto del documento) finirà sicuramente per essere superato nella risposta.

Per qualcosa di semplice come ottenere il "conteggio complessivo" dei risultati da una tale query, somma semplicemente gli elementi di un particolare tipo di faccetta. Oppure invia i tuoi stessi argomenti di query a un .count() operazione:

User.count({ "facets": { "$in": ["genre:Student"] } },function(err,count) {

});

Come detto qui, in particolare quando si implementa il "paging" dei risultati, i ruoli per ottenere "Result Count", "Facet Count" e l'effettiva "Pagina dei risultati" sono tutti delegati a query "separate" al server.

Non c'è niente di sbagliato nell'inviare ciascuna di queste query al server in parallelo e quindi combinare una struttura da inviare al tuo modello o applicazione che assomiglia molto al risultato di ricerca sfaccettato di uno dei prodotti del motore di ricerca che offre questo tipo di risposta.

Concludere

Quindi inserisci qualcosa nel tuo documento per contrassegnare le sfaccettature in un unico posto. Un array di stringhe tokenizzate funziona bene per questo scopo. Funziona bene anche con moduli di query come $in e $all per le condizioni "or" o "e" sulle combinazioni di selezione di faccette.

Non cercare di schiacciare i risultati o nidificare le aggiunte solo per abbinare una struttura gerarchica percepita, ma piuttosto attraversare i risultati ricevuti e utilizzare schemi semplici nei token. È molto semplice

Esegui query paginate per il contenuto come query separate per facet o conteggi complessivi. Cercare di spingere tutti i contenuti negli array e quindi limitarli solo per ottenere conteggi non ha senso. Lo stesso si applicherebbe a una soluzione RDBMS per fare la stessa cosa, in cui i conteggi dei risultati di paging e la pagina corrente sono operazioni di query separate.

Ci sono ulteriori informazioni scritte sul blog di MongoDB sulla ricerca sfaccettata con MongoDB che spiega anche alcune altre opzioni. Sono inoltre disponibili articoli sull'integrazione con soluzioni di ricerca esterne utilizzando mongoconnector o altri approcci.