Jedną z funkcjonalności najnowszej wersji Solr (czyli 3.5) jest możliwość identyfikacji języka indekowanego dokumentu na etapie indeksowania. Dzisiejszy wpis postanowiłem poświęcić tej funkcjonalności i przyjrzeć się jak tym razem Apache Solr współgra z Apache Tika.
Na początek
Należy pamiętać, iż opisywana funkcjonalność została wprowadzona w Solr w wersji 3.5.
Założenia
Język będziemy wykrywać na postawie dwóch pól: title oraz body. Chcemy, aby wykryty język został zapisany w polu o nazwie lang.
Struktura naszego indeksu
Struktura indeksu jest oczywiście mocno uproszczona i zawiera jedynie pola potrzebne do testu. Sama definicja pól wygląda następująco:
<field name="id" type="string" indexed="true" stored="true" required="true" /> <field name="title" type="text_ws" indexed="true" stored="true" /> <field name="body" type="text_ws" indexed="true" stored="true" /> <field name="lang" type="string" indexed="true" stored="true" />
Wszystkie pola oznaczone są jako stored=”true”, aby zobaczyć wynik przetwarzania dokumentu przez procesor.
Konfiguracja update request processor’a
Aby móc wykorzystać funkcjonalność identyfikacji języka dokumentu konieczna jest konfiguacja następujących procesora aktualizacji. Skorzystamy z procesora opartego o Apache Tika (choć istnieje także druga implementacja oparta o http://code.google.com/p/language-detection/). W tym celu dodajemy następujący update request processor do pliku solrconfig.xml:
<updateRequestProcessorChain name="langid"> <processor name="langid" class="org.apache.solr.update.processor.TikaLanguageIdentifierUpdateProcessorFactory"> <lst name="defaults"> <str name="langid.fl">title,body</str> <str name="langid.langField">lang</str> </lst> </processor> <processor class="solr.LogUpdateProcessorFactory" /> <processor class="solr.RunUpdateProcessorFactory" /> </updateRequestProcessorChain>
Inne parametry TikaLanguageIdentifierUpdateProcessorFactory opisane są na wiki Apache Solr pod adresem: http://wiki.apache.org/solr/LanguageDetection.
Dodatkowe, potrzebne biblioteki
Aby powyższa zmiana zaczęła działać potrzebujemy jeszcze dodatkowych bibliotek, a dokładniej jednej biblioteki. Z katalogu dist, który znajduje się w dystrybucji Solr kopiujemy plik apache-solr-langid-3.5.0.jar do np. katalogu tikaDir, który tworzyny na tym samym poziomie co katalog webapps w Solr. Oraz dodajemy następującą linię do pliku solrconfig.xml:
<lib dir="../tikaLib/" regex="apache-solr-langid-\d.*\.jar" />
Następna biblioteka, której potrzebujemy to Tika wraz z przyległościami (tika-app-1.0.jar) dostępna np. pod adresem: http://tika.apache.org/. Po skopiowaniu do katalogu tikaDir dodajemy następujący wpis do pliku solrconfig.xml:
<lib dir="../tikaLib/" regex="tika-app-1.0.jar" />
Testowe dokumenty
Do testów przygotowałem trzy dokumenty zawierające po jednym dokumencie w języku angielskim, polskim oraz niemieckim. Ich treść została pobrana z Wikipedii. Wyglądają następująco:
tika_en.xml
<add> <doc> <field name="id">1</field> <field name="title">Water</field> <field name="body">Water is a chemical substance with the chemical formula H2O. A water molecule contains one oxygen and two hydrogen atoms connected by covalent bonds. Water is a liquid at ambient conditions, but it often co-exists on Earth with its solid state, ice, and gaseous state (water vapor or steam). Water also exists in a liquid crystal state near hydrophilic surfaces.[1][2] Under nomenclature used to name chemical compounds, Dihydrogen monoxide is the scientific name for water, though it is almost never used.</field> </doc> </add>
tika_pl.xml
<add> <doc> <field name="id">2</field> <field name="title">Woda</field> <field name="body">Woda (tlenek wodoru; nazwa systematyczna IUPAC: oksydan) – związek chemiczny o wzorze H2O, występujący w warunkach standardowych w stanie ciekłym. W stanie gazowym wodę określa się mianem pary wodnej, a w stałym stanie skupienia – lodem. Słowo woda jako nazwa związku chemicznego może się odnosić do każdego stanu skupienia.</field> </doc> </add>
tika_de.xml
<add> <doc> <field name="id">3</field> <field name="title">Wasser</field> <field name="body">Wasser (H2O) ist eine chemische Verbindung aus den Elementen Sauerstoff (O) und Wasserstoff (H). Wasser ist die einzige chemische Verbindung auf der Erde, die in der Natur in allen drei Aggregatzuständen vorkommt. Die Bezeichnung Wasser wird dabei besonders für den flüssigen Aggregatzustand verwendet. Im festen (gefrorenen) Zustand spricht man von Eis, im gasförmigen Zustand von Wasserdampf.</field> </doc> </add>
Testowanie działania
Aby zaindeksować dane wywołałem następującą serię poleceń:
curl 'http://localhost:8983/solr/update?update.chain=langid' --data-binary @tika_pl.xml -H 'Content-type:application/xml' curl 'http://localhost:8983/solr/update?update.chain=langid' --data-binary @tika_en.xml -H 'Content-type:application/xml' curl 'http://localhost:8983/solr/update?update.chain=langid' --data-binary @tika_de.xml -H 'Content-type:application/xml' curl 'http://localhost:8983/solr/update?update.chain=langid' --data-binary '<commit/>' -H 'Content-type:application/xml'
Warto zauważyć, dodatkowy parameter update.chain=langid dodawany do requestu. Określna on update processor jaki powinien zostać użyty do przetwarzania danych. W tym wypadku chcemy, aby był to nasz zdefiniowany update processor.
Zaindeksowane dane
Sprawdźmy zatem co zostało zaindeksowane. Zróbmy to poprzez wysłanie następującego zapytania: q=*:*&indent=true.
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">0</int> <lst name="params"> <str name="indent">true</str> <str name="q">*:*</str> </lst> </lst> <result name="response" numFound="3" start="0"> <doc> <str name="body">Woda (tlenek wodoru; nazwa systematyczna IUPAC: oksydan) – związek chemiczny o wzorze H2O, występujący w warunkach standardowych w stanie ciekłym. W stanie gazowym wodę określa się mianem pary wodnej, a w stałym stanie skupienia – lodem. Słowo woda jako nazwa związku chemicznego może się odnosić do każdego stanu skupienia.</str> <str name="id">2</str> <str name="lang">pl</str> <str name="title">Woda</str> </doc> <doc> <str name="body">Water is a chemical substance with the chemical formula H2O. A water molecule contains one oxygen and two hydrogen atoms connected by covalent bonds. Water is a liquid at ambient conditions, but it often co-exists on Earth with its solid state, ice, and gaseous state (water vapor or steam). Water also exists in a liquid crystal state near hydrophilic surfaces.[1][2] Under nomenclature used to name chemical compounds, Dihydrogen monoxide is the scientific name for water, though it is almost never used.</str> <str name="id">1</str> <str name="lang">en</str> <str name="title">Water</str> </doc> <doc> <str name="body">Wasser (H2O) ist eine chemische Verbindung aus den Elementen Sauerstoff (O) und Wasserstoff (H). Wasser ist die einzige chemische Verbindung auf der Erde, die in der Natur in allen drei Aggregatzuständen vorkommt. Die Bezeichnung Wasser wird dabei besonders für den flüssigen Aggregatzustand verwendet. Im festen (gefrorenen) Zustand spricht man von Eis, im gasförmigen Zustand von Wasserdampf.</str> <str name="id">3</str> <str name="lang">de</str> <str name="title">Wasser</str> </doc> </result> </response>
Jak widać, Solr przy pomocy biblioteki Tika, był w stanie poprawnie określić język trzech dokumentów jakie wysłaliśmy do indeksowania. Oczywiście, nie cieszmy się zbyt wcześnie, ponieważ pomyłki będą się zdarzać, szczególnie w przypadku, kiedy w ramach jednego dokumentu wykorzystywanych jest wiele języków.
Podsumowanie
Należy pamiętać, iż funkcjonalność detekcji języka dokumentu nie jest idealna i może się mylić. Dodatkowo, im dłuższe dokumenty, tym dokładniej będzie działać opisywana funkcjonalność. Oczywiście problemem jest to, że nie jesteśmy w stanie wykrywać języka podczas wyszukiwania, jednak nie jest to tylko problem Solr. Z tym możemy radzić sobie poprzez identyfikację przeglądarki użytkownika, języka w niej wykorzystywanej, bądź identyfikacji miejsca z którego łączy się do naszej aplikacji.