<?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>facet &#8211; Solr.pl</title>
	<atom:link href="https://solr.pl/tag/facet/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>Tue, 10 Nov 2020 09:59:46 +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>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>Możliwość facetingu w Solr</title>
		<link>https://solr.pl/2010/08/23/mozliwosc-facetingu-w-solr/</link>
					<comments>https://solr.pl/2010/08/23/mozliwosc-facetingu-w-solr/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 23 Aug 2010 05:48:10 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[date faceting]]></category>
		<category><![CDATA[facet]]></category>
		<category><![CDATA[facet method]]></category>
		<category><![CDATA[facet parameter]]></category>
		<category><![CDATA[facet query]]></category>
		<category><![CDATA[faceting]]></category>
		<category><![CDATA[local]]></category>
		<category><![CDATA[local params]]></category>
		<category><![CDATA[params]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[range faceting]]></category>
		<category><![CDATA[solr]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=26</guid>

					<description><![CDATA[Faceting to jedna z metod kategoryzacji treści znalezionych w procesie wyszukiwania informacji. W przypadku Solr jest to podział zbioru znalezionych dokumentów na podstawie pewnego kryterium: zawartości pojedynczego pola, zapytania, czy też na podstawie przedziałów lub dat. W dzisiejszym wpisie postaram]]></description>
										<content:encoded><![CDATA[<p>Faceting to jedna z metod kategoryzacji treści znalezionych w procesie  wyszukiwania informacji. W przypadku Solr jest to podział zbioru  znalezionych dokumentów na podstawie pewnego kryterium: zawartości  pojedynczego pola, zapytania, czy też na podstawie przedziałów lub dat. W  dzisiejszym wpisie postaram się przybliżyć możliwości wykorzystania  mechanizmu facetingu, zarówno tego dostępnego obecnie w Solr 1.4.1, jak  również tego co będzie dostępne w przyszłości.</p>
<p><span id="more-26"></span></p>
<p>Jednym z niewielu źródeł dotyczących facetingu jest wiki Solr, a dokładniej strona pod adresem: <a href="http://wiki.apache.org/solr/SimpleFacetParameters" target="_blank" rel="noopener noreferrer">http://wiki.apache.org/solr/SimpleFacetParameters</a>. Poniższy artykuł jest rozszerzeniem informacji dostępnych na wymienionej stronie.</p>
<p>Faceting w Solr można podzielić na cztery podstawowe rodzaje:</p>
<ul>
<li>faceting po polu,</li>
<li>faceting za pomocą zapytania,</li>
<li>faceting po datach,</li>
<li>faceting po przedziałach.</li>
</ul>
<p>Aby uruchomić mechanizm facetingu, należy do zapytania, które zadajemy do Solr dołączyć parametr <em>facet</em> z wartością <em>true</em>.</p>
<h3>Faceting po polu</h3>
<p>Pierwszy rodzaj facetingu, polegający na kategoryzacji znalezionych  dokumentów ze względu na zawartość podanego pola. Dzięki temu rodzajowi  facetingu jesteśmy w stanie pobrać ilości dokumentów znalezionych na  przykład w poszczególnych kategoriach, czy w podziale na lokalizację  geograficzną. Faceting ten charakteryzuje się sporą liczbą opcji i  możliwości konfigurowania jego zachowań. Poniżej parametry możliwe do  wykorzystania:</p>
<ul>
<li><em>facet.field</em> &#8211; pole po którym będzie wykonywany  faceting. W jednym zapytaniu może być wiele pól po którym wykonywany  będzie faceting. Należy jednak liczyć się ze spadkiem wydajności w  przypadku dużej ilości pól, po których wykonujemy faceting.</li>
<li><em>facet.prefix</em> &#8211; ogranicza wyniki facetingu do tych, które zaczynają się od podanego  przedrostka. Parametr może być definiowany dla poszczególnych pól  przekazanych w parametrze <em>facet.field</em> poprzez dodanie nazwy pola w następujący sposób: <em>facet.NAZWA_POLA.prefix</em>.&nbsp; Z pomocą tego parametru w dość prosty sposób można wdrożyć mechanizm autocomplete.</li>
<li><em>facet.sort</em> &#8211; określa w jaki sposób mają być sortowane wyniki facetingu. Jeżeli  korzystamy z Solr w wersji niższej, niż 1.4 parametr ten przyjmuje  wartości <em>true</em> lub <em>false</em> oznaczające kolejno:  sortowanie po ilości wyników oraz sortowanie według porządku w indeksie  (w przypadku znaków ASCII oznacza sortowania alfabetyczne). Jeżeli  natomiast korzystamy z Solr w wersji 1.4 lub wyższej powinniśmy  korzystać z wartości <em>count</em> (oznaczającej to samo co wartość <em>true</em>) oraz <em>index</em> (oznaczającej to samo co <em>false</em>). Warto wiedzieć, iż wartością domyślną parametru jest wartość <em>true/count</em> w przypadku ustawienia parametru <em>facet.limit</em> na wartość 0 lub <em>false/index</em> w przypadku ustawienia większego limitu. Parametr może być definiowany dla poszczególnych pól przekazanych w parametrze <em>facet.field.</em></li>
<li><em>facet.limit </em>&#8211;  parametr określający jak dużo unikalnych wartości ma zwrócić mechanizm  facetingu dla danego pola. Wartość ujemna tego parametru oznacza brak  ustawionego limitu. Należy pamiętać, iż im większy limit, tym większą  ilość pamięci potrzebujemy oraz tym dłuższy czas wykonywania zapytania.  Wartość domyślna parametru to 100. Parametr może być definiowany dla  poszczególnych pól przekazanych w parametrze <em>facet.field</em>.</li>
<li><em>facet.offset</em> &#8211; parametr określający od którego wyniku facetingu prezentować wyniki.  Wartość domyślna parametru to 0. Parametr może być wykorzystany do  stronicowania wyników facetingu. Parametr może być definiowany dla  poszczególnych pól przekazanych w parametrze <em>facet.field.</em></li>
<li><em>facet.mincount</em> &#8211; parametr określający, jaką minimalną liczność musi mieć dany wynik,  aby pokazany został w wynikach facetingu. Domyślna wartość tego  parametru to 0. Parametr może być definiowany dla poszczególnych pól  przekazanych w parametrze <em>facet.field.</em></li>
<li><em>facet.missing</em> &#8211; parametr określający, czy oprócz standardowych wyników facetingu ma  być dodany wpis o ilości dokumentów nie posiadających wpisu w danym  polu. Parametr przyjmuje wartości <em>true </em>oraz <em>false</em> (wartość domyślna). Parametr może być definiowany dla poszczególnych pól przekazanych w parametrze <em>facet.field.</em></li>
<li><em>facet.method</em> &#8211; parametr wprowadzony w Solr 1.4, przyjmuje wartości <em>enum</em> oraz <em>fc</em>. Określa metodę wyliczania wartości facetingu. Ustawienie metody kryjącej się pod parametrem <em>enum </em>skutkuje  wyliczeniem wszystkich termów w danym polu i wyliczeniem na tej  podstawie wyników facetingu. Ta metoda wyliczenia okazuje się wydajna  przy polach, które mają małą ilość unikalnych termów. Druga metoda  oznaczona jako <em>fc</em> jest standardową metodą wyliczania facetingu  dla pól jednowartościowych i polega na iterowaniu po wszystkich  znalezionych dokumentach w celu wyliczenia wyników facetingu. Parametr  może być definiowany dla poszczególnych pól przekazanych w parametrze <em>facet.field. </em>Domyślną wartością parametru jest <em>fc</em> dla wszystkich pól nie opartych o typ <em>Boolean</em>. <em><br />
</em></li>
<li><em>facet.enum.cache.minDf </em>&#8211;  parametr o dziwnie brzmiącej nazwie określający minimalną liczbę  dokumentów pasujących do pojedynczego termu, aby dla tego termu użyć  metody <em>fc</em> do wyliczania wyników facetingu. Wiem, że to brzmi pokrętnie, ale nie wiem czy da się prościej to wytłumaczyć <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;" /></li>
</ul>
<p>Tak wyglądają parametry facetingu, z jakich możemy skorzystać w  przypadku pierwszego rodzaju facetingu. W większości parametrów  napisałem, iż możliwe jest definiowanie parametru dla poszczególnych  pól. Jak to wygląda ? Załóżmy, że zadajemy następujące zapytanie do  Solr:
</p>
<pre class="brush:xml">q=solr&amp;facet=true&amp;facet.field=category&amp;facet.field=location</pre>
<p>Proste zapytanie o term 'solr&#8217; z włączonym mechanizmem facetingu po dwóch polach &#8211; polu <em>category</em> oraz polu <em>location</em>. Chcielibyśmy, dla pola <em>category</em> pokazać 200 wyników facetingu posortowanych według liczności, a dla pola <em>location</em> pokazać 50 wyników facetingu posortowanych alfabetycznie. Aby to  osiągnąć dodajemy do naszego zapytania następujący fragment:
</p>
<pre class="brush:xml">facet.category.limit=200&amp;facet.category.sort=count&amp;facet.location.limit=50&amp;facet.location.sort=index</pre>
<p>W pokazany sposób możemy bez problemu modyfikować zachowanie mechanizmu  facetingu dla poszczególnych pól dla których jest on wyliczany w ramach  zapytania.</p>
<h3>Faceting za pomocą zapytania</h3>
<p>Metoda facetingu oparta tak naprawdę o jeden parametr &#8211; <em>facet.query</em> do którego podajemy zapytanie. Zapytanie musi być zapisane tak, aby  standardowy parser Lucene był w stanie je zrozumieć. Przykładem  wykorzystania tego parametru jest np. zapytanie o grupę cenową, które  mogłoby wyglądać na przykład tak:
</p>
<pre class="brush:xml">facet.query=price:[0+TO+100]</pre>
<p>Należy  jednak pamiętać, iż każdy dodany do zapytania parametr <em>facet.query</em> to kolejne zapytanie do Lucene, co oznacza spadek wydajności całego zapytania zadawanego do Solr.</p>
<p>W przypadku tej metody facetingu warto wspomnieć, iż istnieje  możliwość zdefiniowania własnego parsera, który ma być użyty do  przetworzenia zapytania przekazanego za pomocą parametru <em>facet.query</em>. Aby skorzystać na przykład z parsera o nazwie <em>myParser</em> przekazany parametr powinien wyglądać następująco:
</p>
<pre class="brush:xml">facet.query={!myParser}aaa.</pre>
<h3>Faceting po datach</h3>
<p>W wersji 1.3 Solr pojawiła się nowa funkcjonalność &#8211; faceting po  datach. Pozwala na wyliczanie wyników facetingu z uwzględnieniem  wszystkich zawiłości związanych z przetwarzaniem dat. Należy pamiętać,  iż faceting po datach może być tylko wykorzystywany z polami opartymi o  typ <em>solr.DateField</em>. Przejdźmy więc do opisania parametrów związanych z facetingiem po datach:</p>
<ul>
<li><em>facet.date </em>&#8211; podobnie jak parametr <em>facet.field</em> parametr ten służy do określenia pól, w których ma być przeprowadzany faceting po datach. Podobnie jak w przypadku parametru <em>facet.field</em> możliwe jest podanie tego parametru wielokrotnie, aby umożliwić faceting po datach na wielu polach w ramach jednego zapytania.</li>
<li><em>facet.date.start </em>&#8211;  parametr określający dolną granicę daty, czyli od której daty ma być  rozpoczęte wyliczanie facetingu. Parametr może być definiowany dla  poszczególnych pól przekazanych w parametrze <em>facet.date</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.date</em>.</li>
<li><em>facet.date.end</em> &#8211; parametr określający górną granicę daty, czyli do której daty ma być  zakończone wyliczanie facetingu. Parametr może być definiowany dla  poszczególnych pól przekazanych w parametrze <em>facet.date</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.date</em>.</li>
<li><em>facet.date.gap </em>&#8211;  parametr określający przedziały dat, jakie mają być generowane dla  zdefiniowanych granic. Parametr może być definiowany dla poszczególnych  pól przekazanych w parametrze <em>facet.date</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.date</em>.</li>
<li><em>facet.date.hardend</em> &#8211; parametr przyjmujący wartości <em>true</em> oraz <em>false</em>, określający co Solr ma zrobić w przypadku kiedy parametr <em>facet.date.gap</em> nie podzieli równo przedziałów pomiędzy zdefiniowanym początkiem, a końcem. Jeżeli ustawimy ten parametr na wartość <em>true</em> ostatni przedział może być większy od podanego w parametrze <em>facet.date.end</em> końca. W przypadku ustawienia na wartość <em>false</em> (która jest wartością domyślną) ostatni przedział dat może być mniejszy  od pozostałych. Parametr może być definiowany dla poszczególnych pól  przekazanych w parametrze <em>facet.date</em>.</li>
<li><em>facet.date.other</em> &#8211; parametr określający jakie wartości oprócz tych wyliczonych dla  określonych przedziałów mają być zawarte w wynikach facetingu. Parametr  może być definiowany dla poszczególnych pól przekazanych w parametrze <em>facet.date</em>. Parametr może przyjmować następujące wartości:
<ul>
<li><em>before</em> &#8211; oprócz przedziałów wyniki facetingu będą  zawierać wyliczenia ilości dla dat mieszczących się przed granicą  zdefiniowaną w parametrze <em>facet.date.start,</em></li>
<li><em>after </em>&#8211;  oprócz przedziałów wyniki facetingu będą zawierać wyliczenia ilości dla  dat mieszczących się za granicą zdefiniowaną w parametrze <em>facet.date.end,</em></li>
<li><em>between</em> &#8211; do wyników facetingu po datach zostanie dołączona informacja o licznościach w przedziale zdefiniowanym przez parametry <em>facet.date.start</em> oraz <em>facet.date.end,</em></li>
<li><em>all </em>&#8211; skrót określający, że dla danego pola mają zostać dodane trzy powyższe opcje,</li>
<li><em>none &#8211;</em> wartość określająca, iż żadna dodatkowa informacja ma nie być dołączona do wyników facetingu.</li>
</ul>
</li>
<li><em>facet.date.include</em> &#8211; parametr, który zostanie  wprowadzony w Solr 4.0. Parametr pozwala na domykanie, bądź otwieranie  przedziałów zdefiniowanych przy pomocy parametrów <em>facet.date.start</em> oraz <em>facet.date.end</em>. Parametr będzie przyjmował następujące wartości:
<ul>
<li><em>lower </em>&#8211; każdy z powstałych przedziałów będzie zawierał swoją dolną granicę,</li>
<li><em>upper</em> &#8211; każdy z powstałych przedziałów będzie zawierał swoją górną granicę,</li>
<li><em>egde</em> &#8211; pierwszy i ostatni przedział będą zawierały swoje zewnętrzne granice &#8211;  czyli dolną dla pierwszego przedziału i górną dla ostatniego  przedziału,</li>
<li><em>outer</em> &#8211; parametr określający, iż przedziały zdefiniowane przez wartości <em>before</em> i <em>after</em> parametru <em>facet.date.other</em> będą zawierały swoje granice, nawet jeżeli inne przedziały zawierają już te granice,</li>
<li><em>all</em> &#8211; parametr powodujący włączenie czterech powyższych opcji.</li>
</ul>
</li>
</ul>
<p>Tak przedstawiają się opcje facetingu po datach. Poniżej przykład wykorzystania tego rodzaju facetingu:
</p>
<pre class="brush:xml">q=solr&amp;facet=true&amp;facet.date=addDate&amp;facet.date.start=NOW/DAY-30DAYS&amp;facet.date.end=NOW/DAY%2B30DAYS&amp;facet.date.gap=%2B1DAY</pre>
<p>Zajmijmy się facetingiem w tym zapytaniu &#8211; faceting po datach po polu o nazwie <em>addDate</em>.  Jako dolną granicę ustawiamy datę o 30 dni wcześniejszą niż obecna,  górna granica to data o 30 dni później, niż w chwili zadawania  zapytania. Przedziały mają być wielkości jednego dnia.</p>
<h3>Faceting po przedziałach</h3>
<p>Funkcjonalność która dostępna będzie w Solr 3.1. Jeżeli ktoś chce już  teraz ją testować, to zarówno trunk, jak i branch 3.x mają tą  funkcjonalność zaimplementowaną. Ta metoda facetingu powstała jako  rozszerzenie pomysłu facetingu po datach. Funkcjonalność działa  analogicznie do facetingu po datach, czyli w wyniku działania dostajemy  listę przedziałów skonstruowanych automatycznie na podstawie parametrów.  Lista parametrów, jakie charakteryzują działanie mechanizmu:</p>
<ul>
<li><em>facet.range </em>&#8211; parametr określający po jakich polach ma  być przeprowadzony faceting po przedziałach. Parametr może być  przekazywany wielokrotnie.</li>
<li><em>facet.range.start </em>&#8211;  parametr określający dolną granicę przedziałów, czyli wartość od której  ma być  rozpoczęte wyliczanie facetingu. Parametr może być definiowany  dla  poszczególnych pól przekazanych w parametrze <em>facet.range</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.range</em>.</li>
<li><em>facet.range.end</em> &#8211; parametr określający dolną granicę przedziałów, czyli wartość na  której ma być skończone wyliczanie facetingu. Parametr może być  definiowany  dla  poszczególnych pól przekazanych w parametrze <em>facet.range</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.range</em>.</li>
<li><em>facet.range.gap</em> &#8211; parametr określający wielkość przedziałów, jakie mają być generowane  dla  zdefiniowanych granic. Parametr może być definiowany dla  poszczególnych  pól przekazanych w parametrze <em>facet.range</em>. Parametr ten jest wymagany w przypadku korzystania z parametru <em>facet.range</em>.</li>
<li><em>facet.range.hardend</em> &#8211; parametr przyjmujący wartości <em>true</em> oraz <em>false</em>, określający co Solr ma zrobić w przypadku kiedy parametr <em>facet.range.gap</em> nie podzieli równo przedziałów pomiędzy zdefiniowanym początkiem, a końcem. Jeżeli ustawimy ten parametr na wartość <em>true</em> ostatni przedział może być większy od podanego w parametrze <em>facet.range.end</em> końca. W przypadku ustawienia na wartość <em>false</em> (która jest wartością domyślną) ostatni przedział może być mniejszy  od  pozostałych. Parametr może być definiowany dla poszczególnych pól   przekazanych w parametrze <em>facet.range</em>.</li>
<li><em>facet.range.other</em> &#8211; parametr określający jakie wartości oprócz tych wyliczonych dla   określonych przedziałów mają być zawarte w wynikach facetingu. Parametr   może być definiowany dla poszczególnych pól przekazanych w parametrze <em>facet.range</em>. Parametr może przyjmować następujące wartości:
<ul>
<li><em>before</em> &#8211; oprócz przedziałów wyniki facetingu będą  zawierać wyliczenia ilości dla przedziału mieszczących się przed granicą  zdefiniowaną w parametrze <em>facet.range.start,</em></li>
</ul>
<ul>
<li><em>after </em>&#8211; oprócz przedziałów wyniki facetingu będą  zawierać  wyliczenia ilości dla przedziału mieszczących się za granicą  zdefiniowaną w  parametrze <em>facet.range.end,</em></li>
</ul>
<ul>
<li><em>between</em> &#8211; do wyników facetingu po rozdziałach zostanie dołączona informacja o licznościach w przedziale zdefiniowanym przez parametry <em>facet.range.start</em> oraz <em>facet.range.end,</em></li>
</ul>
<ul>
<li><em>all </em>&#8211; skrót określający, że dla danego pola mają zostać dodane trzy powyższe opcje,</li>
<li><em>none &#8211;</em> wartość określająca, iż żadna dodatkowa informacja ma nie być dołączona do wyników facetingu po przedziałach.</li>
</ul>
</li>
<li><em>facet.range.include </em>&#8211; parametr pozwala na  domykanie, bądź otwieranie przedziałów zdefiniowanych przy pomocy  parametrów <em>facet.range.start</em> oraz <em>facet.range.end</em>. Parametr przyjmuje następujące wartości:
<ul>
<li><em>lower </em>&#8211; każdy z powstałych przedziałów będzie zawierał swoją dolną granicę,</li>
<li><em>upper</em> &#8211; każdy z powstałych przedziałów będzie zawierał swoją górną granicę,</li>
<li><em>egde</em> &#8211; pierwszy i ostatni przedział będą zawierały swoje  zewnętrzne granice  &#8211; czyli dolną dla pierwszego przedziału i górną dla  ostatniego  przedziału,</li>
<li><em>outer</em> &#8211; parametr określający, iż przedziały zdefiniowane przez wartości <em>before</em> i <em>after</em> parametru <em>facet.date.other</em> będą zawierały swoje granice, nawet jeżeli inne przedziały zawierają już te granice,</li>
<li><em>all</em> &#8211; parametr powodujący włączenie czterech powyższych opcji.</li>
</ul>
</li>
</ul>
<p>Jak widać parametry facetingu po przedziałach są prawie identyczne,  jak w przypadku facetingu po datach. Działanie jest także analogiczne.  Przykładem zapytania z wykorzystaniem facetingu po datach może być  następujące zapytanie:
</p>
<pre class="brush:xml">q=solr&amp;facet=true&amp;facet.range=price&amp;facet.range.start=0&amp;facet.range.end=1000&amp;facet.range.gap=100</pre>
<p>Tak przeszliśmy przez wszystkie rodzaje facetingu. Jednak to jeszcze  nie wszystko. Użytkownicy Solr w wersji 1.4 i wyższych mają możliwość  korzystania z tzw. <em>LocalParams</em> wraz z facetingiem.</p>
<h3>LocalParams i faceting</h3>
<p>Załóżmy takie wymaganie. Mamy zapytanie, które zwraca wyniki wyszukiwania dla słowa <em>solr</em> oraz, które ma zdefiniowane dwa filtry jeden dla kategorii, a drugi dla  kraju z którego pochodzi dokument. Oprócz wyników wyszukiwania chcemy  umożliwić, w ramach wyników wyszukiwania, nawigację po regionach oraz po  kategoriach, ale chcielibyśmy, aby liczności nie były od siebie  zależne. To znaczy chcielibyśmy dać możliwość nawigacji po regionach dla  słowa <em>solr</em>, ale nie zawężonych do wybranej kategorii, oraz po  kategorii, ale nie zawężonej do wybranego regionu. Żeby zrobić to w Solr  w wersji 1.3 lub wcześniejszej, należałoby napisać następujące  zapytania:
</p>
<pre class="brush:xml">q=solr&amp;fq=category:search&amp;fq=region:poland
q=solr&amp;facet=true&amp;facet.field=category&amp;facet.field=region</pre>
<p>Dwa zapytania dlatego, że po pierwsze musimy pobrać zawężone wyniki  wyszukiwania, a z drugiej strony potrzebujemy niezawężonych wyników  wyszukiwania po to, aby pobrać wymagane liczności za pomocą facetingu.</p>
<p>W przypadku Solr w wersji 1.4 lub wyższej mamy możliwość skrócenia  tego do jednego zapytania. Do tego celu wykorzystamy możliwość tagowania  i wykluczania tagowanych parametrów. Pierwsze zapytanie zmieniamy w  następujący sposób:
</p>
<pre class="brush:xml">q=solr&amp;fq={!tag=categoryFQ}fq=category:search&amp;fq={!tag=regionFQ}region:poland</pre>
<p>Na razie wyniki wyszukiwania się nie zmienią. Do powyższego zapytania  zostały dodane tagi nadające nazwę każdemu z wykorzystywanych filtrów  po to, abyśmy mogli wykluczyć je w facetingu.</p>
<p>Drugie zapytanie modyfikujemy w następujący sposób:
</p>
<pre class="brush:xml">q=solr&amp;facet=true&amp;facet.field={!ex=categoryFQ,regionFQ}category&amp;facet.field={!ex=categoryFQ,regionFQ}region</pre>
<p>Tutaj także na razie wyniki facetingu nie uległy zmianie. Dodaliśmy  do facetingu wykluczenia, które mówią o tym, że filtry o nazwach <em>categoryFQ</em> oraz <em>regionFQ</em> mają nie być brane pod uwagę przy wyliczaniu wyników facetingu.</p>
<p>Tak zmodyfikowane zapytanie łączymy w jedno, które powinno wyglądać następująco:
</p>
<pre class="brush:xml">q=solr&amp;fq={!tag=categoryFQ}fq=category:search&amp;fq={!tag=regionFQ}region:poland&amp;facet=true&amp;facet.field={!ex=categoryFQ,regionFQ}category&amp;facet.field={!ex=categoryFQ,regionFQ}region</pre>
<p>Więcej o <em>LocalParams</em> napiszę w jednym z kolejnych wpisów.</p>
<h3>Kilka słów na koniec</h3>
<p>Mam nadzieję, że tym artykułem przybliżyłem możliwości wykorzystania  facetingu w Solr, zarówno w starszych wersjach, w tej obecnej, jak i  tych, które pojawią się w przyszłości.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2010/08/23/mozliwosc-facetingu-w-solr/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>6 grzechów głównych w kontekście zadawania zapytań</title>
		<link>https://solr.pl/2010/08/11/6-grzechow-glownych-w-kontekscie-zadawania-zapytan/</link>
					<comments>https://solr.pl/2010/08/11/6-grzechow-glownych-w-kontekscie-zadawania-zapytan/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Wed, 11 Aug 2010 13:16:08 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[facet]]></category>
		<category><![CDATA[facet.limit]]></category>
		<category><![CDATA[facet.offset]]></category>
		<category><![CDATA[jak nie zadawać zapytań]]></category>
		<category><![CDATA[jak zadawać zapytania]]></category>
		<category><![CDATA[poprawne zapytania]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[zapytania]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=22</guid>

					<description><![CDATA[W swojej dotychczasowej pracy związanej z Lucene i Solr spotkałem się z różnymi zapytaniami. O ile w przypadku Lucene programista z reguły wie co chce osiągnąć i zastanawia się nad optymalnym rozwiązaniem, o tyle w przypadku Solr już tak nie]]></description>
										<content:encoded><![CDATA[<p>W swojej dotychczasowej pracy związanej z Lucene i Solr spotkałem się z różnymi zapytaniami. O ile w przypadku Lucene programista z reguły wie co chce osiągnąć i zastanawia się nad optymalnym rozwiązaniem, o tyle w przypadku Solr już tak nie jest. Solr jest produktem z którego teoretycznie może skorzystać każdy, zarówno osoba nie znająca języka Java, taka, która nie posiada szerokiej i specjalistycznej wiedzy technicznej, jak również programista. Właśnie ze względu na to, że Solr jest produktem, który bardzo łatwo uruchomić i z niego skorzystać, wiele osób nie zadaje sobie trudu związanego z przeczytaniem dokumentacji, czy przejrzeniem listy dyskusyjnej użytkowników. Co za tym idzie, ludzie Ci, wcześniej czy później popełniają błędy &#8211; błędy wynikające z różnych braków &#8211; braku wiedzy na temat Solr, umiejętności, doświadczenia, czy ze zwykłego braku czasu i napiętych terminów. Chciałbym dzisiaj przedstawić kilka podstawowych błędów przy składaniu zapytań i jak ich uniknąć.</p>
<p><span id="more-22"></span></p>
<h3>1. Brak wykorzystania filtrów</h3>
<p>Jednym z podstawowych błędów jakie spotykam co jakiś czas jest brak wykorzystania filtrów, czyli prosto mówiąc brak wykorzystania parametru <em>fq </em>w zapytaniach. Pamiętajmy o tym, filtry to nasi przyjaciele <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;" /> Dzięki filtrom cache wykorzystywany jest bardziej optymalnie. Filtry nie wpływają na ważność dokumentu w kontekście zapytania (współczynnik <em>score</em>), a co za tym idzie, możemy wykonywać zawężania bez obawy o zmianę wartości <em>score</em> poszczególnych dokumentów (przydatne np. w sklepach e-commerce w przypadku zawężania grup produktów).</p>
<h3>2. Warunki logiczne i parametr q</h3>
<p>Kolejny z &#8222;grzechów&#8221; jakie spotykam dość często, dość mocno związany z poprzednim punktem. Nie jest to może błąd w dosłownym tego słowa znaczeniu, aczkolwiek, jest to obszar, gdzie prosta zmiana będzie miała spory wpływ na wydajność. Zakładając, że domyślnym operatorem logicznym jest <em>OR</em>, wyobraźmy sobie zapytanie w postaci <code>q=(java+wzorce+projektowe)+AND+kategoria:ksiazki+AND+promocja:true+AND+wydawnictwo:ABC</code>. Zapytanie to jest jak najbardziej poprawne z punktu widzenia logiki aplikacji, gdzie mamy dostać odpowiednią grupę wyników wyszukiwania. Co jednak, jeżeli chcemy, aby także optymalnie wykorzystywało cache Solr, a tym samym wykonywało się szybciej. Odpowiedź jest dość prosta &#8211; należy przenieść niektóre z warunków do filtrów. Zmieniając przedstawione zapytanie na<code> q=java+wzrce+projektowe&amp;fq=kategoria:ksiazki&amp;fq=promocja:true&amp;fq=wydawnictwo:ABC</code> Solr skorzysta z dwóch rodzajów cache &#8211; <em>queryDocumentCache </em>w celu pobrania dokumentów dla zapytania z parametru <em>q</em> oraz z <em>filterCache </em>dla każdego z filtrów. Zmiana zapytania w pokazany sposób pozwoliła na wykorzystanie dodatkowego cache oraz na uporządkowanie wpisów w <em>queryDocumentCache </em>(ze względu na skrócenie zapytania w parametrze <em>q</em>).</p>
<h3>3. Ogromne ilości facet query</h3>
<p>Kolejny &#8222;grzech&#8221; związany z obsługą grup dokumentów. Dość często, szczególnie, w przypadku aplikacji które mają dużą ilość parametrów pozwalających kategoryzować produkty spotykałem zapytania z dużą ilością parametrów <em>facet.query</em>. Zapytania te używane były do wyświetlania grup dokumentów &#8211; według ceny, lokalizacji, grup i tak dalej. Dobrym przykładem jest grupowanie po cenie, gdzie klient biznesowy może określać przedziały cenowe dla poszczególnych kategorii i na tym podstawie grupować produkty. Pamiętajmy, że dołożenie do zapytania 100, czy 200 razy parametru <em>facet.query</em> odbija się na wydajności i to czasami dość znacznie. Jeżeli interesuje nas szybka reakcja Solr nie możemy stosować takich zapytań. W takich wypadkach zawsze proponuję modyfikację struktury indeksu, czyli stworzenie odpowiednich przedziałów w importerze aplikacji i przekazywanie do Solr identyfikatorów tych przedziałów, które tłumaczy aplikacja. Pozwala to na zlikwidowanie dziesiątek, czy setek <em>facet.query</em> na rzecz jednego parametru facet, po odpowiednim polu (oczywiście w przykładzie z grupami zależnymi od kategorii mogą to być pola dynamiczne). Wiąże się z jeszcze jedną niedogodnością &#8211; wytłumaczeniem klientowi, dlaczego musi nacisnąć przycisk reindeksacji danych po zmianach przedziałów. Z reguły jednak testy wydajnościowe przy dużym obciążeniu i dużej różnorodności zapytań mówią same za siebie.</p>
<h3>4. Limity facetingu</h3>
<p>Problem pojawiający się na styku zapytań zadawanych do Solr, a logiki biznesowej jaką realizować ma aplikacja korzystająca z Solr. Przykładem tego &#8222;grzechu&#8221; jest prosta lista kategorii, którą klient chce mieć wyświetlaną w zależności od strony na jakiej znajduje się użytkownik. Kiedy kategorii jest mało nie mamy problemu, gorzej kiedy tych kategorii jest bardzo dużo. Bardzo często spotykałem się z podejściem ze strony programistów, aby pobierać wszystkie kategorie z Solr (z mocno zwiększonym w stosunku do domyślnego parametrem <em>facet.limit</em>) i dopiero w aplikacji zawężać te wyniki. Według mnie jest to podejście, które może generować problemy &#8211; po pierwsze faceting wymaga pamięci, po drugie czasu na przetworzenie i agregację wyników. Co więcej, pobranie wszystkich 50.000 kategorii wraz z licznościami może być bolesne dla Solr. Jeżeli zależy nam na szybkich zapytaniach, starajmy się korzystać z parametru facet.limit rozsądnie i ewentualnie tak budować aplikację, aby możliwe było stronicowanie wyników facetingu i korzystanie tym samym z parametru <em>facet.offset</em>. Jeżeli nie jest to możliwe, to przynajmniej skonfigurujmy tak kontener w którym działa Solr, aby miał wystarczającą ilość pamięci, aby obsłużyć równoległe zapytania i przygotujmy się, że zapytania z dużą wartością <em>facet.limit</em> mogą wykonywać się dłużej, niż inne.</p>
<h3>5. Pobieranie niepotrzebnych danych</h3>
<p>Bardzo często spotykanym problemem jest pobieranie wszystkich informacji, a nie tylko tych, które są nam potrzebne. Oczywiście problem nie dotyczy wdrożeń, gdzie Solr serwuje informacje takie jak na przykład identyfikator produktu i tylko identyfikator. Jednak, duża ilość wdrożeń z którą miałem do czynienia opierała się prawie w całości na Solr, a co za tym idzie indeks składał się z wielu pól z atrybutem <em>stored</em> ustawionym na wartość <em>true</em>. Programiści korzystający z Solr bardzo rzadko korzystali z parametru<em> fl</em> oraz możliwości ograniczania pól, które są zwracane odpowiedzi. W ekstremalnych przypadkach prowadziło to do problemów z ilością danych, jakie trzeba było przesyłać przez sieć.</p>
<h3>6. Wiele zapytań do uzyskania liczności grup dokumentów</h3>
<p>W niektórych wdrożeniach ważniejsze od standardowego wyszukiwania, gdzie użytkownik wpisuje frazę jaką chce znaleźć, jest przechodzenie do dokumentów za pomocą nawigacji, na przykład przy pomocy działów, kategorii, podkategorii i tak dalej. Bardzo często oprócz na przykład nazwa kategorii podaje się także informacje takie jak ilość dokumentów w tej kategorii, czyli np. produktów. Spotkałem się z przypadkami, gdzie ilości dokumentów w poszczególnych kategoriach były pobierane za pomocą oddzielnych zapytań. Skutek &#8211; wyświetlenie 100 kategorii na formatce skutkowało taką samą ilością zapytań do Solr. Nie róbmy tego &#8211; jeżeli trzeba zmodyfikujmy indeks Solr tak, aby możliwe było wykorzystanie mechanizmów facetingu. Może w danym momencie będzie to więcej pracy, ale na pewno w dłuższej perspektywie czasu się to opłaci.</p>
<h3>Kilka słów na koniec</h3>
<p>Należy pamiętać, że są to tylko przykłady, które uważam za dość powszechne, a przynajmniej na które dość często natknąłem się podczas pracy. Nie są to na pewno wszystkie błędy popełniane przy korzystaniu z Solr, jednak mam nadzieję, że przynajmniej w pewnym stopniu uwypuklają stronę w którą należy spoglądać generując zapytania do Solr, czy optymalizując już istniejące.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2010/08/11/6-grzechow-glownych-w-kontekscie-zadawania-zapytan/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
