Solr i autocomplete (cz. 1)

Niemal każdy z nas widział jak wygląda funkcjonalność autocomplete, czyli podpowiadanie użytkownikowi wyrazów lub całych fraz wyszukiwania. Nic dziwnego więc, że także Solr udostępnia mechanizmy przy pomocy których możemy zbudować takie funkcjonalności. W dzisiejszym wpisie pokażę w jaki sposób można zbudować podpowiadanie przy pomocy facetingu.

Indeks

Załóżmy, że chcemy podpowiadać użytkownikowi nazwy produktów w sklepie internetowym. Załóżmy, że nasz indeks składa się z następujących pól:

<field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
<field name="name" type="text" indexed="true" stored="true" multiValued="false" />
<field name="description" type="text" indexed="true" stored="true" multiValued="false" />

A typ text zdefiniowany jest w następujący sposób:

<fieldType name="text" class="solr.TextField" positionIncrementGap="100"> 
 <analyzer>
  <tokenizer class="solr.WhitespaceTokenizerFactory"/>
  <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> 
  <filter class="solr.LowerCaseFilterFactory"/>
 </analyzer>
</fieldType>

Konfiguracja

Na początku należy zastanowić się co chcemy uzyskać. Czy chcemy aby podpowiadane były tylko poszczególne wyrazy składające się na frazy, czy może jednak pełne nazwy rozpoczynające się na podane przez użytkownika litery. W zależności od naszych wyborów musimy przygotować odpowiednie pole, na podstawie którego będziemy budować podpowiedzi.

Podpowiadanie pojedynczych wyrazów składających się na nazwę

W przypadku podpowiadania pojedynczych wyrazów powinniśmy podpowiadanie oprzeć o pole, które będzie odpowiednio tokenizowane. W naszym przypadku pole name będzie wystarczające. Należy jednak pamiętać, iż jeżeli chcemy korzystać np. ze stemmingu należałoby zdefiniować kolejny typ, który były go pozbawiony, ze względu na to jak taka analiza działa na zawartość pola.

Podpowiadanie pełnych nazw

W przypadku podpowiadania pełnych nazw produktów potrzebujemy innej konfiguracji pola na którym oprzemy podpowiadanie – najlepsze do tego będzie pole nietokenizowane. Nie możemy jednak wykorzystać do tego celu typu string – ze względu na to. W tym celu definiujemy pole następująco:

<field name="name_auto" type="text_auto" indexed="true" stored="true" multiValued="false" />

Typ ten został zdefiniowany w następujący sposób:

<fieldType name="text_auto" class="solr.TextField">
 <analyzer>
  <tokenizer class="solr.KeywordTokenizerFactory"/>
  <filter class="solr.LowerCaseFilterFactory"/>
 </analyzer>
</fieldType>

Aby nie było konieczności modyfikacji formatu danych dodajemy dodatkowo odpowiednią definicję kopiowania informacji:

<copyField source="name" dest="name_auto" />

Jak to wykorzystać ?

Mając już odpowiednio zaindeksowane dane możemy zacząć korzystanie z Solr. Aby skorzystać z tak przygotowanych danych skorzystać wystarczy dość proste zapytanie:

q=*:*&facet=true&facet.field=POLE&facet.mincount=1&facet.prefix=ZAPYTANIE_UŻYTKOWNIKA

Gdzie:

  • POLE – pole na jakiego podstawie mamy zamiar realizować podpowiadanie. W naszym przypadku name_auto.
  • ZAPYTANIE_UŻYTKOWNIKA – litery, które wpisał użytkownik.

Warto zauważyć parametr rows=0 dodany po to, aby widoczny był tylko wynik facetingu. Oczywiście nie jest to konieczność.

Na przykład:

fl=id,name&rows=0&q=*:*&facet=true&facet.field=name_auto&facet.mincount=1&facet.prefix=dys

Wynik powyższego zapytania mógłby wyglądać następująco:

<response>
 <lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
 </lst>
 <result name="response" numFound="4" start="0"/>
 <lst name="facet_counts">
  <lst name="facet_queries"/>
  <lst name="facet_fields">
   <lst name="name_auto">
    <int name="dysk twardy">1</int>
    <int name="dysk twardy samsung">1</int>
    <int name="dysk twardy seagate">1</int>
    <int name="dysk twardy toshiba">1</int>
   </lst>
  </lst>
  <lst name="facet_dates"/></lst>
</response>

Dodatkowe możliwości

Warto wspomnieć o dodatkowych możliwościach jakie niesie za sobą ta metoda.

Pierwsza z możliwości to pokazanie użytkownikowi dodatkowych informacji takich jak ilość wyników jaką dostanie użytkownik po wybraniu odpowiedniej podpowiedzi. Jeżeli chcemy pokazywać takie informacje będzie to na pewno ciekawa opcja.

Możliwość wyboru sortowania wyników facetingu, czyli standardowe wykorzystanie parametru facet.sort. W zależności od potrzeb możemy posortować wyniki po ilości dokumentów (domyślne zachowanie, wartość parametru ustawiamy na true) lub alfabetycznie (wartość parametru ustawiamy na false).

Możemy ograniczyć podpowiedzi, aby nie były generowane te, które mają mniejszą, niż określona ilość wyników. Aby skorzystać z tej możliwości należy przekazać w parametrze facet.mincount ilość dokumentów od jakiej mają być pokazywane wyniki.

I jak dla mnie największy plus tej metody – możliwość prostego pobierania podpowiedzi tylko tych, które pasują do zapytania użytkownika oraz dodatkowych parametrów, takich jak np. kategoria w której się znajduje. Na przykład chcemy pokazać podpowiedzi dla użytkownika, który znajduje się w dziale AGD naszego sklepu. Podejrzewamy, że w tej chwili nie będą go interesować produkty typu odtwarzacze DVD i dlatego dodajemy parametr fq=dział:agd (zakładając, że mamy taki dział). Po tak zmodyfikowanym zapytaniu, użytkownik nie dostanie podpowiedzi wygenerowanych z całego indeksu, a zawężone, do tego jaki dział przegląda.

Kilka słów na zakończenie

Jak wiele metod i ta ma swoje plusy i minusy. Plusem tego rozwiązania jest łatwość jego wykorzystania, brak dodatkowych komponentów oraz to, że wyniki podpowiedzi można w bardzo prosty sposób zawężać, aby były generowane tylko z tych dokumentów, które pasują do zapytania wpisanego przez użytkownika. Jako duży plus można zaliczyć pokazywanie ilości dokumentów, jakie dostanie użytkownik wybierając daną podpowiedź (oczywiście przy zachowaniu takich samych parametrów wyszukiwania). Do minusów należy na pewno konieczność posiadania dodatkowych typów i pól obsługujących podpowiedzi, wbrew pozorom dość ograniczone możliwości oraz obciążenie Solr powodowane przez mechanizm facetingu.

W następnym wpisie dotyczącym funkcjonalności autocomplete postaram się rozszerzyć temat i pokazać kolejne metody generowania podpowiedzi za pomocą Solr.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *