Jeden z naszych czytelników zgłosił bardzo ciekawy problem, który można streścić do następującego pytania – „Dlaczego nie działają mi polskie litery z zapytaniach z wykorzystaniem wildcardów ?„. Ten wpis postara się odpowiedzieć na to pytanie.
Definicja typu i pola
Nasz czytelnik posiada następujący typ danych opisanych w pliku schema.xml:
<fieldType name="c_string" class="solr.TextField"> <analyzer type="index"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory" /> <filter class="solr.ReversedWildcardFilterFactory" /> </analyzer> <analyzer type="query"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory" /> <filter class="solr.ReversedWildcardFilterFactory" /> </analyzer> </fieldType>
Do tego pole, które jest obsługiwane przez ten typ wygląda następująco:
<field name="word" type="c_string" indexed="true" stored="true" />
Dane
Do testów opisywanego problemu wykorzystywałem następujące dane:
<add> <doc> <field name="id">1</field> <field name="word">Zażółć gęślą jaźń</field> </doc> </add>
Definicja problemu
Problem został zdefiniowany następująco: „w polu word mam polskie znaki, ale gdy zrobię zapytanie z polskim znakiem, np. „word:*ą*” to nic mi nie znajdzie„.
O czym warto pamiętać korzystając z ReversedWildcardFilterFactory
Podczas korzystania z ReversedWildcardFilterFactory należy pamiętać, aby filter ten zdefiniować tylko dla analizy podczas indeksowania, a nie definiować go dla analizy zapytań. Zatem poprawiona definicja typu powinna wyglądać następująco:
<fieldType name="c_string" class="solr.TextField"> <analyzer type="index"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory" /> <filter class="solr.ReversedWildcardFilterFactory" /> </analyzer> <analyzer type="query"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory" /> </analyzer> </fieldType>
Czy teraz już działa ?
Zadając następujące zapytanie:
http://localhost:8983/solr/select?q=word:*ś*
dalej nie otrzymujemy żadnych wyników. Dlaczego ?
Solr i obsługa wildcardów
Odpowiedź na pytanie postawione powyżej, jest dość prosta – Solr nie analizuje zapytań w których występują wildcardy. Tak, oznacza to, że podczas indeksacji filtr ASCIIFoldingFilterFactory usuwa nam polskie znaki zamieniając je na ich odpowiedniki z tablic 127 znaków ASCII, jednak w trakcie zadawania zapytania to się nie dzieje, pomimo tego, że filtry są zdefiniowane prawidłowo. I dlatego nie dostajemy żadnych wyników wyszukiwania. Jednak w takim wypadku, powinniśmy dostać wyniki zapytania na następujące zapytanie:
http://localhost:8983/solr/select?q=word:*s*
I tak się dokładnie dzieje, na powyższe zapytanie dostajemy wyniki wyszukiwania, jakich oczekiwaliśmy.
Możliwe rozwiązania
Jeżeli ktoś zapytał by mnie jakie rozwiązanie bym zasugerował, odpowiedziałbym, że w tym momencie po stronie aplikacji usuwałbym polskie znaki z zapytań które mają w sobie wildcardy. Od wersji 1.5 Solr, ReversedWildcardFilterFactory będzie poprawnie obsługiwać znaki spoza podstawowej tablicy ASCII, tak więc nie będzie konieczności korzystania z ASCIIFoldingFilterFactory, a co za tym idzie, problem nie będzie występował