<?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>howto &#8211; Solr.pl</title>
	<atom:link href="https://solr.pl/tag/howto/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 08:15:24 +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>Aplikacja &#8222;sprzedaż samochodów&#8221; – Spatial Search, czyli wprowadzenie danych lokalizacyjnych (cz. 3)</title>
		<link>https://solr.pl/2011/03/14/aplikacja-sprzedaz-samochodow-spatial-search-czyli-wprowadzenie-danych-lokalizacyjnych-cz-3/</link>
					<comments>https://solr.pl/2011/03/14/aplikacja-sprzedaz-samochodow-spatial-search-czyli-wprowadzenie-danych-lokalizacyjnych-cz-3/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Andrzejewski]]></dc:creator>
		<pubDate>Mon, 14 Mar 2011 08:13:38 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[schema]]></category>
		<category><![CDATA[solr]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=207</guid>

					<description><![CDATA[Ilość ogłoszeń w naszej bazie rozrosła się do tego stopnia, że klienci zaproponowali dodanie nowej opcji przy filtrowaniu wyników wyszukiwania oraz nowej opcji sortowania. Mianowicie musimy dodać funkcjonalność, która pozwoli nam operować na danych związanych z lokalizacją auta w danym]]></description>
										<content:encoded><![CDATA[<p lang="pl-PL">Ilość ogłoszeń w naszej bazie rozrosła się do tego stopnia, że klienci zaproponowali dodanie nowej opcji przy filtrowaniu wyników wyszukiwania oraz nowej opcji sortowania. Mianowicie musimy dodać funkcjonalność, która pozwoli nam operować na danych związanych z lokalizacją auta w danym ogłoszeniu.</p>
<p><span id="more-207"></span></p>
<h2>Analiza wymagań</h2>
<p lang="pl-PL">Chcemy dodać dwie nowe funkcjonalności:</p>
<ol>
<li>Zawężanie wyników wyszukiwania w taki sposób, aby możliwe było wyświetlenie tylko tych aut, które są położone nie dalej niż x kilometrów od określonego miejsca, gdzie x = 50,100,200,500,1000 km.</li>
<li>Sortowanie wyników wyszukiwania po odległości pomiędzy danym punktem, a lokalizacją auta z danego ogłoszenia.</li>
</ol>
<p lang="pl-PL">W celu realizacji powyższych zadań, skorzystamy z funkcjonalności solr zwanej &#8222;Spatial Search&#8221;, która dostępna jest od wersji 3.1. Zmiany, które będziemy musieli wprowadzić, dotyczyć będą modyfikacji pliku schema.xml oraz danych wejściowych, do których dodamy informację o położeniu geograficznym każdego z aut. Na końcu zostanie nam już tylko odpowiednie złożenie zapytań.</p>
<p lang="pl-PL">
<h2>Zmiany w schema.xml</h2>
<ol>
<li>Definicja nowych typów pól:
<ul>
<li>pierwsza definicja to nic innego jak kolejny typ liczbowy &#8211; double:</li>
<pre class="brush:xml">&lt;fieldType name="tdouble" precisionStep="8" omitNorms="true" positionIncrementGap="0"/&gt;</pre>
<li> druga definicja zaś wykorzystuje specjalną klasę &#8222;solr.LatLonType&#8221;, która pozwoli nam na zaindeksowanie danych geograficznych wykorzystując pole dynamiczne o suffixie &#8222;_coordinate&#8221;:</li>
<pre class="brush:xml">&lt;fieldType name="location" subFieldSuffix="_coordinate"/&gt;</pre>
</ul>
</li>
<li>Definicja &nbsp;nowych pól:
<ul>
<li>pole, które będzie wykorzystywane do gromadzenia informacji o nazwie miejscowości, z którego pochodzi auto:</li>
<pre class="brush:xml">&lt;field name="city" type="string" indexed="true" stored="true" /&gt;</pre>
<li>pole &#8222;loc&#8221; posłuży nam do zaindeksowania danych lokalizacyjnych:</li>
<pre class="brush:xml">&lt;field name="loc" type="location" indexed="true" stored="false"/&gt;</pre>
<li>pole dynamiczne będzie wykorzystywane wewnętrznie do gromadzenia informacji, które wprowadzimy do pola &#8222;loc&#8221;:</li>
<pre class="brush:xml">&lt;dynamicField name="*_coordinate"  type="tdouble" indexed="true" stored="false"/&gt;</pre>
</ul>
</li>
</ol>
<h2>Analiza danych wejściowych</h2>
<p lang="pl-PL">W celu prezentacji sposobu modyfikacji nowych danych, weźmy próbkę 5-ciu ogłoszeń z miast:</p>
<ol>
<li>Koszalin
<ul>
<li><em>szerokość geograficzna</em>: 54.12</li>
<li><em>długość geograficzna</em>: 16.11</li>
</ul>
</li>
<li>Białystok
<ul>
<li><em>szerokość geograficzna</em>: 53.08</li>
<li><em>długość geograficzna</em>: 23.09</li>
</ul>
</li>
<li>Szczecin
<ul>
<li><em>szerokość geograficzna</em>: 53.25</li>
<li><em>długość geograficzna</em>: 14.35</li>
</ul>
</li>
<li>Gdańsk
<ul>
<li><em>szerokość geograficzna</em>: 54.21</li>
<li><em>długość geograficzna</em>: 18.40</li>
</ul>
</li>
<li>Warszawa
<ul>
<li><em>szerokość geograficzna</em>: 52.15</li>
<li><em>długość geograficzna</em>: 21.00</li>
</ul>
</li>
</ol>
<p lang="pl-PL">Dane lokalizacyjne wprowadzamy do pola &#8222;loc&#8221; wpisując szerokość geograficzną danego miasta oraz po przecinku jego długość. Nasze dane mogą wyglądać zatem tak:</p>
<pre class="brush:xml">&lt;add&gt;
   &lt;doc&gt;
      &lt;field name="id"&gt;1&lt;/field&gt;
      &lt;field name="make"&gt;Audi&lt;/field&gt;
      &lt;field name="model"&gt;80&lt;/field&gt;
      &lt;field name="year"&gt;2008&lt;/field&gt;
      &lt;field name="price"&gt;9774&lt;/field&gt;
      &lt;field name="engine_size"&gt;2000&lt;/field&gt;
      &lt;field name="mileage"&gt;92467&lt;/field&gt;
      &lt;field name="colour"&gt;green&lt;/field&gt;
      &lt;field name="damaged"&gt;false&lt;/field&gt;
      &lt;field name="city"&gt;Koszalin&lt;/field&gt;
      &lt;field name="loc"&gt;54.12,16.11&lt;/field&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;field name="id"&gt;2&lt;/field&gt;
      &lt;field name="make"&gt;Audi&lt;/field&gt;
      &lt;field name="model"&gt;A8&lt;/field&gt;
      &lt;field name="year"&gt;2009&lt;/field&gt;
      &lt;field name="price"&gt;9078&lt;/field&gt;
      &lt;field name="engine_size"&gt;1000&lt;/field&gt;
      &lt;field name="mileage"&gt;31369&lt;/field&gt;
      &lt;field name="colour"&gt;black&lt;/field&gt;
      &lt;field name="damaged"&gt;false&lt;/field&gt;
      &lt;field name="city"&gt;Białystok&lt;/field&gt;
      &lt;field name="loc"&gt;53.08,23.09&lt;/field&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;field name="id"&gt;3&lt;/field&gt;
      &lt;field name="make"&gt;Audi&lt;/field&gt;
      &lt;field name="model"&gt;TT&lt;/field&gt;
      &lt;field name="year"&gt;1997&lt;/field&gt;
      &lt;field name="price"&gt;1109&lt;/field&gt;
      &lt;field name="engine_size"&gt;1299&lt;/field&gt;
      &lt;field name="mileage"&gt;116987&lt;/field&gt;
      &lt;field name="colour"&gt;silver&lt;/field&gt;
      &lt;field name="damaged"&gt;true&lt;/field&gt;
      &lt;field name="city"&gt;Szczecin&lt;/field&gt;
      &lt;field name="loc"&gt;53.25,14.35&lt;/field&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;field name="id"&gt;4&lt;/field&gt;
      &lt;field name="make"&gt;BMW&lt;/field&gt;
      &lt;field name="model"&gt;Seria 7&lt;/field&gt;
      &lt;field name="year"&gt;2007&lt;/field&gt;
      &lt;field name="price"&gt;140000&lt;/field&gt;
      &lt;field name="engine_size"&gt;3000&lt;/field&gt;
      &lt;field name="mileage"&gt;418000&lt;/field&gt;
      &lt;field name="colour"&gt;green&lt;/field&gt;
      &lt;field name="damaged"&gt;false&lt;/field&gt;
      &lt;field name="city"&gt;Gdańsk&lt;/field&gt;
      &lt;field name="loc"&gt;54.21,18.40&lt;/field&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;field name="id"&gt;5&lt;/field&gt;
      &lt;field name="make"&gt;Chevrolet&lt;/field&gt;
      &lt;field name="model"&gt;TrailBlazer&lt;/field&gt;
      &lt;field name="year"&gt;2007&lt;/field&gt;
      &lt;field name="price"&gt;140000&lt;/field&gt;
      &lt;field name="engine_size"&gt;3000&lt;/field&gt;
      &lt;field name="mileage"&gt;418000&lt;/field&gt;
      &lt;field name="colour"&gt;green&lt;/field&gt;
      &lt;field name="damaged"&gt;false&lt;/field&gt;
      &lt;field name="city"&gt;Warszawa&lt;/field&gt;
      &lt;field name="loc"&gt;52.15,21.00&lt;/field&gt;
   &lt;/doc&gt;
&lt;/add&gt;</pre>
<h2>Tworzymy zapytania</h2>
<p lang="pl-PL">Dane lokalizacyjne mamy w indeksie, zatem zostało nam już tylko złożyć odpowiednie zapytania, które zrealizują nasze nowe funkcjonalności. Załóżmy, że będziemy wyszukiwać ogłoszenia znajdując się w mieście Białystok, które jest położone w odległości ok. 200 km od miasta Warszawa, ok. 400 km od miasta Gdańsk, ok. 550 km od miasta Koszalin oraz ok. 650 km od miasta Szczecin.</p>
<p lang="pl-PL">W celu realizacji punktu 1 z analizy wymagań, dodajemy do żądania nowe zapytanie filtrujące:</p>
<p lang="pl-PL">
<pre class="brush:xml">...&amp;fq={!geofilt sfield=loc}&amp;pt=53.08,23.09&amp;d=50</pre>
<p lang="pl-PL">gdzie:</p>
<ul>
<li><em>sfield</em> &#8211; nazwa pola, do którego wprowadzaliśmy nasze dane lokalizacyjne.</li>
<li><em>pt</em> &#8211; współrzędne punktu startowego, w naszym wypadku są to współrzędne miasta Białystok.</li>
<li><em>d</em> &#8211; dystans o jaki chcemy zawęzić wyniki wyszukiwania. Podstawiając kolejno wartości 50,100,200,500,1000 możemy zrealizować nasze wymagania.</li>
</ul>
<p lang="pl-PL">Przykład:</p>
<ol>
<li>Zapytanie:
<pre class="brush:xml">q=*:*&amp;fq={!geofilt sfield=loc}&amp;pt=53.08,23.09&amp;d=200</pre>
</li>
<li>Wyniki wyszukiwania:</li>
<pre class="brush:xml">&lt;result name="response" numFound="2" start="0"&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Białystok&lt;/str&gt;
      &lt;str name="colour"&gt;black&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;1000&lt;/int&gt;
      &lt;str name="id"&gt;2&lt;/str&gt;
      &lt;str name="make"&gt;Audi&lt;/str&gt;
      &lt;int name="mileage"&gt;31369&lt;/int&gt;
      &lt;str name="model"&gt;A8&lt;/str&gt;
      &lt;float name="price"&gt;9078.0&lt;/float&gt;
      &lt;int name="year"&gt;2009&lt;/int&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Warszawa&lt;/str&gt;
      &lt;str name="colour"&gt;green&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;3000&lt;/int&gt;
      &lt;str name="id"&gt;5&lt;/str&gt;
      &lt;str name="make"&gt;Chevrolet &lt;/str&gt;
      &lt;int name="mileage"&gt;418000&lt;/int&gt;
      &lt;str name="model"&gt;TrailBlazer&lt;/str&gt;
      &lt;float name="price"&gt;140000.0&lt;/float&gt;
      &lt;int name="year"&gt;2007&lt;/int&gt;
   &lt;/doc&gt;
&lt;/result&gt;</pre>
</ol>
<p lang="pl-PL">Świetnie, w wynikach nie mamy ogłoszeń z miast Koszalin, Gdańsk oraz Szczecin, gdyż te miasta leżą w odległości ponad 200 km od miasta Białystok.</p>
<p lang="pl-PL">W celu realizacji punktu 2 z analizy wymagań, wykorzystamy możliwość sortowania wyników wyszukiwania z użyciem funkcji geodist. Tworzymy następujące zapytanie:</p>
<p lang="pl-PL">
<pre class="brush:xml">...&amp;sfield=loc&amp;pt=53.08,23.09&amp;sort=geodist()+desc</pre>
<p lang="pl-PL">Przykład sortowania wyników wyszukiwania po odległości, rozpoczynając od miasta Białystok:</p>
<ol>
<li>Zapytanie:
<pre class="brush:xml">q=*:*&amp;sfield=loc&amp;pt=53.08,23.09&amp;sort=geodist()+asc</pre>
</li>
<li>Wyniki wyszukiwania:</li>
<pre class="brush:xml">&lt;result name="response" numFound="5" start="0"&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Białystok&lt;/str&gt;
      &lt;str name="colour"&gt;black&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;1000&lt;/int&gt;
      &lt;str name="id"&gt;2&lt;/str&gt;
      &lt;str name="make"&gt;Audi&lt;/str&gt;
      &lt;int name="mileage"&gt;31369&lt;/int&gt;
      &lt;str name="model"&gt;A8&lt;/str&gt;
      &lt;float name="price"&gt;9078.0&lt;/float&gt;
      &lt;int name="year"&gt;2009&lt;/int&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Warszawa&lt;/str&gt;
      &lt;str name="colour"&gt;green&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;3000&lt;/int&gt;
      &lt;str name="id"&gt;5&lt;/str&gt;
      &lt;str name="make"&gt;Chevrolet &lt;/str&gt;
      &lt;int name="mileage"&gt;418000&lt;/int&gt;
      &lt;str name="model"&gt;TrailBlazer&lt;/str&gt;
      &lt;float name="price"&gt;140000.0&lt;/float&gt;
      &lt;int name="year"&gt;2007&lt;/int&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Gdańsk&lt;/str&gt;
      &lt;str name="colour"&gt;green&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;3000&lt;/int&gt;
      &lt;str name="id"&gt;4&lt;/str&gt;
      &lt;str name="make"&gt;BMW&lt;/str&gt;
      &lt;int name="mileage"&gt;418000&lt;/int&gt;
      &lt;str name="model"&gt;Seria 7&lt;/str&gt;
      &lt;float name="price"&gt;140000.0&lt;/float&gt;
      &lt;int name="year"&gt;2007&lt;/int&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Koszalin&lt;/str&gt;
      &lt;str name="colour"&gt;green&lt;/str&gt;
      &lt;bool name="damaged"&gt;false&lt;/bool&gt;
      &lt;int name="engine_size"&gt;2000&lt;/int&gt;
      &lt;str name="id"&gt;1&lt;/str&gt;
      &lt;str name="make"&gt;Audi&lt;/str&gt;
      &lt;int name="mileage"&gt;92467&lt;/int&gt;
      &lt;str name="model"&gt;80&lt;/str&gt;
      &lt;float name="price"&gt;9774.0&lt;/float&gt;
      &lt;int name="year"&gt;2008&lt;/int&gt;
   &lt;/doc&gt;
   &lt;doc&gt;
      &lt;str name="city"&gt;Szczecin&lt;/str&gt;
      &lt;str name="colour"&gt;silver&lt;/str&gt;
      &lt;bool name="damaged"&gt;true&lt;/bool&gt;
      &lt;int name="engine_size"&gt;1299&lt;/int&gt;
      &lt;str name="id"&gt;3&lt;/str&gt;
      &lt;str name="make"&gt;Audi&lt;/str&gt;
      &lt;int name="mileage"&gt;116987&lt;/int&gt;
      &lt;str name="model"&gt;TT&lt;/str&gt;
      &lt;float name="price"&gt;1109.0&lt;/float&gt;
      &lt;int name="year"&gt;1997&lt;/int&gt;
   &lt;/doc&gt;
&lt;/result&gt;</pre>
</ol>
<p lang="pl-PL">Zgadza się! Wymagania zostały zrealizowane.</p>
<h2>Podsumowanie</h2>
<p lang="pl-PL">Po raz kolejny udało nam się sprostać oczekiwaniom naszych klientów. Tym razem dodaliśmy funkcjonalności związane z lokalizacją geograficzną aut, które pozwolą użytkownikom na zawężanie oraz sortowanie wyników wyszukiwania wykorzystując odległości geograficzne. Pełen sukces.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2011/03/14/aplikacja-sprzedaz-samochodow-spatial-search-czyli-wprowadzenie-danych-lokalizacyjnych-cz-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Aplikacja &#8222;sprzedaż samochodów” – WordDelimiterFilter i PatternReplaceFilter, czyli na ratunek jakości wyników (cz. 2)</title>
		<link>https://solr.pl/2011/02/14/aplikacja-sprzedaz-samochodow-worddelimiterfilter-i-patternreplacefilter-czyli-na-ratunek-jakosci-wynikow-cz-2/</link>
					<comments>https://solr.pl/2011/02/14/aplikacja-sprzedaz-samochodow-worddelimiterfilter-i-patternreplacefilter-czyli-na-ratunek-jakosci-wynikow-cz-2/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 14 Feb 2011 08:03:28 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[schema]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=182</guid>

					<description><![CDATA[W pierwszej części naszego cyklu stworzyliśmy pewną standardową strukturę indeksu, odpowiednio konfigurując plik schema.xml. Przy takiej konfiguracji, na pierwsze skargi klientów, dotyczących działania silnika wyszukiwawczego nie trzeba było długo czekać. Dlaczego wpisując w kryteria wyszukiwania frazę &#8222;audi a&#8221; nie otrzymuję]]></description>
										<content:encoded><![CDATA[<p lang="pl-PL">W <a href="http://solr.pl/2011/01/31/aplikacja-sprzedaz-samochodow-projektowanie-schema-xml-dla-naszych-potrzeb-cz-1/" target="_blank" rel="noopener noreferrer">pierwszej części</a> naszego cyklu stworzyliśmy pewną standardową strukturę indeksu, odpowiednio konfigurując plik schema.xml. Przy takiej konfiguracji, na pierwsze skargi klientów, dotyczących działania silnika wyszukiwawczego nie trzeba było długo czekać. Dlaczego wpisując w kryteria wyszukiwania frazę &#8222;audi a&#8221; nie otrzymuję ofert związanych z autami &#8222;Audi A6&#8221; lub &#8222;Audi A8&#8221; ? Wpisałem &#8222;Honda crv&#8221; &#8211; 0 wyników. &#8222;Suzuki maruti&#8221; &#8211; też nic. Czy takich ofert nie ma w bazie z ogłoszeniami ? Otóż są, ale konfiguracja typu pola, po którym wyszukujemy (pole &#8222;content&#8221; &#8211; typ &#8222;text&#8221;) uniemożliwia w obecnym stanie znalezienie tych ogłoszeń przy zastosowaniu powyższych zapytań. Na pomoc rusza nam chyba najbardziej popularny filtr &#8211; WordDelimiterFilter, oraz PatternReplaceFilter, których odpowiednia konfiguracja pozwoli sprostać naszym potrzebom.</p>
<p><span id="more-182"></span></p>
<h2>Analiza wymagań</h2>
<p lang="pl-PL">W celu dokonania analizy danych, które wchodzą w skład pola, po którym wyszukujemy, weźmy następującą próbkę, na której oprzemy naszą konfigurację:</p>
<ul>
<li><em>Marka</em>: Audi<br />
<em>Modele</em>: 80, 90, A6, A8, TT</li>
</ul>
<ul>
<li><em>Marka</em>: BMW<br />
<em>Modele</em>: M3, M5, Seria 7, Seria 8, X1, X3</li>
</ul>
<ul>
<li><em>Marka</em>: Chevrolet<br />
<em>Modele</em>: TrailBlazer</li>
</ul>
<ul>
<li><em>Marka</em>: Citroen<br />
<em>Modele</em>: C-Crosser, C3 Pluriel, C4 Picasso</li>
</ul>
<ul>
<li><em>Marka</em>: Ford<br />
<em>Modele</em>: C-MAX, S-MAX</li>
</ul>
<ul>
<li><em>Marka</em>: Honda<br />
<em>Modele</em>: Accord, CR-V, FR-V, HR-V</li>
</ul>
<ul>
<li><em>Marka</em>: Kia<br />
<em>Modele</em>: Cee&#8217;d</li>
</ul>
<ul>
<li><em>Marka</em>: Suzuki<br />
<em>Modele</em>: Alto/Maruti</li>
</ul>
<p lang="pl-PL">Nazwy marek są prostymi słowami, z którymi aktualna konfiguracja (WhitespaceTokenizer + LowerCaseFilter) poradzi sobie bez problemu. Problem pojawia się przy modelach aut, które zawierają dodatkowe znaki oraz separatory, które często ignorujemy przy wyszukiwaniu. Pogrupujmy sobie powyższą próbkę ze względu na charakterystykę danych:</p>
<ol>
<li>Nazwy modeli, które nie wymagają dodatkowych filtrów i obecna konfiguracja jest wystarczająca &#8211; 80, 90, TT, Seria 7, Seria 8, Accord</li>
<li>Nazwy modeli, których nazwy składają się z cyfr i liter, których to rozdzielenie jest pożądane &#8211; A6, A8, M3, M5, X1, X3, C3 Pluriel, C4 Picasso. Chcielibyśmy móc wyszukiwać powyższe modele wpisując tylko literę lub tylko cyfrę, ale również wpisując całą nazwę modelu.</li>
<li>Modele, które mają zmianę wielkości znaków w nazwie &#8211; TrailBlazer. Chcielibyśmy znaleźć taki model wpisując &#8222;trail&#8221;, &#8222;blazer&#8221;, &#8222;trailBlazer&#8221;, &#8222;trailblazer&#8221;.</li>
<li>Nazwy modeli, które zawierają separatory, które chcemy ignorować (wpisując nazwę modelu jako pełny wyraz &#8211; uwzględniając separator lub nie &#8211; oraz po częściach nazwy modelu, które taki separator generuje) &#8211; C-Crosser, C-MAX, S-MAX, CR-V, FR-V, HR-V, Alto/Maruti.<br />
Przykład: chcielibyśmy znaleźć ogłoszenie z modelem &#8222;C-MAX&#8221; wpisująć frazy &#8222;c&#8221;, &#8222;max&#8221;, &#8222;c-max&#8221; &#8222;cmax&#8221;.</li>
<li>Celowo w punkcie 4 pominąłem model &#8222;Cee&#8217;d&#8221;. Ten model przy wyszukiwaniu chcielibyśmy traktować trochę inaczej, a mianowicie uniemożliwić znalezienie ogłoszenia przy wpisaniu &#8222;cee&#8221; lub &#8222;d&#8221;. Traktujemy nazwę &#8222;Cee&#8217;d&#8221; tylko i wyłącznie jako jeden wyraz, czyli realizujemy wyszukiwanie tylko dla przypadków &#8222;cee&#8217;d&#8221; oraz &#8222;ceed&#8221;.</li>
</ol>
<h2>Konfiguracja WordDelimiterFilter</h2>
<p lang="pl-PL">Na podstawie opisanej charakterystyki dobierzmy takie wartości atrybutów filtra WordDelimiterFilter, aby wszystkie powyższe wymagania zostały spełnione:</p>
<ol>
<li>WordDelimiterFilter jest w tym wypadku zbędny, do realizacji wymagań z pkt 1 wystarczy WhitespaceTokenizer + LowerCaseFilter.</li>
<li> W celu realizacji wymagań z pkt 2 należy zadbać o odpowiednie ustawienie następujących atrybutów:
<ul>
<li> <em>generateWordParts=&#8221;1&#8243;</em> &#8211; wartość musi być ustawiona na &#8222;1&#8221;, jeżeli chcemy mieć możliwość generowania części słów</li>
<li><em>generateNumberParts=&#8221;1&#8243;</em> &#8211; wartość musi być ustawiona na &#8222;1&#8221;, jeżeli chcemy mieć możliwość generowania części liczbowych</li>
<li><em>splitOnNumerics=&#8221;1&#8243;</em> &#8211; wartość musi być ustawiona na &#8222;1&#8221;, jeżeli chcemy mieć możliwość rozdzielania literek od liczb</li>
</ul>
</li>
<li> W celu realizacji wymagań z pkt 3, musimy ustawić następujące atrybuty:
<ul>
<li> <em>generateWordParts=&#8221;1&#8243;</em></li>
<li><em>splitOnCaseChange=&#8221;1&#8243;</em> &#8211; wartość musi być ustawiona na &#8222;1&#8221;, jeżeli chcemy mieć możliwość generowania części słów przy przejściu z dużej litery na małą i odwrotnie</li>
</ul>
</li>
<li> W celu realizacji wymagań z pkt 4, ustawiamy następujące atrybuty:
<ul>
<li> <em>generateWordParts=&#8221;1&#8243;</em></li>
<li><em>catenateWords=&#8221;1&#8243; </em>&#8211;  wartość musi być ustawiona na &#8222;1&#8221;, abyśmy mogli dodatkowo ignorować separatory, poprzez łączenie wyrazów, które są takim separatorem rozdzielone</li>
</ul>
</li>
</ol>
<p lang="pl-PL">Zatem konfiguracja naszego filtra wygląda następująco:</p>
<pre class="brush:xml">&lt;filter class="solr.WordDelimiterFilterFactory"
 splitOnNumerics="1"
 splitOnNumerics="1"
 generateWordParts="1"
 generateNumberParts="1"
 catenateWords="1"
/&gt;</pre>
<p lang="pl-PL">Dodatkowo okazuje się, że domyślna wartość atrybutów &#8222;splitOnNumerics&#8221; oraz &#8222;splitOnNumerics&#8221; to właśnie &#8222;1&#8221;. Pozostałe atrybuty, których nie wykorzystujemy (poza &#8222;stemEnglishPossessive&#8221;), mają domyślną wartość na &#8222;0&#8221;. Konfiguracja naszego filtra zatem upraszcza się do następującej postaci:</p>
<pre class="brush:xml">&lt;filter class="solr.WordDelimiterFilterFactory"
 generateWordParts="1"
 generateNumberParts="1"
 catenateWords="1"
 stemEnglishPossessive="0"
/&gt;</pre>
<p lang="pl-PL">Co zrobić z punktem nr. 5 naszej charakterystyki danych? Ustaliliśmy, że nie chcielibyśmy dla tego przypadku traktować znaku &#8221; &#8217; &#8221; jako separatora, a tak właśnie by się stało przy powyższej konfiguracji. Może zatem użyć w filtrze opcji, która zachowa to słowo w stanie niezmienionym, czyli wykorzystać atrybut protected=&#8221;protwords.txt&#8221; i dodać słowo &#8222;Cee&#8217;d&#8221; do pliku protwords.txt? No tak, ale co z faktem, że chcemy móc wyszukać taki dokument, przy wpisaniu frazy &#8222;ceed&#8221; ? Najlepiej by było zająć się tym przypadkiem w oddzielnym filtrze, a do filtra WordDelimiterFilter wprowadzić wartość, której ten filtr nie będzie musiał już analizować.</p>
<h2>Konfiguracja PatternReplaceFilter</h2>
<p lang="pl-PL">Filtr PatternReplaceFilter zastosujemy przed filtrem WordDelimiterFilter. Za pomocą PatternReplaceFilter będziemy mogli po prostu wyciąć znak &#8222;'&#8221; z nazwy tego specyficznego modelu, zastępując go pustym znakiem. W ten sposób, do filtra WordDelimiterFilter trafi nam nazwa &#8222;Ceed&#8221;, która przy obecnej konfiguracji nie zastosuje na takiej wartości żadnej modyfikacji. Filtry będą miały taką samą konfigurację przy indeksowaniu jak i przy wyszukiwaniu, zatem użytkownik będzie w stanie znaleźć ogłoszenie z marką &#8222;Cee&#8217;d&#8221; przy wpisaniu frazy &#8222;cee&#8217;d&#8221; jak i &#8222;ceed&#8221;:</p>
<pre>&lt;filter class="solr.PatternReplaceFilterFactory" pattern="'" replacement="" replace="all" /&gt;</pre>
<h2>Wizualizacja działania nowej konfiguracji typu pola &#8222;text&#8221;</h2>
<p lang="pl-PL">Podsumowując, nasz typ &#8222;text&#8221; zmienił się następująco:</p>
<pre class="brush:xml">&lt;fieldType name="text" positionIncrementGap="100"&gt;
 &lt;analyzer&gt;
  &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
   &lt;filter class="solr.PatternReplaceFilterFactory" pattern="'" replacement="" replace="all" /&gt;
   &lt;filter class="solr.WordDelimiterFilterFactory"
    generateWordParts="1"
    generateNumberParts="1"
    catenateWords="1"
    stemEnglishPossessive="0"
  /&gt;
  &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
 &lt;/analyzer&gt;
&lt;/fieldType&gt;</pre>
<p lang="pl-PL">Wykorzystajmy panel administracyjny solr, aby zobaczyć na przykładzie każdego z punktów, czy konfigurując nasz typ tak jak powyżej, otrzymamy to, czego oczekujemy:</p>
<p style="text-align: center;"><a href="http://solr.pl/wp-content/uploads/2011/02/11.jpg"><img fetchpriority="high" decoding="async" class="size-full wp-image-840 aligncenter" src="http://solr.pl/wp-content/uploads/2011/02/11.jpg" alt="" width="725" height="70"></a></p>
<p style="text-align: center;"><a href="http://solr.pl/wp-content/uploads/2011/02/2.jpg"><img decoding="async" class="size-full wp-image-841 aligncenter" src="http://solr.pl/wp-content/uploads/2011/02/2.jpg" alt="" width="694" height="740"></a></p>
<ol>
<li>(Model: &#8222;80&#8221;) Tak jak oczekiwaliśmy, wprowadzone filtry nie mają wpływu na dane charakterystyczne dla punktu 1.</li>
<li>(Model: &#8222;A8&#8221;) WordDelimiterFilter rozdzielił nam liczbę od wyrazu.</li>
<li>(Model: &#8222;TrailBlazer&#8221;)WordDelimiterFilter rozdzielił nam &#8222;trail&#8221; od &#8222;Blazer&#8221;. Dodatkowo mamy możliwość wyszukiwania po &#8222;trailblazer&#8221;. Super.</li>
<li>(Model: &#8222;CR-V&#8221;) WordDelimiterFilter rozdzielił nam wyraz po separatorze (w tym wypadku &#8222;-&#8222;). Dodatkowo mamy możliwość wyszukiwania po nazwie modelu nie uwzględniając separatora (&#8222;crv&#8221;).</li>
<li>(Model: &#8222;Cee&#8217;d&#8221;) PatternReplaceFilter zamienił nam &#8222;Cee&#8217;d&#8221; na &#8222;Ceed&#8221; a WordDelimiterFilter zachował tę wartość. O to nam chodziło.</li>
</ol>
<h2>Podsumowanie</h2>
<p lang="pl-PL">W drugiej części naszego cyklu użyliśmy dwóch nowych filtrów w celu poprawy jakości wyników wyszukiwania. Na przykładzie naszych &#8222;samochodowych&#8221; danych omówiliśmy użycie WordDelimiterFilter oraz PatternReplaceFilter. Poprawka wprowadzona, klient usatysfakcjonowany &#8230; ale na jak długo ?</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2011/02/14/aplikacja-sprzedaz-samochodow-worddelimiterfilter-i-patternreplacefilter-czyli-na-ratunek-jakosci-wynikow-cz-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Aplikacja &#8222;sprzedaż samochodów&#8221; &#8211; projektowanie schema.xml dla naszych potrzeb (cz. 1)</title>
		<link>https://solr.pl/2011/01/31/aplikacja-sprzedaz-samochodow-projektowanie-schema-xml-dla-naszych-potrzeb-cz-1/</link>
					<comments>https://solr.pl/2011/01/31/aplikacja-sprzedaz-samochodow-projektowanie-schema-xml-dla-naszych-potrzeb-cz-1/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Andrzejewski]]></dc:creator>
		<pubDate>Mon, 31 Jan 2011 08:01:46 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[schema]]></category>
		<category><![CDATA[solr]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=178</guid>

					<description><![CDATA[Podstawowym plikiem konfiguracyjnym solr, który jest niejako łącznikiem pomiędzy tym czego potrzebujemy, a tym co rozumie solr, jest plik schema.xml. Dobre zaprojektowanie schema.xml jest głównym czynnikiem warunkującym poprawne funkcjonowanie wyszukiwarki, która będzie w stanie zrealizować wszystkie wymagania, jakie przed nią]]></description>
										<content:encoded><![CDATA[<p>Podstawowym plikiem konfiguracyjnym solr, który jest niejako łącznikiem pomiędzy tym czego potrzebujemy, a tym co rozumie solr, jest plik schema.xml. Dobre zaprojektowanie schema.xml jest głównym czynnikiem warunkującym poprawne funkcjonowanie wyszukiwarki, która będzie w stanie zrealizować wszystkie wymagania, jakie przed nią stawiamy. Zacznijmy zatem kolejny cykl artykułów, poświęconych projektowaniu pliku schema.xml jak i również wszystkich składników wchodzących w skład zdefiniowanych przez nas typów pól.</p>
<p><span id="more-178"></span></p>
<h2>Analiza wymagań</h2>
<p lang="pl-PL">Wyobraźmy sobie, że chcemy wykorzystać silnik solr w celu dodania wyszukiwarki ogłoszeń samochodowych do naszego serwisu. Serwis nasz jest w tym momencie dosyć prymitywny i przetrzymuje podstawowe informacje opisujące właściwości każdego wystawionego na sprzedaż samochodu:</p>
<ul>
<li>marka</li>
<li>model</li>
<li>rok produkcji</li>
<li>cena</li>
<li>pojemność</li>
<li>przebieg</li>
<li>kolor</li>
<li>czy uszkodzony</li>
</ul>
<p lang="pl-PL">Chcielibyśmy w tym momencie zaprojektować najprostszy plik konfiguracyjny, który pomoże odpowiednio zaindeksować dane z powyższych pól. Zanim jednak przystąpimy do rzeźbienia pliku schema.xml, odpowiedzmy sobie na siedem podstawowych pytań, dotyczących każdego z tych pól:</p>
<h3>1. Jaki typ ?</h3>
<p>Ustalamy typ każdego pola:</p>
<ul>
<li>marka &#8211; pole tekstowe</li>
<li>model &#8211; pole tekstowe</li>
<li>rok produkcji &#8211; pole liczbowe</li>
<li>cena &#8211; pole liczbowe, zmiennoprzecinkowe</li>
<li>pojemność &#8211; pole liczbowe</li>
<li>przebieg &#8211; pole liczbowe</li>
<li>kolor &#8211; pole tekstowe</li>
<li>czy uszkodzony &#8211; pole logiczne</li>
</ul>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Będziemy potrzebowali definicji typów: string, boolean, int, float.</p>
<h3>2. Czy po polu ma się odbywać wyszukiwanie ?</h3>
<p lang="pl-PL">Ustalamy, z których pól będą wykorzystywane informacje, w celu znalezienia odpowiednich ogłoszeń samochodowych. W naszym serwisie będą to 3 pola: marka, model oraz rok produkcji.</p>
<h4>Co nam to mówi ?</h4>
<p>Pewnie będziemy potrzebowali kolejnego typu pola, który będzie poddawany działaniu różnych filtrów, zwiększających nasze szanse znalezienia interesującego nas dokumentu. Stworzymy sobie dodatkowe pole tego typu, po którym będziemy wyszukiwać i wrzucimy tam dane z wszystkich 3 powyższych pól.</p>
<h3>3. Czy sortowalne lub grupowalne ?</h3>
<p lang="pl-PL">Serwis nasz przewiduje sortowanie wyników wyszukiwania po polach: model, rok produkcji, cena oraz przebieg. Chcielibyśmy również móc grupować wyniki wyszukiwania (faceting) po polach marka, model, rok produkcji oraz kolor.</p>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Pola tekstowe, po których sortujemy lub grupujemy nie powinny być poddawane działaniu filtrów, które mogą nam rozdzielić na tokeny wartości w tych polach. Zależy nam jednak na tym, aby wszystkie wartości były zapisane małymi literami, tak aby wielkość liter nie wpływała na sortowanie czy też grupowanie. Będzie trzeba stworzyć nowy typ pola, który nam to umożliwi.</p>
<h3>4. Czy wykorzystywane przy filtrowaniu ?</h3>
<p lang="pl-PL">Na stronie wyszukiwania ogłoszeń chcemy mieć możliwość zawężenia wyników wyszukiwania, poprzez ustawianie zakresów na polach: rok produkcji, cena, pojemność oraz przebieg.</p>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Dobierzmy zatem takie typy dla tych pól, aby filtrowanie po zakresach było jak najbardziej wydajne.</p>
<h3>5. Czy zostały mi pola, które nie zostały wymienione w punktach 2, 3 lub 4 ?</h3>
<p lang="pl-PL">Okazuje się, że na polu &#8222;czy wymagane&#8221; nie będziemy przeprowadzać żadnych &#8222;operacji&#8221;.</p>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Ustawiamy atrybut &#8222;indexed&#8221; dla takiego pola na wartość false.</p>
<h3>6.Czy wymagane ?</h3>
<p lang="pl-PL">W naszym serwisie zakładamy, że polami wymaganymi dla każdego ogłoszenia będą pola marka, model oraz rok produkcji. Nie chcemy mieć dokumentów, które nie mają zdefiniowanych co najmniej tych trzech pól.</p>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Przy definiowaniu tych pól musimy pamiętać o ustawieniu wartości atrybutu &#8222;required&#8221; na true.</p>
<h3>7. Czy wartości pól mają być pobierane z indeksu w oryginalnym stanie?</h3>
<p lang="pl-PL">Informację ze wszystkich pól chcielibyśmy wyciągnąć bezpośrednio z wyników wyszukiwania i zaprezentować klientowi serwisu.</p>
<h4>Co nam to mówi ?</h4>
<p lang="pl-PL">Przy definiowaniu tych pól musimy pamiętać o ustawieniu wartości atrybutu &#8222;stored&#8221; na true.</p>
<h2>Dodajmy definicje typów pól</h2>
<p lang="pl-PL">Odpowiedzieliśmy już sobie na nasze niezbędne pytanie, wyciągnęliśmy wnioski, więc czas wprowadzić je w życie. Dodajmy do schemy typy pól:</p>
<p lang="pl-PL">Dodajemy zwykły typ string, który nie jest poddawany żadnej analizie, przyda się np. jako typ dla pola reprezentującego unikalny identyfikator dokumentu.</p>
<pre class="brush:xml">&lt;fieldType name="string" sortMissingLast="true" omitNorms="true"/&gt;</pre>
<p lang="pl-PL">Dodajemy typ boolean.</p>
<pre class="brush:xml">&lt;fieldType name="boolean" sortMissingLast="true" omitNorms="true"/&gt;</pre>
<p lang="pl-PL">Dodajemy typy dla pól liczbowych. Pamiętamy, że zależy nam na typach, które zagwarantują nam szybsze wykonywanie zapytań po zakresach. Skorzystajmy zatem z typów tint oraz tfloat:</p>
<pre class="brush:xml">&lt;fieldType name="tint" precisionStep="8" omitNorms="true" positionIncrementGap="0"/&gt;
&lt;fieldType name="tfloat" precisionStep="8" omitNorms="true" positionIncrementGap="0"/&gt;</pre>
<p lang="pl-PL">Stwórzmy teraz typ tekstowy, który będzie wykorzystywany przez pole zbiorcze po którym będziemy wyszukiwać. Załóżmy prosty typ, który rozdzieli nam wszystkie tokeny po białych znakach, po czym zamieni wszystkie litery na małe.</p>
<pre class="brush:xml">&lt;fieldType name="text" positionIncrementGap="100"&gt;
  &lt;analyzer&gt;
    &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
    &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
  &lt;/analyzer&gt;
&lt;/fieldType&gt;</pre>
<p lang="pl-PL">Potrzebujemy jeszcze typu dla pól, które będą sortowalne/grupowalne:</p>
<pre class="brush:xml">&lt;fieldType name="lowercase" positionIncrementGap="100"&gt;
  &lt;analyzer&gt;
    &lt;tokenizer class="solr.KeywordTokenizerFactory"/&gt;
    &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
    &lt;filter class="solr.TrimFilterFactory" /&gt;
  &lt;/analyzer&gt;
&lt;/fieldType&gt;</pre>
<p lang="pl-PL">KeywordTokenizer tak naprawdę nie tokenizuje wartości którą dostaje na wejściu, czyli niezmieniona wartość zostanie poddana działaniu filtra LowerCaseFilterFactory po czym filtr TrimFilterFactory zadba o to, aby zostały usunięte wszelkie białe znaki, znajdujące się na początku lub na końcu wartości.</p>
<h2>Dodajmy definicje pól</h2>
<p>Identyfikator dokumentu:
</p>
<pre class="brush:xml">&lt;field name="id" type="string" indexed="true" stored="true" required="true" /&gt;</pre>
<p>Marka oraz model:
</p>
<pre class="brush:xml">&lt;field name="make" type="text" indexed="false" stored="true" required="true" /&gt;
&lt;field name="model" type="text" indexed="false" stored="true" required="true" /&gt;</pre>
<p>Nasuwa się pytanie, dlaczego atrybuty indexed dla pól marka oraz model są ustawione na false? Przecież są to pola, które wykorzystywane są przy wyszukiwaniu, sortowaniu i grupowaniu. Zgadza się. Jednakże w celach wyszukiwania przekopiujemy wartości z tych pól do pola zbiorczego, a w celach sortowania/grupowania przekopiujemy wartości z tych pól do pól o typie &#8222;lowercase&#8221;.<br />
Pola, do których będziemy kopiować wartości marek oraz modeli samochodów, a które to będą wykorzystywane do sortowania/grupowania po tych polach:
</p>
<pre class="brush:xml">&lt;field name="make_sort" type="lowercase" indexed="true" stored="false" /&gt;
&lt;field name="model_sort" type="lowercase" indexed="true" stored="false" /&gt;</pre>
<p>Pole zbiorcze, do którego będą kopiowane wartości z pól, po których chcemy wyszukiwać. Jako że do tego pola kopiujemy wartości z więcej niż jednego pola, musimy ustawić wartość atrybutu „multiValued” na true:
</p>
<pre class="brush:xml">&lt;field name="content" type="text" indexed="true" stored="false" multiValued="true"/&gt;</pre>
<p>Rok produkcji:
</p>
<pre class="brush:xml">&lt;field name="year" type="tint" indexed="true" stored="true" required="true" /&gt;</pre>
<p>Cena:
</p>
<pre class="brush:xml">&lt;field name="price" type="tfloat" indexed="true" stored="true" /&gt;</pre>
<p>Pojemność:
</p>
<pre class="brush:xml">&lt;field name="engine_size" type="tint" indexed="true" stored="true" /&gt;</pre>
<p>Przebieg:
</p>
<pre class="brush:xml">&lt;field name="mileage" type="tint" indexed="true" stored="true" /&gt;</pre>
<p>Kolor:
</p>
<pre class="brush:xml">&lt;field name="colour" type="lowercase" indexed="true" stored="true" /&gt;</pre>
<p>Pamiętamy o wartości false dla atrybutu „indexed” dla pola „Czy uszkodzony”:
</p>
<pre class="brush:xml">&lt;field name="damaged" type="boolean" indexed="false" stored="true" /&gt;</pre>
<p>Zostało nam przekopiować wartości z pól, po których wyszukujemy do jednego pola zbiorczego:
</p>
<pre class="brush:xml">&lt;copyField source="make" dest="content"/&gt;
&lt;copyField source="model" dest="content"/&gt;
&lt;copyField source="year" dest="content"/&gt;</pre>
<p>&#8230; i ponownie pola marki i modelu do pól, po których będziemy sortować:
</p>
<pre class="brush:xml">&lt;copyField source="make" dest="make_sort"/&gt;
&lt;copyField source="model" dest="model_sort"/&gt;</pre>
<h2>Czy coś jeszcze do schemy?</h2>
<p>Uzupełnijmy scheme jeszcze o 3 elementy:<br />
Klucz unikalny dokumentu
</p>
<pre class="brush:xml">&lt;uniqueKey&gt;id&lt;/uniqueKey&gt;</pre>
<p>Domyślne pole, po którym wyszukujemy
</p>
<pre class="brush:xml">&lt;defaultSearchField&gt;content&lt;/defaultSearchField&gt;</pre>
<p>Domyślny operator, wykorzystywany przez parser zapytań do solr. Ustawmy go na wartość &#8222;AND&#8221;.
</p>
<pre class="brush:xml">&lt;solrQueryParser defaultOperator="AND"/&gt;</pre>
<p>Mamy zatem gotowy plik konfiguracyjny schema.xml! Zobaczmy jak wygląda w całej okazałości:
</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;schema name="carsale" version="1.2"&gt;
  &lt;types&gt;
   &lt;fieldType name="string" sortMissingLast="true" omitNorms="true"/&gt;
   &lt;fieldType name="boolean" sortMissingLast="true" omitNorms="true"/&gt;
   &lt;fieldType name="tint" precisionStep="8" omitNorms="true" positionIncrementGap="0"/&gt;
   &lt;fieldType name="tfloat" precisionStep="8" omitNorms="true" positionIncrementGap="0"/&gt;
   &lt;fieldType name="text" positionIncrementGap="100"&gt;
     &lt;analyzer&gt;
       &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
       &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
     &lt;/analyzer&gt;
   &lt;/fieldType&gt;
   &lt;fieldType name="lowercase" positionIncrementGap="100"&gt;
     &lt;analyzer&gt;
       &lt;tokenizer class="solr.KeywordTokenizerFactory"/&gt;
       &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
       &lt;filter class="solr.TrimFilterFactory" /&gt;
     &lt;/analyzer&gt;
   &lt;/fieldType&gt;
 &lt;/types&gt;
 &lt;fields&gt;
   &lt;field name="id" type="string" indexed="true" stored="true" required="true" /&gt;
   &lt;field name="make" type="text" indexed="false" stored="true" required="true" /&gt;
   &lt;field name="model" type="text" indexed="false" stored="true" required="true" /&gt;
   &lt;field name="make_sort" type="lowercase" indexed="true" stored="false" /&gt;
   &lt;field name="model_sort" type="lowercase" indexed="true" stored="false" /&gt;
   &lt;field name="year" type="tint" indexed="true" stored="true" required="true" /&gt;
   &lt;field name="price" type="tfloat" indexed="true" stored="true" /&gt;
   &lt;field name="engine_size" type="tint" indexed="true" stored="true" /&gt;
   &lt;field name="mileage" type="tint" indexed="true" stored="true" /&gt;
   &lt;field name="colour" type="lowercase" indexed="true" stored="true" /&gt;
   &lt;field name="damaged" type="boolean" indexed="false" stored="true" /&gt;
   &lt;field name="content" type="text" indexed="true" stored="false" multiValued="true"/&gt;
 &lt;/fields&gt;
 &lt;uniqueKey&gt;id&lt;/uniqueKey&gt;
 &lt;defaultSearchField&gt;content&lt;/defaultSearchField&gt;
 &lt;solrQueryParser defaultOperator="AND"/&gt;
 &lt;copyField source="make" dest="content"/&gt;
 &lt;copyField source="model" dest="content"/&gt;
 &lt;copyField source="make" dest="make_sort"/&gt;
 &lt;copyField source="model" dest="model_sort"/&gt;
 &lt;copyField source="year" dest="content"/&gt;
&lt;/schema&gt;</pre>
<h2>Podsumowując</h2>
<p>W dzisiejszym wpisie udało nam się stworzyć plik schema.xml, który pomoże nam tak zaindeksować dane, abyśmy mogli zrealizować funkcjonalności wyszukiwania ogłoszeń naszego serwisu sprzedaży samochodów. Chcielibyśmy jednak rozwijać nasz serwis, co będzie się wiązało z dodatkowymi zmianami w pliku konfiguracyjnym &#8230; i nie tylko. W następnych artykułach z cyklu &#8222;sprzedaż samochodów&#8221; będziemy realizować nowe wymagania oraz wprowadzać kolejne modyfikacje.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2011/01/31/aplikacja-sprzedaz-samochodow-projektowanie-schema-xml-dla-naszych-potrzeb-cz-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
