W ostatnim czasie moją uwagę przykuła funkcjonalność opisania w zgłoszeniu SOLR-2272, czyli funkcjonalność SQL’owego JOIN zaimplementowanego w Solr. W dzisiejszym wpisie przyjrzymy się bliżej tej funkcjonalności.
Przygotowanie
Pierwszą rzeczą jaką musimy zrobić to pobranie kodu z głównej gałęzi (trunk) repozytorium SVN projektów Lucene/Solr i dodanie nałożenie na ten kod łatki załączonej do zgłoszenia SOLR-2272. Później kilka chwil na zbudowanie Solr i możemy przystępować do testów.
Struktura indeksu
Do celów testowych zdecydowałem się zdefiniować następującą strukturę indeksu:
<fields> <field name="id" type="string" indexed="true" stored="true" required="true" /> <field name="name" type="text" indexed="true" stored="true"/> <field name="color" type="string" indexed="true" stored="true"/> <field name="parent" type="string" indexed="true" stored="true"/> </fields>
Sama struktura jest raczej prosta. Pole id odpowiada za przechowywanie unikalnego identyfikatora dokumentu. Pole name odpowiada za nazwę dokumentu, color to kolor produktu, a pole parent to identyfikator rodzica.
Dane testowe
Plik z przykładowymi danymi wygląda następująco:
<add> <doc> <field name="id">1</field> <field name="name">First document</field> <field name="color">Red</field> </doc> <doc> <field name="id">2</field> <field name="name">Second document</field> <field name="color">Yellow</field> </doc> <doc> <field name="id">3</field> <field name="name">Third document</field> <field name="color">Red</field> <field name="parent">1</field> </doc> <doc> <field name="id">4</field> <field name="name">Fourth document</field> <field name="color">Yellow</field> <field name="parent">1</field> </doc> </add>
Przykład zapytania
Do krótkich testów jakie przeprowadziłem wybrałem dość prosty przypadek. W odpowiedzi na zapytanie chciałem dostać dokumenty, które są rodzicami dokumentów posiadających w polu color wartość Yellow. Nic nadzwyczajnego, przynajmniej w rozumieniu SQL. Aby wykonać takie zapytanie w standardowym Solr musielibyśmy wykonać przynajmniej dwa zapytania – pierwsze o dokumenty z odpowiednią wartością w polu, a następnie o dokumenty rodziców. A jak wygląda to w przypadku Solr 4.0 i łatki ze zgłoszenia SOLR-2272 ? Poniżej zapytanie:
http://localhost:8983/solr/select?q={!join from=parent to=id}color:Yellow
I odpowiedź Solr:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">1</int> <lst name="params"> <str name="q">{!join from=parent to=id}color:Yellow</str> </lst> </lst> <result name="response" numFound="1" start="0"> <doc> <str name="color">Red</str> <str name="id">1</str> <str name="name">First document</str> </doc> </result> </response>
Jak widać dostaliśmy wyniki takie, jakich się spodziewaliśmy. Jednak jak działa to zapytanie ? Jak widać na załączonym przykładzie oprócz standardowego pobrania dokumentów, które mają w polu jakąś wartość (color:Yellow) dochodzi dość specyficzna konstrukcja {!join from=parent to=id}. Fragment ten mówi Solr, aby pokazać nie dokumenty oryginalne, ale te, które mają wartość w polu id taką samą jak pole parent dokumentów spełniających wcześniejszy warunek.
Weryfikacja
Sprawdźmy, czy to działa. Najpierw pobierzmy dokumenty, które spełniają posiadają w polu color wartość Yellow.W tym celu zadajemy zapytanie:
http://localhost:8983/solr/select?q=color:Yellow
Odpowiedź Solr, była następująca:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">2</int> <lst name="params"> <str name="q">color:Yellow</str> </lst> </lst> <result name="response" numFound="2" start="0"> <doc> <str name="color">Yellow</str> <str name="id">2</str> <str name="name">Second document</str> </doc> <doc> <str name="color">Yellow</str> <str name="id">4</str> <str name="name">Fourth document</str> <str name="parent">1</str> </doc> </result> </response>
Mamy zatem jeden dokument, który posiada wartość w polu parent – wartość ta to 1. Dokument o id równym jeden jest następujacy:
<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">4</int> <lst name="params"> <str name="indent">true</str> <str name="q">id:1</str> </lst> </lst> <result name="response" numFound="1" start="0"> <doc> <str name="color">Red</str> <str name="id">1</str> <str name="name">First document</str> </doc> </result> </response>
Widać zatem, że zapytanie z JOIN’em zadziałało prawidłowo 😉
Kilka słów na koniec
Warto pamiętać, że w obecnej chwili funkcjonalność jest w fazie rozwojowej i może się zmieniać. Ważne jest jednak to, że w wersji 4.0 Solr będziemy mogli cieszyć się funkcjonalnością podobną do SQL’owego JOIN.