<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>4.0 &#8211; Solr.pl</title>
	<atom:link href="https://solr.pl/tag/4-0/feed/" rel="self" type="application/rss+xml" />
	<link>https://solr.pl</link>
	<description>All things to be found - Blog related to Apache Solr &#38; Lucene projects - https://solr.apache.org</description>
	<lastBuildDate>Wed, 11 Nov 2020 22:30:08 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>Solr 4.0: DirectSolrSpellChecker</title>
		<link>https://solr.pl/2012/04/30/solr-4-0-directsolrspellchecker/</link>
					<comments>https://solr.pl/2012/04/30/solr-4-0-directsolrspellchecker/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 30 Apr 2012 21:29:41 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[checker]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[spell]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=414</guid>

					<description><![CDATA[Jedną z nowości, która zostanie zaprezentowana w Solr 4.0, jest nowy rodzaj SpellChecker&#8217;a, który nie potrzebuje własnego indeksu. Postanowiłem przyjrzeć się jego konfiguracji i działaniu. Stan obecny W chwili obecnej (Solr 3.6) mamy do dyspozycji następujące implementacje SpellChecker&#8217;a: org.apache.solr.spelling.IndexBasedSpellChecker org.apache.solr.spelling.FileBasedSpellChecker]]></description>
										<content:encoded><![CDATA[<p>Jedną z nowości, która zostanie zaprezentowana w Solr 4.0, jest nowy rodzaj SpellChecker&#8217;a, który nie potrzebuje własnego indeksu. Postanowiłem przyjrzeć się jego konfiguracji i działaniu.</p>
<p><span id="more-414"></span></p>
<h3>Stan obecny</h3>
<p>W chwili obecnej (<a href="http://solr.pl/2012/04/12/apache-lucene-i-solr-3-6/" target="_blank" rel="noopener noreferrer">Solr 3.6</a>) mamy do dyspozycji następujące implementacje SpellChecker&#8217;a:</p>
<ul>
<li><em>org.apache.solr.spelling.IndexBasedSpellChecker</em></li>
<li><em>org.apache.solr.spelling.FileBasedSpellChecker</em></li>
</ul>
<p>Wraz z nadejściem Solr 4.0, dostaniemy dodatkowo nową implementację:</p>
<ul>
<li><em>org.apache.solr.spelling.DirectSolrSpellChecker</em></li>
</ul>
<h3>Obecne problemy</h3>
<p>W moim przypadku, jednym z głównych problemów <em>IndexBasedSpellChecker&#8217;a</em> była konieczność przebudowywania jego indeksu. Ze względu na to, że operacja mogła trwać długo, nie było możliwości przebudowywania tego indeksu po każdej operacji <em>commit</em>, co w niektórych wypadkach było znaczącym problemem. Oczywiście problem ten nie dotyczył <em>FileBasedSpellChecker&#8217;a</em>, jednak w moim wypadku pełnił rolę pomocniczego mechanizmu poprawiania błędów użytkowników.</p>
<h3>Konfiguracja</h3>
<p>Konfiguracja, jest analogiczna do tej do której przyzwyczaił nas Solr 3. Poniżej przykład:
</p>
<pre class="brush:xml">&lt;searchComponent name="spellcheck" class="solr.SpellCheckComponent"&gt;
  &lt;str name="queryAnalyzerFieldType"&gt;textTitle&lt;/str&gt;
  &lt;lst name="spellchecker"&gt;
    &lt;str name="name"&gt;default&lt;/str&gt;
    &lt;str name="field"&gt;title&lt;/str&gt;
    &lt;str name="classname"&gt;solr.DirectSolrSpellChecker&lt;/str&gt;
    &lt;str name="distanceMeasure"&gt;internal&lt;/str&gt;
    &lt;float name="accuracy"&gt;0.7&lt;/float&gt;
    &lt;int name="maxEdits"&gt;2&lt;/int&gt;
    &lt;int name="minPrefix"&gt;1&lt;/int&gt;
    &lt;int name="maxInspections"&gt;5&lt;/int&gt;
    &lt;int name="minQueryLength"&gt;4&lt;/int&gt;
    &lt;float name="maxQueryFrequency"&gt;0.01&lt;/float&gt;
    &lt;float name="thresholdTokenFrequency"&gt;.01&lt;/float&gt;
  &lt;/lst&gt;
&lt;/searchComponent&gt;</pre>
<p>Co oznaczają poszczególne parametry konfiguracyjne:</p>
<ul>
<li><em>queryAnalyzerFieldType</em> &#8211; nazwa typu na podstawie którego dokonywana będzie analiza zapytania zadanego do SpellChecker&#8217;a.</li>
<li><em>field</em> &#8211; pole, które będzie wykorzystywane do budowania podpowiedzi.</li>
<li><em>classname</em> &#8211; implementacja SpellChecker&#8217;a.</li>
<li><em>distanceMeasure</em> &#8211; algorytm określający odległość pomiędzy słowami, w tym wypadku domyślny, czyli wykorzystujący algorytm Levenshtein&#8217;a.</li>
<li><em>accuracy</em> &#8211; dokładność, jaka musi być osiągnięta, aby podpowiedź była uznana za poprawną.</li>
<li><em>maxEdits</em> &#8211; maksymalna ilość zmian podczas procesu wyliczania termów, możliwe wartości to <em>1</em> i <em>2</em>.</li>
<li><em>minPrefix</em> &#8211; minimalny wspólny przedrostek w podczas wyliczania termów.</li>
<li><em>maxInspections</em> &#8211; maksymalna liczba sprawdzeń dla każdej podpowiedzi.</li>
<li><em>minQueryLength</em> &#8211; minimalna wielkość słowa, aby te było brane pod uwagę jako podpowiedź.</li>
<li><em>maxQueryFrequency</em> &#8211; maksymalny procent dokumentów w jakich może wystąpić słowo, aby było uznane za kandydata do poprawienia (wartość <em>0.01</em> oznacza <em>1%</em>).</li>
<li><em>thresholdTokenFrequency</em> &#8211; minimalny procent dokumentów w jakich musi wystąpić podpowiedź, aby była uznana za poprawną (wartość <em>.01</em> oznacza <em>1%</em>).</li>
</ul>
<p>Powyższe atrybuty konfiguracji pokazują, iż <em>DirectSolrSpellChecker</em> daje nam dość duże pole jeżeli chodzi o konfigurację jego zachowania.</p>
<h3>Korzystanie</h3>
<p><em>DirectSolrSpellChecker</em> nie różni się w kwestii wykorzystania od swoich poprzedników. Tak samo jak w poprzednim wypadku możemy skonfigurować Solr, aby dodawał wyniki działania SpellCheckera do wyników wyszukiwania w każdym zapytaniu lub jako oddzielny handler wywoływany wtedy, kiedy nasza aplikacja uzna to za stosowne. O korzystaniu ze SpellChecker&#8217;a pisaliśmy już kiedyś w przykładowej aplikacji &#8222;<a href="http://solr.pl/2011/05/23/aplikacja-%E2%80%9Esprzedaz-samochodow%E2%80%9D-%E2%80%93-spellcheckcomponent-czy-naprawde-miales-to-na-mysli-cz-5/">Sprzedaż samochodów</a>&#8222;.</p>
<h3>Czego możemy oczekiwać ?</h3>
<p>Zgodnie z informacjami, jakie można znaleźć w zgłoszeniu <a href="https://issues.apache.org/jira/browse/LUCENE-2507">LUCENE-2507</a> <em>DirectSolrSpellChecker</em> uwalnia nas nie tylko od konieczności budowania indeksu SpellCheck&#8217;a, ale także niesie ze sobą szansę na poprawę działania tego mechanizmu. Z tego co widać, <em>DirectSolrSpellChecker</em> działa lepiej od dotychczas dostępnych implementacji kosztem spadku wydajności, którym moim zdaniem jest do zaakceptowania, przynajmniej jeżeli nie potrzebujemy podpowiedzi od SpellCheckera przy każdym zapytaniu.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2012/04/30/solr-4-0-directsolrspellchecker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Solr 4.0 i możliwości analizy języka polskiego</title>
		<link>https://solr.pl/2012/04/02/solr-4-0-i-mozliwosci-analizy-jezyka-polskiego/</link>
					<comments>https://solr.pl/2012/04/02/solr-4-0-i-mozliwosci-analizy-jezyka-polskiego/#comments</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 02 Apr 2012 21:27:23 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[analiza]]></category>
		<category><![CDATA[analyzer]]></category>
		<category><![CDATA[hunspell]]></category>
		<category><![CDATA[język]]></category>
		<category><![CDATA[lucene]]></category>
		<category><![CDATA[morfologik]]></category>
		<category><![CDATA[polish]]></category>
		<category><![CDATA[polski]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[solr 4.0]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=408</guid>

					<description><![CDATA[Ze względu na to, iż wsparcie dla języka polskiego w Lucene (i Solr) jest już od jakiegoś czasu, postanowiłem przyjrzeć się jak zmieni się to wraz z premierą Lucene i Solr w wersji 4.0. Dostępne opcje W obecnej chwili dostępne]]></description>
										<content:encoded><![CDATA[<p>Ze względu na to, iż wsparcie dla języka polskiego w Lucene (i Solr) jest już od jakiegoś czasu, postanowiłem przyjrzeć się jak zmieni się to wraz z premierą Lucene i Solr w wersji 4.0.</p>
<p><span id="more-408"></span></p>
<h3>Dostępne opcje</h3>
<p>W obecnej chwili dostępne są trzy opcje, jeżeli chodzi o analizę języka polskiego:</p>
<ul>
<li>Wykorzystanie możliwości&nbsp; biblioteki Stempel (od wersji 3.1 Solr)</li>
<li>Wykorzystanie&nbsp;możliwości biblioteki Hunspell i słownika języka polskiego (od wersji 3.5 Solr)</li>
<li>Wykorzystanie możliwości biblioteki Morfologik (od wersji 4.0 Solr, <a href="https://issues.apache.org/jira/browse/SOLR-3272" target="_blank" rel="noopener noreferrer">SOLR-3272</a>)</li>
</ul>
<h3>Konfiguracja</h3>
<p>Przyjrzyjmy się konfiguracji każdej z wyżej wymienionych funkcjonalności (należy pamiętać, że poniższe konfiguracje zostały oparte o Solr 4.0).</p>
<h4>Stempel</h4>
<p>W celu dodania stemmingu języka polskiego przy pomocy biblioteki Stempel, to proste dodanie filtra do definicji typu:
</p>
<pre class="brush:xml">&lt;filter class="solr.StempelPolishStemFilterFactory" /&gt;</pre>
<p>Oprócz tego, do <em>SOLR_HOME/lib</em> należy dodać bibliotekę <em>lucene-analyzers-stempel-4.0.jar</em> oraz <em>apache-solr-analysis-extras-4.0.jar</em>. <em></em> Dobrym pomysłem jest także użycie<em>&nbsp;solr.LowerCaseFilterFactory</em> przed Stemplem.</p>
<h4>Hunspell</h4>
<p>Podobnie, jak w powyższym przypadku, skorzystanie z Hunspell&#8217;a to dodanie filtra do definicji typu. Na przykład w taki sposób:
</p>
<pre class="brush:xml">&lt;filter class="solr.HunspellStemFilterFactory" dictionary="pl_PL.dic" affix="pl_PL.aff" ignoreCase="true" /&gt;</pre>
<p>Parametry <em>dictionary</em> oraz <em>affix</em> odpowiadają za definicję słownika z którego korzystamy. Natomiast parametr <em>ignoreCase</em> ustawiony na wartość <em>true</em> mówi filtrowi, aby nie zwracać uwagi na wielkość znaków. Słowniki można znaleźć m.in. pod adresem: <a href="http://wiki.services.openoffice.org/wiki/Dictionaries" target="_blank" rel="noopener noreferrer">http://wiki.services.openoffice.org/wiki/Dictionaries</a>.</p>
<h4>Morfologik</h4>
<p>Tak jak w wyżej wymienionych przypadkach, tak samo i tutaj, skorzystanie z Morfologika to dodanie filtra do definicji typu. Tym razem w następujący sposób:
</p>
<pre class="brush:xml">&lt;filter class="solr.MorfologikFilterFactory" dictionary="MORFOLOGIK" /&gt;</pre>
<p>Parametr <em>dictionary</em> to definicja z którego słownika chcemy skorzystać, do wyboru mamy:</p>
<ul>
<li>MORFOLOGIK</li>
<li>MORFEUSZ</li>
<li>COMBINED</li>
</ul>
<p>Oprócz tego, do <em>SOLR_HOME/lib</em> należy dodać bibliotekę <em>lucene-analyzers-morfologik-4.0.jar, </em><em>apache-solr-analysis-extras-4.0.jar, morfologik-fsa-1.5.2.jar</em>, <em>morfologik-polish-1.5.2.jar</em> oraz <em>morfologik-stemming-1.5.2.jar</em>.</p>
<h3>Porównanie działania</h3>
<p>Oczywiście nie byłem w stanie ocenić działania dla całego korpusu słów języka polskiego, dlatego wybrałem sobie cztery słowa, aby sprawdzić, jak zachowuje się każdy z wymienionych wyżej filtrów. Słowa te to: &#8222;<em>urodzić urodzony urodzona urodzeni&#8221;.</em> Wyniki przedstawiają się następująco:</p>
<h4>Stempel</h4>
<p>Wynikiem działania Stempla były następujące tokeny:
</p>
<pre>[urodzić] [urodzo] [urodzona] [urodzeni]</pre>
<p>Należy jednak pamiętać, iż Stempel to stemmer, a więc wyniki jego działania mogą i będą odbiegać od form podstawowych, czy też tematów słów. Ważne jest to, aby interesujące nas słowa sprowadzane były do tej samej formy, co umożliwi znalezienie odpowiedniego słowa przez Lucene/Solr. Pamiętając jednak o tym, widać iż wyniki nie są zadowalające, przynajmniej dla mnie. Na przykład zadając zapytanie <em>urodzić</em>, nie znaleźlibyśmy dokumentów ze słowami <em>urodzona</em>, czy <em>urodzony</em>. Dodatkowo widać, iż Stempel wyprodukował po jednym tokenie dla każdego ze słów.</p>
<h4>Hunspell</h4>
<p>Wynikiem działania Hunspell&#8217;a były następujące tokeny:
</p>
<pre>[urodzić, urodzić] [urodzony, urodzić] [urodzić] [urodzić, urodzony, urodzenie]</pre>
<p>Porównując wyniki uzyskane z pomocą Hunspell&#8217;a do tych uzyskanych z pomocą Stempla widać różnicę. Nasze przykładowe zapytanie o słowo <em>urodzić</em>, znalazłoby zarówno dokumenty ze słowem <em>urodzony</em>, jak również ze słowem <em>urodzona</em>, czy <em>urodzeni</em>. Całkiem miło. Dodatkowo widać, iż na trzy z czterech słów wejściowych Hunspell wygenerował więcej, niż jeden token (oczywiście umieszczając je na odpowiednich pozycjach w strumieniu tokenów). Wynik działania Hunspell&#8217;a mnie satysfakcjonuje, natomiast spójrzmy jeszcze na działanie najnowszego filtra dostępnego w Lucene i Solr pozwalającego na analizę języka polskiego, czyli na Morfologika.</p>
<h4>Morfologik</h4>
<p>Wynikiem działania Morfologika były następujące tokeny:
</p>
<pre>[urodzić] [urodzony, urodzić] [urodzić] [urodzić, urodzony]</pre>
<p>Porównując wyniki uzyskane za pomocą Morfologika do tych uzyskanych za pomocą Hunspell&#8217;a ciężko zauważyć różnicę (oczywiście w tym wypadku). Jedyną różnicą pomiędzy Hunspell&#8217;em, a Morfologikiem jest ostatni term dla słowa <em>urodzeni</em>, czyli <em>urodzenie</em>, którego nie otrzymaliśmy w wyniku działania Morfologika. Moim zdaniem wynik działania Morfologika, podobnie jak w przypadku Hunspell&#8217;a można uznać za satysfakcjonujący.</p>
<h3>Wydajność</h3>
<p>Test wydajności został zrobiony bardzo prosto &#8211; każdorazowo zostało zaindeksowanych 5 milionów dokumentów, gdzie wszystkie pola tekstowe były oparte o analizę języka polskiego z odpowiednim filtrem (do tego kilka standardowych filtrów, jak usuwanie stopwordów, synonimy, itp). Za każdym razem indeksowanie rozpoczynane było od nowa na nowej instancji Solr 4.0. Ze względu na korzystanie z Data Import Handlera polecenie commit wysyłane było co 100.000 dokumentów. Indeks składał się z kilkunastu pól, jednak sama struktura nie jest ważna ze względu na to, że zamierzałem zobaczyć, jak wygląda porównanie poszczególnych filtrów. Poniżej wyniki testu:</p>
[table “20” not found /]<br />

<p><strong>Uwaga<em>:</em></strong> W chwili pisania niniejszego tekstu, zgodnie ze zgłoszeniem <a href="https://issues.apache.org/jira/browse/SOLR-3245">SOLR-3245</a> istnieje problem z wydajnością Hunspella z polskimi słownikami w Solr 4.0. Najprawdopodobniej, sytuacja ta zostanie rozwiązana do czasu wypuszczenia wersji 4.0 Solr, jednak jeżeli zastanawiacie się nad korzystaniem z Solr 4.0 i Hunspell&#8217;a z polskimi słownikami wydajność takiego tandemu może być niezadowalająca.</p>
<p>Niestety ze względu na problemy wydajnościowe z Hunspell&#8217;em nie byliśmy w stanie porównać wydajności trzech dostępnych filtrów umożliwiających analizę języka polskiego. Natomiast z powyższej tabeli wnioskować można, iż w większości przypadków zarówno Stempel, jak i Morfologik będą charakteryzowały się podobną wydajnością.</p>
<h3>Krótkie podsumowanie</h3>
<p>Pomimo braku wyników wydajnościowych dotyczących Hunspell&#8217;a (bo te które są uważam za błędne i jestem pewien, że zostaną poprawione), widać iż Hunspell i Morfologik są dobrymi kandydatami do wykorzystania jeżeli chodzi o filtr umożliwiający analizę języka polskiego. W przypadku Morfologika, mamy wydajność podobną do Stempla, a w testach wychodzi na to, że Morfologik daje sobie radę z większą ilością polskich słów, co wpłynie pozytywnie na odczucia użytkowników.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2012/04/02/solr-4-0-i-mozliwosci-analizy-jezyka-polskiego/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Solr 4.0: Realtime GET</title>
		<link>https://solr.pl/2012/01/09/solr-4-0-realtime-get/</link>
					<comments>https://solr.pl/2012/01/09/solr-4-0-realtime-get/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 09 Jan 2012 20:35:54 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[near]]></category>
		<category><![CDATA[near real time]]></category>
		<category><![CDATA[nrt]]></category>
		<category><![CDATA[real]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[time]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=343</guid>

					<description><![CDATA[Kolejną funkcjonalnością, jakiej postanowiłem się przyjrzeć, w związku ze zbliżającym się Solr 4.0, jest tzw. &#8222;Realtime Get&#8221;. Jest to funkcjonalność umożliwiająca wyszukiwanie danych, które nie zostały jeszcze dodane do indexu, czyli po ich indeksowaniu nie zostało wysłane polecenie commit. Spójrzmy]]></description>
										<content:encoded><![CDATA[<p>Kolejną funkcjonalnością, jakiej postanowiłem się przyjrzeć, w związku ze zbliżającym się Solr 4.0, jest tzw. &#8222;Realtime Get&#8221;. Jest to funkcjonalność umożliwiająca wyszukiwanie danych, które nie zostały jeszcze dodane do indexu, czyli po ich indeksowaniu nie zostało wysłane polecenie <em>commit</em>. Spójrzmy zatem, jak to działa.</p>
<p><span id="more-343"></span></p>
<h3>Trochę teorii</h3>
<p>Aktualizacja danych w Lucene i Solr ma jeden zasadniczy minus &#8211; w przypadku standardowego korzystania nie jesteśmy w stanie zobaczyć zmian w indeksie, do chwili, kiedy nie zostanie wywołane polecenie <em>commit</em>. Problem polega na tym, iż operacja <em>commit </em>jest stosunkowo droga pod względem wydajnościowym i zbyt częste jej używanie może powodować problemy. Z związku z tym, jeżeli podczas implementacji aplikacji wykorzystującej Lucene lub Solr możesz być postawiony przed wyborem: albo wysoka wydajność, albo szybko widoczne zmiany. W związku z tym twórcy Lucene i Solr podjęli prace w kierunku umożliwiającym wyszukiwanie <em>Near Real Time</em> (NRT). W Lucene mamy już tą możliwość, w wersji 4.0 Solr także się jej doczekamy, ale nie tylko jej.</p>
<h3>Konfiguracja</h3>
<p>Aby funkcjonalność Realtime Get miała możliwość działania, potrzebujemy skonfigurować następujące rzeczy:</p>
<h4>Log transakcyjny</h4>
<p>Pierwsza z rzeczy koniecznych do uruchomienia funkcjonalności Realtime Get to zapisywanie loga transakcyjnego. W tym celu do konfiguracji <em>updateHandler&#8217;a</em> dodajemy następujący wpis:
</p>
<pre class="brush:xml">&lt;updateLog&gt;
  &lt;str name="dir"&gt;
<p>Powyższy wpis oznacza, iż katalog z logiem transakcyjnym zostanie zapisany w katalogu, gdzie zapisywane są dane.</p>
<h4>Realtime Get handler</h4>
<p>Druga rzecz, którą musimy zrobić, aby zobaczyć Realtime Get w działaniu, to zdefiniowanie odpowiedniego handlera (bądź komponentu). W tym celu do pliku <em>solrconfig.xml </em>dodajemy następujący wpis:
</p>
<pre class="brush:xml">&lt;requestHandler name="/get" class="solr.RealTimeGetHandler"&gt;
  &lt;lst name="defaults"&gt;
    &lt;str name="omitHeader"&gt;true&lt;/str&gt;
  &lt;/lst&gt;
&lt;/requestHandler&gt;</pre>
<p>Powyższy wpis, to nic innego jak zdefiniowanie nowego handlera, opartego o klasę <em>solr.RealTimeGetHandler</em>, który umożliwia wyszukiwanie w oparciu o log transakcyjny.</p>
<h3>Działanie</h3>
<p>Aby sprawdzić działanie <em>Realtime Get</em> postanowiłem zrobić dość prosty test. Najpierw zaindeksowałem jeden plik (z tych które dostępne są w katalogu <em>exampledocs</em>) za pomocą następującego polecenia:
</p>
<pre class="brush:bash">curl 'http://localhost:8983/solr/update' -d @hd.xml -H 'Content-type:application/xml'</pre>
<p>Oczywiście, po indeksowaniu nie wysyłamy polecenia <em>commit</em>. Zgodnie z oczekiwaniami, zadanie zapytania w postaci:
</p>
<pre class="brush:bash">http://localhost:8983/solr/select?q=*:*</pre>
<p>nie zwraca wyników wyszukiwania. Sprawdźmy więc, czy handler zarejestrowany jako <em>/get</em> jest w stanie dostarczyć nam wyniki. Wywołuję zatem następujące zapytanie:
</p>
<pre class="brush:bash">http://localhost:8983/solr/get?id=SP2514N</pre>
<p>W odpowiedzi, na powyższe zapytanie otrzymujemy następujący dokument:
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
&lt;doc name="doc"&gt;
  &lt;str name="id"&gt;SP2514N&lt;/str&gt;
  &lt;str name="name"&gt;Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133&lt;/str&gt;
  &lt;str name="manu"&gt;Samsung Electronics Co. Ltd.&lt;/str&gt;
  &lt;str name="manu_id_s"&gt;samsung&lt;/str&gt;
  &lt;arr name="cat"&gt;
    &lt;str&gt;electronics&lt;/str&gt;
    &lt;str&gt;hard drive&lt;/str&gt;
  &lt;/arr&gt;
  &lt;arr name="features"&gt;
    &lt;str&gt;7200RPM, 8MB cache, IDE Ultra ATA-133&lt;/str&gt;
    &lt;str&gt;NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor&lt;/str&gt;
  &lt;/arr&gt;
  &lt;float name="price"&gt;92.0&lt;/float&gt;
  &lt;int name="popularity"&gt;6&lt;/int&gt;
  &lt;bool name="inStock"&gt;true&lt;/bool&gt;
  &lt;date name="manufacturedate_dt"&gt;2006-02-13T15:26:37Z&lt;/date&gt;
  &lt;str name="store"&gt;35.0752,-97.032&lt;/str&gt;&lt;/doc&gt;
&lt;/response&gt;</pre>
<p>Zatem otrzymaliśmy dokument, który nie został jeszcze dodany do indeksu.</p>
<h3>Możliwe zastosowanie</h3>
<p>Zauważyliście pewnie, że aby pobrać dokument musiałem podać jego identyfikator (możliwe jest także podanie listy identyfikatorów). To prawda, <em>Realtime Get</em> przynajmniej w tym momencie, nie wspiera pełnego wyszukiwania, ponieważ nie do tego został stworzony. Funkcjonalność ta jest w stanie pokazać aktualizację dokumentów, których znamy identyfikatory - np. poprzez dodanie komponentu wykorzystywanego w <em>solr.RealTimeGetHandler</em> do dowolnego innego handlera. Dodatkowo nie musimy się bać o wydajność - komponent jest bardzo szybki. Zatem, jeżeli jednym z problemów twojej aplikacji opartej na Solr, jest problem z długim oczekiwaniem na aktualizację możesz z uśmiechem patrzeć w przyszłość <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /><em></em></p>
<h3>Podsumowując</h3>
<p>Funkcjonalność ta niesie za sobą bardzo dużo możliwości jeżeli chodzi o Solr, a także jego rozwój w kierunku SolrCloud. Na podstawie loga transakcyjnego będzie możliwe zaimplementowanie, np. automatycznego odtwarzania instancji Solr w klastrze, czy aktualizacji instancji w bardzo szybkim czasie. Jak widać wersja 4.0 to nie tylko usprawnienia w kierunku wyszukiwania, ale także rozwój Solr w kierunku baz NOSQL.</p>
<p>{solr.data.dir:}&lt;/str&gt;<br />
&lt;/updateLog&gt;</p>
<p>Powyższy wpis oznacza, iż katalog z logiem transakcyjnym zostanie zapisany w katalogu, gdzie zapisywane są dane.</p>
<h4>Realtime Get handler</h4>
<p>Druga rzecz, którą musimy zrobić, aby zobaczyć Realtime Get w działaniu, to zdefiniowanie odpowiedniego handlera (bądź komponentu). W tym celu do pliku <em>solrconfig.xml </em>dodajemy następujący wpis:
</p>
<pre wp-pre-tag-1=""></pre>
<p>Powyższy wpis, to nic innego jak zdefiniowanie nowego handlera, opartego o klasę <em>solr.RealTimeGetHandler</em>, który umożliwia wyszukiwanie w oparciu o log transakcyjny.</p>
<h3>Działanie</h3>
<p>Aby sprawdzić działanie <em>Realtime Get</em> postanowiłem zrobić dość prosty test. Najpierw zaindeksowałem jeden plik (z tych które dostępne są w katalogu <em>exampledocs</em>) za pomocą następującego polecenia:
</p>
<pre wp-pre-tag-2=""></pre>
<p>Oczywiście, po indeksowaniu nie wysyłamy polecenia <em>commit</em>. Zgodnie z oczekiwaniami, zadanie zapytania w postaci:
</p>
<pre wp-pre-tag-3=""></pre>
<p>nie zwraca wyników wyszukiwania. Sprawdźmy więc, czy handler zarejestrowany jako <em>/get</em> jest w stanie dostarczyć nam wyniki. Wywołuję zatem następujące zapytanie:
</p>
<pre wp-pre-tag-4=""></pre>
<p>W odpowiedzi, na powyższe zapytanie otrzymujemy następujący dokument:
</p>
<pre wp-pre-tag-5=""></pre>
<p>Zatem otrzymaliśmy dokument, który nie został jeszcze dodany do indeksu.</p>
<h3>Możliwe zastosowanie</h3>
<p>Zauważyliście pewnie, że aby pobrać dokument musiałem podać jego identyfikator (możliwe jest także podanie listy identyfikatorów). To prawda, <em>Realtime Get</em> przynajmniej w tym momencie, nie wspiera pełnego wyszukiwania, ponieważ nie do tego został stworzony. Funkcjonalność ta jest w stanie pokazać aktualizację dokumentów, których znamy identyfikatory &#8211; np. poprzez dodanie komponentu wykorzystywanego w <em>solr.RealTimeGetHandler</em> do dowolnego innego handlera. Dodatkowo nie musimy się bać o wydajność &#8211; komponent jest bardzo szybki. Zatem, jeżeli jednym z problemów twojej aplikacji opartej na Solr, jest problem z długim oczekiwaniem na aktualizację możesz z uśmiechem patrzeć w przyszłość <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /><em></em></p>
<h3>Podsumowując</h3>
<p>Funkcjonalność ta niesie za sobą bardzo dużo możliwości jeżeli chodzi o Solr, a także jego rozwój w kierunku SolrCloud. Na podstawie loga transakcyjnego będzie możliwe zaimplementowanie, np. automatycznego odtwarzania instancji Solr w klastrze, czy aktualizacji instancji w bardzo szybkim czasie. Jak widać wersja 4.0 to nie tylko usprawnienia w kierunku wyszukiwania, ale także rozwój Solr w kierunku baz NOSQL.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2012/01/09/solr-4-0-realtime-get/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Solr 4.0: DocTransformers &#8211; pierwsze spojrzenie</title>
		<link>https://solr.pl/2011/12/05/solr-4-0-doctransformers-pierwsze-spojrzenie/</link>
					<comments>https://solr.pl/2011/12/05/solr-4-0-doctransformers-pierwsze-spojrzenie/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 05 Dec 2011 20:33:18 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[doctransformers]]></category>
		<category><![CDATA[document]]></category>
		<category><![CDATA[lucene]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[transformation]]></category>
		<category><![CDATA[transformer]]></category>
		<category><![CDATA[transformers]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=337</guid>

					<description><![CDATA[Dzisiejszy wpis jest kolejnym z serii, w której staramy się przybliżyć funkcjonalności jakie pojawią się w wersji 4.0 Apache Solr. Dzisiaj przyjrzymy się funkcjonalności pozwalającej na zmianę sposobu w jaki zwracane są pola w dokumentach. Po co mi taka funkcjonalność]]></description>
										<content:encoded><![CDATA[<p>Dzisiejszy wpis jest kolejnym z serii, w której staramy się przybliżyć funkcjonalności jakie pojawią się w wersji 4.0 Apache Solr. Dzisiaj przyjrzymy się funkcjonalności pozwalającej na zmianę sposobu w jaki zwracane są pola w dokumentach.</p>
<p><span id="more-337"></span></p>
<h3>Po co mi taka funkcjonalność ?</h3>
<p>Do tej pory, praktycznie, nie mieliśmy możliwości wpływania na to, jak budowane były odpowiedzi zwracane przez Solr. Wraz z pojawieniem się wersji 4.0 Solr dostaniemy do ręki nowe narzędzie, tzw<em>. DocTransformers</em>. Funkcjonalność ta pozwala na modyfikację pól w wynikach wyszukiwania zwróconych przez Solr. Patrząc na to, co w tym momencie jest dostępne, mamy na przykład możliwość zamiany nazw zwracanych pól, czy oznaczenia elementów dodawanych przez <em>QueryElevationComponent</em>. W tym momencie nie jest tego dużo, natomiast implementacja własnego <em>DocTransformer&#8217;a </em>nie jest trudna, o czym za chwilę.</p>
<h3>Co jest już dostępne</h3>
<p>W tym momencie, w wersji 4.0 Apache Solr dostępne są następujące funkcjonalności związane z <em>DocTransformer&#8217;ami</em>:</p>
<ul>
<li>Możliwość oznaczenia, które dokumenty zostały dodane przez <em>QueryElevationComponent</em>.</li>
<li>Możliwość dodania informacji explain do dokumentu.</li>
<li>Możliwość dodania stałej wartości jako pola do dokumentu.</li>
<li>Możliwość dodania informacji o shardzie z jakiego pochodzi danych dokument.</li>
<li>Możliwość dodania informacji <em>docid</em> jako pola dokumentu (identyfikator wykorzystywany przez Lucene).</li>
</ul>
<h3>Jak z tego skorzystać ?</h3>
<p>Sprawdźmy, jak wygląda wykorzystanie tej funkcjonalności. Do tego celu pobrałem najnowszą wersję Apache Solr z repozytorium i uruchomiłem przykładowe wdrożenie. Następnie zaindeksowałem przykładowe dane i zadałem następujące zapytanie:
</p>
<pre class="brush:xml">http://localhost:8983/solr/select?q=encoded&amp;fl=name,score,[docid],[explain]</pre>
<p>W powyższym zapytaniu warto przyjrzeć się parametrowi <em>fl</em>. Oprócz informacji takich, jak pole <em>name</em> oraz wartość <em>score</em> powiedzieliśmy Solr, że chcemy, aby do wygenerowania wyników wyszukiwania zostały wykorzystane dwa <em>DocTransformery</em>: <em>[docid]</em> oraz <em>[explain]</em>. W odpowiedzi Solr wygenerował następującego XML&#8217;a:
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
 &lt;lst name="responseHeader"&gt;
  &lt;int name="status"&gt;0&lt;/int&gt;
  &lt;int name="QTime"&gt;2&lt;/int&gt;
  &lt;lst name="params"&gt;
    &lt;str name="q"&gt;encoded&lt;/str&gt;
    &lt;str name="fl"&gt;name,score,[docid],[explain]&lt;/str&gt;
  &lt;/lst&gt;
 &lt;/lst&gt;
 &lt;result name="response" numFound="2" start="0" maxScore="0.50524884"&gt;
 &lt;doc&gt;
  &lt;str name="name"&gt;Test with some GB18030 encoded characters&lt;/str&gt;
  &lt;float name="score"&gt;0.50524884&lt;/float&gt;
  &lt;int name="[docid]"&gt;0&lt;/int&gt;
  &lt;str name="[explain]"&gt;
  0.50524884 = (MATCH) weight(text:encoded in 0) [DefaultSimilarity], result of:
    0.50524884 = score(doc=0,freq=1.0 = termFreq=1), product of:
      1.0000001 = queryWeight, product of:
        3.2335923 = idf(docFreq=2, maxDocs=28)
        0.3092536 = queryNorm
      0.5052488 = fieldWeight in 0, product of:
        1.0 = tf(freq=1.0), with freq of:
          1.0 = termFreq=1
        3.2335923 = idf(docFreq=2, maxDocs=28)
        0.15625 = fieldNorm(doc=0)
  &lt;/str&gt;
 &lt;/doc&gt;
 &lt;doc&gt;
  &lt;str name="name"&gt;Test with some UTF-8 encoded characters&lt;/str&gt;
  &lt;float name="score"&gt;0.4041991&lt;/float&gt;
  &lt;int name="[docid]"&gt;25&lt;/int&gt;
  &lt;str name="[explain]"&gt;
  0.4041991 = (MATCH) weight(text:encoded in 25) [DefaultSimilarity], result of:
    0.4041991 = score(doc=25,freq=1.0 = termFreq=1), product of:
      1.0000001 = queryWeight, product of:
        3.2335923 = idf(docFreq=2, maxDocs=28)
        0.3092536 = queryNorm
      0.40419903 = fieldWeight in 25, product of:
        1.0 = tf(freq=1.0), with freq of:
          1.0 = termFreq=1
        3.2335923 = idf(docFreq=2, maxDocs=28)
        0.125 = fieldNorm(doc=25)
  &lt;/str&gt;
 &lt;/doc&gt;
&lt;/result&gt;
&lt;/response&gt;</pre>
<p>Jak widać, Solr dołączył do wyników wyszukiwania to o co go prosiliśmy.</p>
<h3>Własna implementacja</h3>
<p>Omówmy, jak wygląda implementacja własnego <em>DocTransfomer&#8217;a</em>. Poniżej, przykład klasy <em>RenameFieldsTransformer </em>z pakietu <em>org.apache.solr.response.transform</em>. Ogólnie polega to na implementacji następujących metod z klasy <em>DocTransformer</em> z pakietu <em>org.apache.solr.response.transform</em>:</p>
<ul>
<li><code>String getName()</code> &#8211; metoda zwracająca nazwę transformera,</li>
<li><code>void transform(SolrDocument doc, int docid)</code> &#8211; metoda dokonująca transformacji.</li>
</ul>
<p>Sama implementacja wygląda następująco:
</p>
<pre class="brush:java">public class RenameFieldsTransformer extends DocTransformer {
 final NamedList&lt;String&gt; rename;

 public RenameFieldsTransformer( NamedList&lt;String&gt; rename ) {
  this.rename = rename;
 }

 @Override
 public String getName() {
  StringBuilder str = new StringBuilder();
  str.append( "Rename[" );
  for( int i=0; i&lt; rename.size(); i++ ) {
   if( i &gt; 0 ) {
    str.append( "," );
   }
   str.append( rename.getName(i) ).append( "&gt;&gt;" ).append( rename.getVal( i ) );
  }
  str.append( "]" );
  return str.toString();
 }

 @Override
 public void transform(SolrDocument doc, int docid) {
  for( int i=0; i&lt;rename.size(); i++ ) {
   Object v = doc.remove( rename.getName(i) );
   if( v != null ) {
    doc.setField(rename.getVal(i), v);
   }
  }
 }
}</pre>
<p>Powyższy kod umożliwia zwrócenie pola o innej nazwie, niż ta, która została zaindeksowana. Metoda <em>transform</em> iteruje po wszystkich wartościach zmiennej <em>rename</em>, która zawiera nazwę pól, które mają zostać zmienione wraz z nazwami na jakie powinny zostać zamienione. Należy pamiętać, iż, aby nasz własny transformer zaczął działać, należy dodać go do pliku <em>solrconfig.xml</em>. Oto przykład w wiki Solr:
</p>
<pre class="brush:xml">&lt;transformer name="elevated" class="org.apache.solr.response.transform.EditorialMarkerFactory" /&gt;</pre>
<h3>Podsumowując</h3>
<p>Należy pamiętać, iż opisywana funkcjonalność jest oznaczona jako eksperymentalna i jej działanie może się zmienić w stosunku do opisywanego w chwili publikacji wersji 4.0 Solr i Lucene. Na pewno wrócimy do tematu po ukazaniu się Solr 4.0.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2011/12/05/solr-4-0-doctransformers-pierwsze-spojrzenie/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Solr 4.0: możliwości parametru fl &#8211; pierwsze spojrzenie</title>
		<link>https://solr.pl/2011/11/22/solr-4-0-mozliwosci-parametru-fl-pierwsze-spojrzenie/</link>
					<comments>https://solr.pl/2011/11/22/solr-4-0-mozliwosci-parametru-fl-pierwsze-spojrzenie/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Tue, 22 Nov 2011 20:32:04 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[fields]]></category>
		<category><![CDATA[fl]]></category>
		<category><![CDATA[parametr]]></category>
		<category><![CDATA[pola]]></category>
		<category><![CDATA[pseudo]]></category>
		<category><![CDATA[pseudo fields]]></category>
		<category><![CDATA[solr]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=333</guid>

					<description><![CDATA[W związku ze zbliżającym się powoli wydaniem Apache Solr w wersji 4.0 uznałem, iż nadszedł czas, aby przybliżyć niektóre z funkcjonalności, jakie dostaniemy w swoje ręce wraz z premierą tej wersji silnika wyszukiwania. Na pierwszy ogień przyjrzymy się prostej, aczkolwiek]]></description>
										<content:encoded><![CDATA[<p>W związku ze zbliżającym się powoli wydaniem Apache Solr w wersji 4.0 uznałem, iż nadszedł czas, aby przybliżyć niektóre z funkcjonalności, jakie dostaniemy w swoje ręce wraz z premierą tej wersji silnika wyszukiwania. Na pierwszy ogień przyjrzymy się prostej, aczkolwiek przydatnej funkcjonalności nazwanej <em>pseudo fields </em>wraz z dodatkowymi możliwościami związanymi z parametrem <em>fl</em>.</p>
<p><span id="more-333"></span></p>
<h3>Na początek</h3>
<p>W Apache Solr 4.0 zmienił się nieznacznie sposób obsługi parametru <em>fl</em> &#8211; parametr może być podawany wielokrotnie. Wartości z wszystkich podanych do zapytania parametrów <em>fl</em> zostaną przez Solr połączone. Czasami będzie to przydatne, przynajmniej w moim przypadku.</p>
<h3>Własne nazwy pól</h3>
<p>Wraz z Solr 4.0 będziemy mieli możliwość nazywania pól, jakie zwracane są w Solr. Wyobraźmy sobie, że w zależności od kontekstu chcielibyśmy aby pola, które w indeksie nazywane są <em>price_en</em>, <em>price_pl</em>, czy <em>price_fr</em> były zwracane jako pole <em>price</em>. W Solr 4.0 możemy to zrobić w umieszczając następujący fragment w zapytaniu:
</p>
<pre class="brush:xml">fl=price:price_pl</pre>
<p>Spowoduje to, że pole <em>price_pl</em>, zostanie zwrócone jako pole o nazwie <em>price</em>.</p>
<h3>Wszystkie pola o wspólnym początku nazwy</h3>
<p>Jeżeli będziemy chcieli zwrócić, wraz z dokumentem, wszystkie pola, których nazwa zaczyna się np. od <em>price</em> (użyteczne w przypadku pól dynamicznych) wystarczy, że dodamy następującą wartość parametru <em>fl</em> w zapytaniu:
</p>
<pre class="brush:xml">fl=price*</pre>
<h3>Zwracanie wartości funkcji</h3>
<p>Ostatnia z funkcjonalności, którym przyjrzymy się dzisiaj, czyli możliwość dołączenia wyniku działania funkcji, jako pola dokumentu. Zatem w Solr 4.0 będziemy mieli możliwość dodania np. sumy cen, bądź wyliczonej odległości geograficznej pomiędzy dwoma punktami. Całkiem przydatne. Aby skorzystać z tej funkcjonalności wystarczy do parametru <em>fl</em> dodać odpowiednie wywołanie funkcji dostępnej w Solr, na przykład:
</p>
<pre class="brush:xml">fl=*,stock:sum(stockMain,stockShop)</pre>
<p>Co spowoduje zwrócenie wszystkich pól (wartość *) oraz pola o nazwie <em>stock</em>, które będzie sumą pól <em>stockMain</em> oraz <em>stockShop</em>.</p>
<h3>Kilka słów na koniec</h3>
<p>Oprócz opisanych powyżej, nowych funkcjonalności, parametru <em>fl</em>, jest jeszcze możliwość skorzystania DocTransformer. Opisanie tego zostawiłem sobie jednak na kolejny wpis o Apache Solr 4.0.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2011/11/22/solr-4-0-mozliwosci-parametru-fl-pierwsze-spojrzenie/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Hierarchiczny faceting &#8211; czyli Pivot Facet w trunk&#8217;u</title>
		<link>https://solr.pl/2010/10/25/hierarchiczny-faceting-czyli-pivot-facet-w-trunku/</link>
					<comments>https://solr.pl/2010/10/25/hierarchiczny-faceting-czyli-pivot-facet-w-trunku/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 25 Oct 2010 05:25:50 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[facet]]></category>
		<category><![CDATA[grouping]]></category>
		<category><![CDATA[hierarchical]]></category>
		<category><![CDATA[pivot]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[trunk]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=46</guid>

					<description><![CDATA[W dużej ilości wdrożeń z jakimi miałem do czynienia zawsze pojawiało się pytanie &#8211; co możemy zrobić, aby uzyskać od Solr drzewiastą strukturę facetingu. Oczywiście są na to metody, jednak ich wykorzystanie polegało na modyfikacji danych i odpowiednim przetwarzaniu po]]></description>
										<content:encoded><![CDATA[<p>W dużej ilości wdrożeń z jakimi miałem do czynienia zawsze pojawiało się pytanie &#8211; co możemy zrobić, aby uzyskać od Solr drzewiastą strukturę facetingu. Oczywiście są na to metody, jednak ich wykorzystanie polegało na modyfikacji danych i odpowiednim przetwarzaniu po stronie aplikacji. Nie było to szczególnie funkcjonalne, jak i szczególnie wygodne. Jednak kilka dni temu Solr w wersji 4.0 został wzbogacony o kod oznaczony jako <a href="https://issues.apache.org/jira/browse/SOLR-792" target="_blank" rel="noopener noreferrer">SOLR-792</a> w systemie JIRA. Zobaczmy w takim wypadku, jak pobrać wyniki facetingu w postaci drzewa.</p>
<p><span id="more-46"></span></p>
<p>Ważna uwaga &#8211; funkcjonalność ta w tym momencie jest dostępna tylko i wyłącznie w wersji 4.0 Solr, czyli w wersji rozwojowej. Oznaczenie 4.0 jest oznaczeniem kodu, który znajduje się w <em>trunk&#8217;u</em> repozytorium SVN.</p>
<h3>Kilka słów na początek</h3>
<p>W wielu projektach w jakich miałem okazję zajmować się była konieczność wprowadzenia hierarchicznego facetingu. Jednym z prostszych przykładów jest wymaganie polegające na pokazaniu miejscowości w województwach i ilości dokumentów zarówno w województwach, jak i w poszczególnych miejscowościach. Do tej pory, bez zmiany struktury danych, nie było możliwości zrealizowania takiej funkcjonalności. Teraz już jest <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>Indeksowanie</h3>
<p>Aby nie potrzebnie nie komplikować opisywanych funkcjonalności zdecydowałem się na skorzystanie z przykładowych dokumentów XML dostępnych w katalogu <em>/exampledocs </em>przykładowego wdrożenia. Nie modyfikowałem także pliku <em>schema.xml</em>, czy <em>solrconfig.xml</em>, tak więc konfiguracje zostały standardowe. I tyle jeżeli chodzi o konfigurację. Tak więc możemy uruchomić indeksację (komenda wywołana z katalogu <em>$SOLR_HOME/exampledocs/</em>):
</p>
<pre class="brush:bash">./post.sh *.xml</pre>
<p>Kilka ekranów informacji i mamy zaindeksowane dane.</p>
<h3>Mechanizm</h3>
<p>Samo skorzystanie z hierarchicznego facetingu nie jest trudne. Twórcy Solr dali nam do dyspozycji dwa dodatkowe parametry:</p>
<ul>
<li><em>facet.pivot</em> &#8211; lista pól oddzielonych przecinkami, która pokazuje po jakich polach i w jakiej kolejności wyliczyć strukturę,</li>
<li><em>facet.pivot.mincount</em> &#8211; minimalna ilość dokumentów, aby wynik został uwzględniony w facetingu. Wartość domyślna parametru to 1.</li>
</ul>
<p>Spróbujmy więc.</p>
<h3>Zapytania</h3>
<p>Na początek próba z dwoma polami. Pobieram wszystkie dokumenty z indeksu i dodaje parametr <em>facet.pivot=cat,inStock</em>, czyli mówię Solr, że chce dostać wyniki hierarchicznego facetingu, gdzie pierwszym poziomem hierarchii jest pole <em>cat</em>, a drugim poziomem jest pole <em>inStock</em>. Zapytanie wygląda w następujący sposób:
</p>
<pre class="brush:xml">http://localhost:8983/solr/select/?q=*:*&amp;facet=true&amp;facet.pivot=cat,inStock</pre>
<p>Aby skrócić listing pominąłem część odpowiedzialną za wyniki wyszukiwania wraz z nagłówkiem.
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
.
.
.
&lt;result name="response" numFound="19" start="0"/&gt;
&lt;lst name="facet_counts"&gt;
  &lt;lst name="facet_queries"/&gt;
  &lt;lst name="facet_fields"/&gt;
  &lt;lst name="facet_dates"/&gt;
  &lt;lst name="facet_ranges"/&gt;
  &lt;lst name="facet_pivot"&gt;
    &lt;arr name="cat,inStock"&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;electronics&lt;/str&gt;
        &lt;int name="count"&gt;17&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;13&lt;/int&gt;
          &lt;/lst&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;false&lt;/bool&gt;
            &lt;int name="count"&gt;4&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;memory&lt;/str&gt;
        &lt;int name="count"&gt;6&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;6&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;connector&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;false&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;graphics card&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;false&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;hard drive&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;monitor&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;search&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;software&lt;/str&gt;
        &lt;int name="count"&gt;2&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;2&lt;/int&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
    &lt;/arr&gt;
  &lt;/lst&gt;
&lt;/lst&gt;
&lt;/response&gt;</pre>
<p>Sama prezentacja wyników facetingu, w tym wypadku, uległa zmianie. Dla każdej wartości głównego poziomu mamy znaczniki określające pole (znacznik z atrybutem <em>name=&#8221;field&#8221;</em>), wartość (znacznik z atrybutem <em>name=&#8221;value&#8221;</em>) oraz ilość dokumentów (znacznik z atrybutem <em>name=&#8221;count&#8221;</em>). Następnie mamy tablicę wyników drugiego poziomu (znacznik z atrybutem name=&#8221;pivot&#8221;). Tablica ta zawiera elementy takie same jak poziom pierwszy, czyli nazwa pola, wartość w polu oraz ilość dokumentów z daną wartością.</p>
<p>Zobaczmy, jak mechanizm ten daje sobie radę z większą ilością zagłębienia. W tym celu zadałem następujące zapytanie do tej samej wersji Solr:
</p>
<pre class="brush:xml">http://localhost:8983/solr/select/?q=*:*&amp;facet=true&amp;facet.pivot=cat,inStock,features</pre>
<p>Jak w powyższym przypadku w pominąłem nagłówek odpowiedzi wraz z wynikami zostawiając same wyniki facetingu. Dodatkowo, ze względu na długość wyników facetingu przedstawiam wyniki tylko dla jednej kategorii głównej pomijając resztę:
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
.
.
.
&lt;result name="response" numFound="19" start="0"/&gt;
&lt;lst name="facet_counts"&gt;
  &lt;lst name="facet_queries"/&gt;
  &lt;lst name="facet_fields"/&gt;
  &lt;lst name="facet_dates"/&gt;
  &lt;lst name="facet_ranges"/&gt;
  &lt;lst name="facet_pivot"&gt;
    &lt;arr name="cat,inStock,features"&gt;
      &lt;lst&gt;
        &lt;str name="field"&gt;cat&lt;/str&gt;
        &lt;str name="value"&gt;electronics&lt;/str&gt;
        &lt;int name="count"&gt;17&lt;/int&gt;
        &lt;arr name="pivot"&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;true&lt;/bool&gt;
            &lt;int name="count"&gt;13&lt;/int&gt;
            &lt;arr name="pivot"&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;2&lt;/str&gt;
                &lt;int name="count"&gt;7&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;3&lt;/str&gt;
                &lt;int name="count"&gt;7&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;lcd&lt;/str&gt;
                &lt;int name="count"&gt;5&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;x&lt;/str&gt;
                &lt;int name="count"&gt;5&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;ca&lt;/str&gt;
                &lt;int name="count"&gt;4&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;latenc&lt;/str&gt;
                &lt;int name="count"&gt;4&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;tft&lt;/str&gt;
                &lt;int name="count"&gt;4&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;v&lt;/str&gt;
                &lt;int name="count"&gt;4&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;0&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;1&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;25&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;30&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;5&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;7&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;8&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;time&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;up&lt;/str&gt;
                &lt;int name="count"&gt;3&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;000&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;19&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;20&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;2336&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;27&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;275&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;6&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;75&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;activ&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;built&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;cach&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;color&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;flash&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;heat&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;heatspread&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;matrix&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;mb&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;ms&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;photo&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;resolut&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;seek&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;speed&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;spreader&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;unbuff&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;usb&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
            &lt;/arr&gt;
          &lt;/lst&gt;
          &lt;lst&gt;
            &lt;str name="field"&gt;inStock&lt;/str&gt;
            &lt;bool name="value"&gt;false&lt;/bool&gt;
            &lt;int name="count"&gt;4&lt;/int&gt;
            &lt;arr name="pivot"&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;0&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;1&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;16&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;2&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;20&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;3&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;9&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;90&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;adapt&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;car&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;clock&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;direct&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;directx&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;dual&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;dvi&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;express&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;gddr&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;ghz&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;gl&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;gpu&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;gpuvpu&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;hdtv&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;mb&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;mhz&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;open&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;opengl&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;out&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;pci&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;power&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;vpu&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;white&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
              &lt;lst&gt;
                &lt;str name="field"&gt;features&lt;/str&gt;
                &lt;str name="value"&gt;x&lt;/str&gt;
                &lt;int name="count"&gt;2&lt;/int&gt;
              &lt;/lst&gt;
            &lt;/arr&gt;
          &lt;/lst&gt;
        &lt;/arr&gt;
      &lt;/lst&gt;
    &lt;/arr&gt;
  &lt;/lst&gt;
&lt;/lst&gt;
&lt;/response&gt;</pre>
<p>Jak widać na zaprezentowanym przykładzie, również w tym wypadku Solr nie miał problemów z poprawnym wyliczeniem hierarchii. Sama część prezentacyjna wzbogaciła się o jeden poziom zagłębienia, który podlega tym samym zasadom co reszta poziomów.</p>
<h3>Kilka słów na koniec</h3>
<p>Moim zdaniem jedna z bardziej przydatnych funkcjonalności dla &#8222;<em>zwykłego&#8221; </em>użytkownika. Niestety na razie dostępna tylko w wersji developerskiej Solr. Nie znalazłem także informacji o tym, czy planowane jest przeniesienie tej funkcjonalności do wersji 1.5 Solr, czyli gałęzi o nazwie <em>branch_3x</em> w SVN. Jednak, ważne jest to, że taka funkcjonalność powstała i wcześniej, czy później użytkownicy Solr będą mogli z niej korzystać.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2010/10/25/hierarchiczny-faceting-czyli-pivot-facet-w-trunku/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Szybkie spojrzenie &#8211; FieldCollapsing</title>
		<link>https://solr.pl/2010/09/20/szybkie-spojrzenie-fieldcollapsing/</link>
					<comments>https://solr.pl/2010/09/20/szybkie-spojrzenie-fieldcollapsing/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 20 Sep 2010 04:27:07 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[4.0]]></category>
		<category><![CDATA[collapsing]]></category>
		<category><![CDATA[field]]></category>
		<category><![CDATA[fieldcollapsing]]></category>
		<category><![CDATA[grouping]]></category>
		<category><![CDATA[grupowanie]]></category>
		<category><![CDATA[lucene]]></category>
		<category><![CDATA[lucene 4.0]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[solr 4.0]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=34</guid>

					<description><![CDATA[FieldCollapsing, czyli inaczej grupowanie wyników wyszukiwania &#8211; 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]]></description>
										<content:encoded><![CDATA[<p>FieldCollapsing, czyli inaczej grupowanie wyników wyszukiwania &#8211;  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ść.</p>
<p><span id="more-34"></span></p>
<p>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.</p>
<h3><strong>FieldCollapsing, czyli co ?</strong></h3>
<p>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ć &#8211; 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.</p>
<h3><strong><strong>Parametry</strong></strong></h3>
<p>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:</p>
<ul>
<li><em>group</em> &#8211; analogicznie do np. facetingu ustawienie tego parametru na wartość <em>true</em> włącza mechanizm FieldCollapsing. Wartość domyślna parametru to <em>false</em>.</li>
<li><em>group.field</em> &#8211; określenie na podstawie jakiego pola ma się odbywać grupowanie.</li>
<li><em>group.func</em> &#8211; określenie funkcji, na podstawie wyniku której będzie odbywać się grupowanie.</li>
<li><em>group.limit</em> &#8211; ilość wyników jaka ma być zwrócona w poszczególnych grupach. Domyślna wartość parametru to 1.</li>
<li><em>group.sort</em> &#8211; parametr określający w jaki sposób sortować dokumenty w ramach grup. Wartość domyślna, to wartość <em>score desc</em>.</li>
</ul>
<p>Warto podkreślić, iż parametr <em>rows</em> 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 <em>sort</em>. 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.</p>
<h3><strong>Wyniki wyszukiwania</strong></h3>
<p>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 <em>group.limit</em>). Na przykład, zadając zapytanie:
</p>
<pre class="brush:xml">http://localhost:8983/solr/select/?q=*:*&amp;group=true&amp;group.field=inStock&amp;indent=true</pre>
<p>do indeksu, który powstał poprzez zaindeksowanie wszystkich dokumentów w formacie XML z katalogu <em>exampledocs</em> przykładowego wdrożenia dostarczanego z Solr, otrzymujemy następujący wynik:
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
&lt;lst name="responseHeader"&gt;
  &lt;int name="status"&gt;0&lt;/int&gt;
  &lt;int name="QTime"&gt;0&lt;/int&gt;
  &lt;lst name="params"&gt;
    &lt;str name="group.field"&gt;inStock&lt;/str&gt;
    &lt;str name="group"&gt;true&lt;/str&gt;
    &lt;str name="indent"&gt;true&lt;/str&gt;
    &lt;str name="q"&gt;*:*&lt;/str&gt;
  &lt;/lst&gt;
&lt;/lst&gt;
&lt;lst name="grouped"&gt;
  &lt;lst name="inStock"&gt;
    &lt;int name="matches"&gt;19&lt;/int&gt;
    &lt;arr name="groups"&gt;
     &lt;lst&gt;
        &lt;str name="groupValue"&gt;T&lt;/str&gt;
        &lt;result name="doclist" numFound="15" start="0"&gt;
          &lt;doc&gt;
            &lt;arr name="cat"&gt;&lt;str&gt;electronics&lt;/str&gt;&lt;str&gt;hard drive&lt;/str&gt;&lt;/arr&gt;
            &lt;arr name="features"&gt;&lt;str&gt;7200RPM, 8MB cache, IDE Ultra ATA-133&lt;/str&gt;&lt;str&gt;NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor&lt;/str&gt;&lt;/arr&gt;
            &lt;str name="id"&gt;SP2514N&lt;/str&gt;
            &lt;bool name="inStock"&gt;true&lt;/bool&gt;
            &lt;str name="manu"&gt;Samsung Electronics Co. Ltd.&lt;/str&gt;
            &lt;date name="manufacturedate_dt"&gt;2006-02-13T15:26:37Z&lt;/date&gt;
            &lt;str name="name"&gt;Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133&lt;/str&gt;
            &lt;int name="popularity"&gt;6&lt;/int&gt;
            &lt;float name="price"&gt;92.0&lt;/float&gt;
            &lt;str name="store"&gt;45.17614,-93.87341&lt;/str&gt;
            &lt;double name="store_0_d"&gt;45.17614&lt;/double&gt;
            &lt;double name="store_1_d"&gt;-93.87341&lt;/double&gt;
            &lt;str name="store_lat_lon"&gt;45.17614,-93.87341&lt;/str&gt;
          &lt;/doc&gt;
        &lt;/result&gt;
      &lt;/lst&gt;
      &lt;lst&gt;
        &lt;str name="groupValue"&gt;F&lt;/str&gt;
        &lt;result name="doclist" numFound="4" start="0"&gt;
          &lt;doc&gt;
            &lt;arr name="cat"&gt;&lt;str&gt;electronics&lt;/str&gt;&lt;str&gt;connector&lt;/str&gt;&lt;/arr&gt;
            &lt;arr name="features"&gt;&lt;str&gt;car power adapter, white&lt;/str&gt;&lt;/arr&gt;
            &lt;str name="id"&gt;F8V7067-APL-KIT&lt;/str&gt;
            &lt;bool name="inStock"&gt;false&lt;/bool&gt;
            &lt;str name="manu"&gt;Belkin&lt;/str&gt;
            &lt;date name="manufacturedate_dt"&gt;2005-08-01T16:30:25Z&lt;/date&gt;
            &lt;str name="name"&gt;Belkin Mobile Power Cord for iPod w/ Dock&lt;/str&gt;
            &lt;int name="popularity"&gt;1&lt;/int&gt;
            &lt;float name="price"&gt;19.95&lt;/float&gt;
            &lt;str name="store"&gt;45.17614,-93.87341&lt;/str&gt;
            &lt;double name="store_0_d"&gt;45.17614&lt;/double&gt;
            &lt;double name="store_1_d"&gt;-93.87341&lt;/double&gt;
            &lt;str name="store_lat_lon"&gt;45.17614,-93.87341&lt;/str&gt;
            &lt;float name="weight"&gt;4.0&lt;/float&gt;
          &lt;/doc&gt;
        &lt;/result&gt;
      &lt;/lst&gt;
    &lt;/arr&gt;
  &lt;/lst&gt;
&lt;/lst&gt;
&lt;/response&gt;</pre>
<h3><strong>Na koniec</strong></h3>
<p>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<strong>, </strong>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 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /><strong><br />
</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2010/09/20/szybkie-spojrzenie-fieldcollapsing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
