Autcomplete, cz. 4 (Ngram i faceting)

W poprzednich częściach przedstawiliśmy dwie metody tworzenia podpowiadania zapytań. Następnie jedną z nich rozbudowaliśmy o możliwość dodatkowego definiowania zwracanych informacji. W tym artykule wrócimy ponownie wykorzystamy faceting oraz ngram.

Wymagania

Przy tworzeniu listy podpowiedzi przyjęliśmy następujące założenia:

  1. Podpowiadana jest cała fraza a nie tylko pojedyncze słowo
  2. Podpowiadana fraza może wystąpić w indeksie wielokrotnie
  3. w wyniku chcemy znać liczbę wystąpień
  4. Częściej występujące frazy są podpowiadane w pierwszej kolejności
  5. Kolejność podawanych przez użytkownika słów nie musi odpowiadać kolejności występowania słów w podpowiadanej frazie

Rozwiązanie

Podany w pierwszej części sposób odpada ze względu na pierwsze założenie. Co prawda wyszukiwanie słów we frazie da się prosto osiągnąć zmieniając sposób analizy, jednak zwracane są pojedyncze słowa a nie cała fraza.

Rozwiązanie to zmodyfikowana wersja sposobu z facetingiem. Zamiast stosować wyszukiwanie wszystkich elementów i zawężanie wyników facetingu poprzez facet.prefix, możemy od razu wyszukać tylko te elementy, które mają fragment słowa wpisanego przez użytkownika. Ponieważ nie chcemy stosować zapytania prefiksowego ( „słowo*” ) ze względów wydajnościowych, na pomoc wezwiemy ngramy. Oznacza to zapisanie w indeksie wszystkich przedrostków słowa. Oczywistą wadą jest rozrost indeksu, ale w naszym przypadku jesteśmy w stanie z tym żyć 🙂

Schema.xml

Definiujemy więc dodatkowy typ:

  <fieldType name="text_autocomplete" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
      <tokenizer class="solr.WhitespaceTokenizerFactory"/>
      <filter class="solr.LowerCaseFilterFactory"/>
      <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="25" />
    </analyzer>
    <analyzer type="query">
      <tokenizer class="solr.WhitespaceTokenizerFactory"/>
      <filter class="solr.LowerCaseFilterFactory"/>
    </analyzer>
  </fieldType>

Oraz pola: to, którego wartość będziemy wyświetlać oraz te, służące do wyszukiwania:

<field name="tag_autocomplete" type="text_autocomplete" indexed="true" stored="true" omitNorms="true" omitTermFreqAndPositions="true"/>
<field name="tag" type="string" indexed="true" stored="true" />

Zostaje jeszcze odpowiedni copyField:

<copyField source="tag" dest="tag_autocomplete"/>

 Zapytanie

Po przeindeksowaniu możemy przystąpić do tworzenia zapytania:

  1. Zawężamy listę wyników do tych, które w polu tag_autocomplete mają poszukiwany fragment słowa: q=tag_autocomplete:(FRAZA)
  2. W przypadku wielu podanych przez użytkownika fragmentów słów istotne jest, by były one wyszukiwane wszystkie: q.op=AND
  3. Tak naprawdę wyniki nie są istotne, dane odczytamy z facetingu, więc informujemy solr, że nie potrzebujemy listy wyników: rows=0
  4. Potrzebujemy natomiast faceting: facet=true
  5. W dodatku to faceting po polu w którym przechowujemy oryginalną zawartość pola podpowiedzi: facet.field=tag
  6. Nie interesują nas tagi, które nie zostały znalezione: facet.mincount=1
  7. Interesuje nas 5 wyników: facet.limit=5

Ostateczne zapytanie:

?q=tag_autocomplete:(FRAZA)&q.op=AND&rows=0&facet=true&facet.field=tag&facet.mincount=1&facet.limit=5

Jeśli parametry, które są stałe umieścimy w handlerze, jako wartości domyślne, to zapytanie sprowadza się do:

?q=tag_autocomplete:(FRAZA)

Słowo na koniec

Podstawową zaletą tego rozwiązania w stosunku do rozwiązania opartego o faceting i facet.prefix jest możliwość używania innego pola do zwracania podpowiedzi. Dzięki temu przy podpowiadaniu pojedynczych słów możemy w wyniku wyświetlić całą zawartość pola „tag”.

This post is also available in: angielski

This entry was posted on poniedziałek, Maj 28th, 2012 at 07:36 and is filed under Autocomplete. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 komentarze to “Autcomplete, cz. 4 (Ngram i faceting)”

  1. pb Says:

    W filtrze od ngram’owania brakuje podanej klasy – powinno być:

  2. pb Says:

    wycięło mi najważniejsze, bo potraktowało jako tag html (trzeba dodać sobie otwarcie i zamknięcie taga) 😉 :

    filter class=”solr.EdgeNGramFilterFactory” minGramSize=”1″ maxGramSize=”25″

  3. gr0 Says:

    Dzięki, za zwrócenie uwagi – poprawione.