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

Mongoose - Cerca il testo in tre campi in base al punteggio o alla ponderazione

Un "indice di testo" e cerca è davvero probabilmente l'opzione migliore qui fintanto che stai cercando parole intere.

Aggiungere un indice di testo alla definizione dello schema è abbastanza semplice:

BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)

Ciò consente di eseguire ricerche semplici con ponderazione "impostata" nei campi:

Book.find({ "$text": { "$search": "Holiday School Year" } })
    .select({ "score": { "$meta": "textScore" } })
    .sort({ "score": { "$meta": "textScore" } })
    .exec(function(err,result) {

    }
);

Dove ogni termine abbinato sarà considerato rispetto al campo in cui è stato trovato che dà il maggior peso e il numero di occorrenze.

L'assegnazione dei pesi è allegata all'"indice", quindi la definizione viene fatta una sola volta e non può essere modificata. Un'altra limitazione è che in "ricerca testuale" non vengono considerate parole "parziali". Ad esempio "ci" non corrisponde a "Città" o "Cittadino" e per fare ciò avresti invece bisogno di un'espressione regolare.

Se avevi bisogno di maggiore flessibilità o in generale devi essere in grado di modificare dinamicamente la ponderazione dei risultati, allora hai bisogno di qualcosa come il framework di aggregazione o mapReduce.

Il framework di aggregazione tuttavia non può eseguire una "corrispondenza"logica operazione (può filtrare attraverso il $match operatore, ma non una corrispondenza "logica" ) di una "espressione regolare" ai tuoi termini. Puoi lavorare con parole singole e corrispondenze "esatte", se questo ti soddisfa.

Book.aggregate(
    [
        { "$match": {
            "$or": [
                { "name": /Holiday/ },
                { "description": /Holiday/ },
                { "body": /Holiday/ }
            ]
        }},
        { "$project": {
            "name": 1,
            "description": 1,
            "body": 1,
            "score": {
                "$add": [
                    { "$cond": [{ "$eq": [ "$name", "Holiday" ] },5,0 ] },
                    { "$cond": [{ "$eq": [ "$description", "Holiday" ] },2,0 ] },
                    { "$cond": [{ "$eq": [ "$body", "Holiday" ] },1,0 ] }
                ]
            }
        }},
        { "$sort": { "score": -1 } }
    ],
    function(err,results) {

    }
)

Poiché una pipeline di aggregazione utilizza una struttura di dati per eseguire query in cui è possibile modificare i parametri per il peso su ciascuna esecuzione in base a ciò di cui hai attualmente bisogno.

MapReduce condivide un principio simile, in cui puoi includere un "punteggio" calcolato in parte della chiave primaria emessa come elemento principale. MapReduce ordina naturalmente tutto l'input emesso da questa chiave come ottimizzazione per l'alimentazione a una funzione di riduzione. Tuttavia non è possibile ordinare o "limitare" ulteriormente tale risultato.

Queste sono generalmente le tue opzioni da considerare e decidere quale si adatta meglio al tuo caso.