FieldCollapsing, czyli inaczej grupowanie wyników wyszukiwania – funkcjonalność nad którą developerzy Lucene/Solr pracowali już od dłuższego czasu trafiła właśnie do repozytorium projektu Solr. Postanowiłem się przyjrzeć, w jaki sposób działa ta funkcjonalność.
Na początek mała informacja, FieldCollapsing dostępny jest tylko w wersji 4.0, czyli w wersji rozwojowej kodu projektu Solr i raczej mało prawdopodobnym jest przeniesienie tej funkcjonalności do wersji 3.X.
FieldCollapsing, czyli co ?
Wyobraźmy sobie, iż nasz indeks zawiera informacje o firmach z różnych miast. Chcemy pokazać użytkownikowi po jednej (lub np. dwie, czy trzy) firmie z każdego miasta, oczywiście firmie spełniającej kryteria wyszukiwania. W jaki sposób tego dokonać – wykorzystać właśnie mechanizm FieldCollapsing. Pozwala on na grupowanie zwróconych w wyników wyszukiwania na podstawie zawartości pól. Wyniki wyszukiwania mogą być zgrupowane do pojedynczego dokumentu, bądź stałej ich ilości.
Parametry
Podobnie, jak w przypadku większości funkcjonalności dostępnych w Solr, tak samo zachowanie mechanizmu FieldCollapsing można konfigurować szeregiem parametrów, oto one:
- group – analogicznie do np. facetingu ustawienie tego parametru na wartość true włącza mechanizm FieldCollapsing. Wartość domyślna parametru to false.
- group.field – określenie na podstawie jakiego pola ma się odbywać grupowanie.
- group.func – określenie funkcji, na podstawie wyniku której będzie odbywać się grupowanie.
- group.limit – ilość wyników jaka ma być zwrócona w poszczególnych grupach. Domyślna wartość parametru to 1.
- group.sort – parametr określający w jaki sposób sortować dokumenty w ramach grup. Wartość domyślna, to wartość score desc.
Warto podkreślić, iż parametr rows przekazywany do zapytania będzie określał ilość grup jaka ma zostać zwrócona w wynikach wyszukiwania, a nie ilość pojedynczych dokumentów. Zmienia się także zachowanie parametru sort. Parametr ten będzie sortował grupy wyników, a nie poszczególne dokumenty. Grupy będą sortowane na podstawie zawartości pól pierwszych dokumentów tworzących grupy.
Wyniki wyszukiwania
Wyniki wyszukiwania różnią się od tych do których jesteśmy przyzwyczajeni. Są one pogrupowane według parametrów, które przekazaliśmy. Głównym elementem wyników wyszukiwania nie są już poszczególne dokumenty, a grupy dokumentów. Dopiero w ramach grup pokazywane są dokumenty (ich ilość definiuje parametr group.limit). Na przykład, zadając zapytanie:
http://localhost:8983/solr/select/?q=*:*&group=true&group.field=inStock&indent=true
do indeksu, który powstał poprzez zaindeksowanie wszystkich dokumentów w formacie XML z katalogu exampledocs przykładowego wdrożenia dostarczanego z Solr, otrzymujemy następujący wynik:
<?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="group.field">inStock</str> <str name="group">true</str> <str name="indent">true</str> <str name="q">*:*</str> </lst> </lst> <lst name="grouped"> <lst name="inStock"> <int name="matches">19</int> <arr name="groups"> <lst> <str name="groupValue">T</str> <result name="doclist" numFound="15" start="0"> <doc> <arr name="cat"><str>electronics</str><str>hard drive</str></arr> <arr name="features"><str>7200RPM, 8MB cache, IDE Ultra ATA-133</str><str>NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor</str></arr> <str name="id">SP2514N</str> <bool name="inStock">true</bool> <str name="manu">Samsung Electronics Co. Ltd.</str> <date name="manufacturedate_dt">2006-02-13T15:26:37Z</date> <str name="name">Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133</str> <int name="popularity">6</int> <float name="price">92.0</float> <str name="store">45.17614,-93.87341</str> <double name="store_0_d">45.17614</double> <double name="store_1_d">-93.87341</double> <str name="store_lat_lon">45.17614,-93.87341</str> </doc> </result> </lst> <lst> <str name="groupValue">F</str> <result name="doclist" numFound="4" start="0"> <doc> <arr name="cat"><str>electronics</str><str>connector</str></arr> <arr name="features"><str>car power adapter, white</str></arr> <str name="id">F8V7067-APL-KIT</str> <bool name="inStock">false</bool> <str name="manu">Belkin</str> <date name="manufacturedate_dt">2005-08-01T16:30:25Z</date> <str name="name">Belkin Mobile Power Cord for iPod w/ Dock</str> <int name="popularity">1</int> <float name="price">19.95</float> <str name="store">45.17614,-93.87341</str> <double name="store_0_d">45.17614</double> <double name="store_1_d">-93.87341</double> <str name="store_lat_lon">45.17614,-93.87341</str> <float name="weight">4.0</float> </doc> </result> </lst> </arr> </lst> </lst> </response>
Na koniec
Ciekawa funkcjonalność, która na pewno znajdzie zastosowania w niektórych wdrożeniach. Należy jednak pamiętać, iż funkcjonalność ta będzie jeszcze rozwijana. Jak na razie nie ma wsparcia m.in. dla wyszukiwania rozproszonego, czy grupowania po polach wielowartościowych. W tym momencie nie ma sensu przeprowadzanie też testów wydajnościowych, po pierwsze ze względu na zmiany jakie zajdą w samym mechanizmie, a po drugie ze względu na to, iż jest to mocno rozwojowa wersja Lucene i Solr. Niemniej jednak, na pewno będę miał opisywaną funkcjonalność na oku 😉