2013-01-07 5 views
5

Sto tentando di utilizzare un indice di copertura per implementare la ricerca del testo di derivazione sulla mia app che utilizza mongodb.Impossibile ottenere una query coperta per utilizzare l'indice solo in mongodb

Ho il seguente set di indice:

ensureIndex({st: 1, n: 1, _id: 1}); 

Ma quando ho eseguito spiegare() sulla mia domanda, non riesco mai a ottenere l'indexonly leggere vero, non importa quello che faccio.

db.merchants.find({st: "Blue"}, {n:1,_id:1}).explain() 
{ 
    "cursor" : "BtreeCursor st_1_n_1__id_1", 
    "nscanned" : 8, 
    "nscannedObjects" : 8, 
    "n" : 8, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
     "st" : [ 
      [ 
       "Blue", 
       "Blue" 
      ] 
     ], 
     "n" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ], 
     "_id" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    } 
} 

Ho già capito che l'ordinamento delle chiavi nell'indice importa in qualche modo. Per esempio se ho usato {_id, n: 1, st: 1} non stava usando questo indice affatto per eseguire la query. Ho anche letto da qualche parte che troppo pochi documenti potrebbero innescare comportamenti imprevedibili con explain() poiché più strategie sono ugualmente veloci. Ma in questo caso, vedo che sta usando l'indice giusto, ma non sta usando solo l'indice. Cosa sta succedendo?

Sto usando mongoid e mongo 2.0.8 Credo.

UPDATE:

passa ad utilizzare Mongoid v3.1.4 e v2.2 mongod

Ecco la query che mongod sta vedendo da mongoid: Lun 15 Lug 10:47:26 [conn14] RunQuery chiamato spl_development.merchants {$ query: {st: {$ regex: "cr", $ opzioni: "i"}}, $ explain: true} lun 15 lug 10:47:26 [conn14] query spl_development.merchants query: {$ query: {st: {$ regex: "cr", $ opzioni: "i"}}, $ spiega: true} ntoreturn: 0 keyUpdates: 0 lock (micros) r: 212 nreturned: 1 reslen: 393 0ms

Quindi la proiezione non viene inviata al mongod strato e lo gestisce solo nel livello dell'applicazione. Non è l'ideale!

Ciò è stato riconosciuto come un bug in mongoid e possono essere monitorati qui: https://github.com/mongoid/mongoid/issues/3142

risposta

8

Mi aspetto che la query non possa utilizzare un indice coperto perché si dispone di un campo con una matrice inclusa nell'indice. Questo è suggerito nella spiegazione con "isMultiKey" : true.

Come osservato nella documentazione (Create Indexes that Support Covered Queries):

MongoDB non è possibile utilizzare una query coperta se uno qualsiasi dei campi indicizzati in nessuno dei documenti della collezione include un array. Se un campo indicizzato è un array, l'indice diventa un indice multi-chiave e non può supportare una query coperta.

+0

Grazie Stennie, questo è esattamente giusto, 'st' è una matrice. Immagino che per implementare questo e garantire che sia una query coperta per la velocità, devo usare regex sul campo di testo, mentre la mia strategia precedente era che avevo diviso il testo in parole in una matrice. Speriamo che la lentezza della regex sarà compensata dal fatto che il risultato viene restituito dall'indice di memoria. –

+0

È possibile utilizzare le espressioni regolari per rendere questa una query coperta, ma per un indice efficiente utilizzare la regex dovrebbe essere root-root (ad esempio '/^Blue /') e maiuscole e minuscole. Controlla il valore 'nscanned' quando aggiungi la tua espressione regolare per vedere il numero di confronti dell'indice richiesti rispetto a' n' (il numero di risultati restituiti). È inoltre possibile rendere una query coperta separando gli array di parole chiave in più documenti con un singolo campo indicizzato. Vorrei confrontare i diversi approcci per vedere cosa funziona meglio per il tuo caso d'uso; un multitasto (ma un indice non coperto) può effettivamente andare bene :) – Stennie

+0

Si noti inoltre che è stata elaborata una funzionalità di ricerca del testo migliorata (arginamento, punteggio, corrispondenza frase, parole di arresto, ..) per MongoDB 2.4 (vedere [SERVER- 380] (https://jira.mongodb.org/browse/SERVER-380)). Dovresti essere in grado di testarlo nella prossima versione di sviluppo 2.3.2 (o build notturne se sei impaziente/curioso). Post di blog di qualcuno che sta provando a farlo: [Spiegazione di testo di MongoDB] (http://blog.codecentric.de/en/2013/01/text-search-mongodb-stemming/). – Stennie

1

non ero in grado di riprodurre il problema in 2.2.2, ma aggiungere .sort({n: 1, _id: 1}) nella catena. Dato che non stai ordinando, stai chiedendo i documenti in qualsiasi ordine da parte di mongo di find che desideri utilizzare, e se questo non corrisponde all'ordine nell'indice (ad esempio l'ordine $natural), deve comunque leggere i documenti.

db.merchants.find({st: "Blue"}, {n:1,_id:1}).sort({n: 1, _id: 1}).explain() 
+0

L'ordine nell'indice è irrilevante per la copertura della query. Per definizione, una query coperta è quella in cui i risultati possono essere restituiti utilizzando solo i campi indicizzati. – Stennie

+0

So cosa stai ottenendo, ma quando guardavo questo ho scoperto che se ho aggiunto '.sort ($ natural: 1})' alla catena ha causato la spiegazione di restituire 'indexOnly: false' nei casi dove altrimenti sarebbe vero. Indipendentemente da ciò, sono sicuro che la tua risposta è la vera ragione per cui anche tu! – JohnnyHK

+0

Se si aggiunge solo un ordinamento $ naturale, il Query Optimizer selezionerà probabilmente un 'BasicCursor' (scansione tabella) dato un piccolo numero di documenti da confrontare. Puoi usare un ['hint()'] (http://docs.mongodb.org/manual/reference/operator/hint/) per confermare che una query ordinata sarà ancora coperta se viene usato l'indice corretto: 'db .merchants.find ({st: "Blue"}, {n: 1, _id: 1}). hint ('st_1_n_1__id_1'). sort ({$ natural: 1}). explain() '. – Stennie