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.