2013-01-07 10 views
5

Próbuję użyć indeksu pokrywającego do wdrożenia wyszukiwania tekstu w mojej aplikacji, która używa mongodb.Nie można uzyskać objętego kwerendy do używania indeksu tylko w mongodb

Mam następujący zestaw index:

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

Ale kiedy biegnę wyjaśniać() na moje pytanie, nigdy nie mogę dostać indexOnly czytać prawdziwe, bez względu na to, co robię.

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 
       } 
      ] 
     ] 
    } 
} 

Już się zorientowałem, że uporządkowanie kluczy w indeksie ma jakieś znaczenie. Na przykład, jeśli użyłem {_id, n: 1, st: 1}, to w ogóle nie używałem tego indeksu do wykonania zapytania. Czytałem również gdzieś, że zbyt mało dokumentów może wywołać nieprzewidywalne zachowanie za pomocą funkcji explain(), ponieważ wiele strategii jest równie szybkich. Ale w tym przypadku widzę, że używa on właściwego indeksu, ale nie używa tylko indeksu. Co się dzieje?

Używam mongoid i uważam, że mongo 2.0.8.

UPDATE:

przełączony do korzystania Mongoid v3.1.4 i mongod v2.2

Oto zapytanie, które mongod widzi od mongoid: Pon 15 lipca 10:47:26 [conn14] runQuery o nazwie spl_development.merchants {$ query: {st: {$ regex: "cr", $ options: "i"}}, $ explain: true} Pon. 15 lipca 10:47:26 [conn14] zapytanie o zapytanie spl_development.merchants: {$ query: {st: {$ regex: "cr", $ options: "i"}}, $ explain: true} ntoreturn: 0 keyApdates: 0 locks (micros) r: 212 wrócone: 1 reslen: 393 0ms

Więc projekcja nie jest wysyłana do mongody warstwa i tylko obsługuje ją w warstwie aplikacji. Nieidealny!

Zostało to uznane za błąd w mongoid i można śledzić tutaj: https://github.com/mongoid/mongoid/issues/3142

Odpowiedz

8

Oczekuję, że zapytanie nie będzie mogło korzystać z indeksu objętego usługą, ponieważ w indeksie znajduje się pole z tablicą. Jest to zalecane w wyjaśnieniu z "isMultiKey" : true.

Jak wskazano w dokumentacji (Create Indexes that Support Covered Queries):

MongoDB nie można wykorzystać zadaszony zapytanie, czy którykolwiek z indeksowanych pól w którymkolwiek z dokumentów znajdujących się w kolekcji zawiera tablicę. Jeśli indeksowane pole jest tablicą, indeks staje się indeksem wieloblokowym i nie obsługuje obsługiwanego zapytania.

+0

Dzięki Stennie, to dokładnie tak, "st" to tablica. Chyba zaimplementowałem to i upewniłem się, że jest to zakryte zapytanie o szybkość, muszę użyć wyrażenia regularnego w polu tekstowym, podczas gdy moja wcześniejsza strategia polegała na tym, że podzieliłem tekst na słowa w Tablicy. Mam nadzieję, że spowolnienie regex zostanie skompensowane przez fakt, że wynik jest zwracany z indeksu w pamięci. –

+0

Możesz użyć wyrażeń regularnych, aby uczynić to zadaszonego zapytania, ale dla efektywnego użycia indeksu, regex powinien być zrootowany (np. '/^Blue /') i rozróżniana jest wielkość liter. Sprawdź wartość 'nscanned' po dodaniu wyrażenia regularnego, aby zobaczyć liczbę wymaganych porównań indeksu względem' n' (liczba zwróconych wyników). Możesz również uczynić to zapytaniem objętym zakresem, oddzielając tablice słów kluczowych na wiele dokumentów za pomocą jednego pola indeksowego. Porównałbym różne podejścia, aby zobaczyć, co najlepiej sprawdza się w twoim przypadku użycia; wielostronicowy (ale nieobjęty indeks) może być w porządku :) – Stennie

+0

Należy również pamiętać, że ulepszona funkcja wyszukiwania tekstu (wynik, wynik, punktacja, dopasowanie fraz, słowa kończące, ..) jest opracowywana dla MongoDB 2.4 (patrz [SERVER- 380] (https://jira.mongodb.org/browse/SERVER-380)). Powinieneś być w stanie przetestować to w nadchodzącym wydaniu rozwojowym 2.3.2 (lub kompilacjach nocnych, jeśli jesteś niecierpliwy/ciekawy). Post na blogu od kogoś, kto wypróbowuje to: [MongoDB Text Search Explained] (http://blog.codecentric.de/en/2013/01/text-search-mongodb-stemming/). – Stennie

1

I nie był w stanie odtworzyć problem w 2.2.2, ale dodać .sort({n: 1, _id: 1}) do łańcucha. Ponieważ nie sortujesz, prosisz o dokumenty w każdym zamówionym mongorze, a jeśli to nie pasuje do kolejności w indeksie (np. $natural), wciąż musi czytać dokumenty.

+0

Kolejność w indeksie jest nieistotna dla tego, czy zapytanie jest objęte. Z definicji kwerenda zakodowana to taka, w której wyniki mogą być zwracane przy użyciu tylko indeksowanych pól. – Stennie

+0

Wiem, do czego zmierzasz, ale kiedy patrzyłem na to, znalazłem, że jeśli dodałem '.sort ($ natural: 1}) do łańcucha to spowodowało, że objaśnienie zwróci' indexOnly: false' w przypadkach gdzie byłoby inaczej. Niezależnie od tego, jestem pewien, że twoja odpowiedź jest prawdziwym powodem, dla którego otrzymasz +1! – JohnnyHK

+0

Jeśli po prostu dodasz sortowanie naturalne $, optymalizator zapytań prawdopodobnie wybierze 'BasicCursor' (skanowanie tabeli) z niewielką liczbą dokumentów do porównania. Możesz użyć ['hint()'] (http://docs.mongodb.org/manual/reference/operator/hint/), aby potwierdzić, że sortowane zapytanie będzie nadal objęte, jeśli użyty zostanie właściwy indeks: 'db .merchants.find ({st: "Blue"}, {n: 1, _id: 1}). hint ('st_1_n_1__id_1'). sort ({$ natural: 1}). explain() '. – Stennie