{"id":221,"date":"2011-03-14T09:19:01","date_gmt":"2011-03-14T08:19:01","guid":{"rendered":"http:\/\/sematext.solr.pl\/?p=221"},"modified":"2020-11-11T09:19:47","modified_gmt":"2020-11-11T08:19:47","slug":"car-sale-application-spatial-search-adding-location-data-part-3","status":"publish","type":"post","link":"https:\/\/solr.pl\/en\/2011\/03\/14\/car-sale-application-spatial-search-adding-location-data-part-3\/","title":{"rendered":"&#8220;Car sale application&#8221; \u2013 Spatial Search, adding location data (part 3)"},"content":{"rendered":"<p>The amount of announcements in our database is so large, that our web site users   started to look for another option to filter search results and another way of sorting them. We need to add the functionality, which allows us to operate with localization data related to the cars.<\/p>\n\n\n<!--more-->\n\n\n<h2>Requirements specification<\/h2>\n<p lang=\"pl-PL\">We would like to add two new functionalities:<\/p>\n<ol>\n<li>Filtering the results in order to display only those announcements, that are located not farther than x kilometres from the given place, where x = 50,100,200,500,1000 km.<\/li>\n<li>Sorting the results using the distance between the given place and the given car&#8217;s localization.<\/li>\n<\/ol>\n<p>In order to face the requirements, we need to use solr&#8217;s functionality called \u201cSpatial Search\u201d, that is available in solr distribution from version 3.1. The changes we need to provide are related to schema.xml file modifications and the input data changes, where we have to add the information about the localization of every car. In the end we will create proper requests.<\/p>\n<h2>Schema.xml changes<\/h2>\n<ol>\n<li>New field types definitions:\n<ul>\n<li>the first definition is nothing more than another numerical type:<\/li>\n<pre class=\"brush:xml\">&lt;fieldType name=\"tdouble\" precisionStep=\"8\" omitNorms=\"true\" positionIncrementGap=\"0\"\/&gt;<\/pre>\n<li>the second definition uses the &#8220;solr.LatLonType&#8221; class, which allows us to index localization data using the dynamic field with suffix &#8220;_coordinate&#8221;:<\/li>\n<pre class=\"brush:xml\">&lt;fieldType name=\"location\" subFieldSuffix=\"_coordinate\"\/&gt;<\/pre>\n<\/ul>\n<\/li>\n<li>New fields definitions:\n<ul>\n<li>field, that will be used to accumulate the city name data, that is related to every car:<\/li>\n<pre class=\"brush:xml\">&lt;field name=\"city\" type=\"string\" indexed=\"true\" stored=\"true\" \/&gt;<\/pre>\n<li>&#8220;loc&#8221; field will be used to index localization data:<\/li>\n<pre class=\"brush:xml\">&lt;field name=\"loc\" type=\"location\" indexed=\"true\" stored=\"false\"\/&gt;<\/pre>\n<li>the dynamic field used internally to accumulate the information provided by the &#8220;loc&#8221; field:<\/li>\n<pre class=\"brush:xml\">&lt;dynamicField name=\"*_coordinate\" type=\"tdouble\" indexed=\"true\" stored=\"false\"\/&gt;<\/pre>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>Input data analysis<\/h2>\n<p>In order to present how to modify the input data, let&#8217;s take 5 announcements from the cities:<\/p>\n<ol>\n<li>Koszalin\n<ul>\n<li><em>latitude<\/em>: 54.12<\/li>\n<li><em>longitude<\/em>: 16.11<\/li>\n<\/ul>\n<\/li>\n<li>Bia\u0142ystok\n<ul>\n<li><em>latitude<\/em>: 53.08<\/li>\n<li><em>longitude<\/em>: 23.09<\/li>\n<\/ul>\n<\/li>\n<li>Szczecin\n<ul>\n<li><em>latitude<\/em>: 53.25<\/li>\n<li><em>longitude<\/em>: 14.35<\/li>\n<\/ul>\n<\/li>\n<li>Gda\u0144sk\n<ul>\n<li><em>latitude<\/em>: 54.21<\/li>\n<li><em>longitude<\/em>: 18.40<\/li>\n<\/ul>\n<\/li>\n<li>Warszawa\n<ul>\n<li><em>latitude<\/em>: 52.15<\/li>\n<li><em>longitude<\/em>: 21.00<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>We provide the localization data by entering the latitude and longitude separated by the comma in the &#8220;loc&#8221; field. Our data might look like this:\n<\/p>\n<pre class=\"brush:xml\">&lt;add&gt;\n   &lt;doc&gt;\n      &lt;field name=\"id\"&gt;1&lt;\/field&gt;\n      &lt;field name=\"make\"&gt;Audi&lt;\/field&gt;\n      &lt;field name=\"model\"&gt;80&lt;\/field&gt;\n      &lt;field name=\"year\"&gt;2008&lt;\/field&gt;\n      &lt;field name=\"price\"&gt;9774&lt;\/field&gt;\n      &lt;field name=\"engine_size\"&gt;2000&lt;\/field&gt;\n      &lt;field name=\"mileage\"&gt;92467&lt;\/field&gt;\n      &lt;field name=\"colour\"&gt;green&lt;\/field&gt;\n      &lt;field name=\"damaged\"&gt;false&lt;\/field&gt;\n      &lt;field name=\"city\"&gt;Koszalin&lt;\/field&gt;\n      &lt;field name=\"loc\"&gt;54.12,16.11&lt;\/field&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;field name=\"id\"&gt;2&lt;\/field&gt;\n      &lt;field name=\"make\"&gt;Audi&lt;\/field&gt;\n      &lt;field name=\"model\"&gt;A8&lt;\/field&gt;\n      &lt;field name=\"year\"&gt;2009&lt;\/field&gt;\n      &lt;field name=\"price\"&gt;9078&lt;\/field&gt;\n      &lt;field name=\"engine_size\"&gt;1000&lt;\/field&gt;\n      &lt;field name=\"mileage\"&gt;31369&lt;\/field&gt;\n      &lt;field name=\"colour\"&gt;black&lt;\/field&gt;\n      &lt;field name=\"damaged\"&gt;false&lt;\/field&gt;\n      &lt;field name=\"city\"&gt;Bia\u0142ystok&lt;\/field&gt;\n      &lt;field name=\"loc\"&gt;53.08,23.09&lt;\/field&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;field name=\"id\"&gt;3&lt;\/field&gt;\n      &lt;field name=\"make\"&gt;Audi&lt;\/field&gt;\n      &lt;field name=\"model\"&gt;TT&lt;\/field&gt;\n      &lt;field name=\"year\"&gt;1997&lt;\/field&gt;\n      &lt;field name=\"price\"&gt;1109&lt;\/field&gt;\n      &lt;field name=\"engine_size\"&gt;1299&lt;\/field&gt;\n      &lt;field name=\"mileage\"&gt;116987&lt;\/field&gt;\n      &lt;field name=\"colour\"&gt;silver&lt;\/field&gt;\n      &lt;field name=\"damaged\"&gt;true&lt;\/field&gt;\n      &lt;field name=\"city\"&gt;Szczecin&lt;\/field&gt;\n      &lt;field name=\"loc\"&gt;53.25,14.35&lt;\/field&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;field name=\"id\"&gt;4&lt;\/field&gt;\n      &lt;field name=\"make\"&gt;BMW&lt;\/field&gt;\n      &lt;field name=\"model\"&gt;Seria 7&lt;\/field&gt;\n      &lt;field name=\"year\"&gt;2007&lt;\/field&gt;\n      &lt;field name=\"price\"&gt;140000&lt;\/field&gt;\n      &lt;field name=\"engine_size\"&gt;3000&lt;\/field&gt;\n      &lt;field name=\"mileage\"&gt;418000&lt;\/field&gt;\n      &lt;field name=\"colour\"&gt;green&lt;\/field&gt;\n      &lt;field name=\"damaged\"&gt;false&lt;\/field&gt;\n      &lt;field name=\"city\"&gt;Gda\u0144sk&lt;\/field&gt;\n      &lt;field name=\"loc\"&gt;54.21,18.40&lt;\/field&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;field name=\"id\"&gt;5&lt;\/field&gt;\n      &lt;field name=\"make\"&gt;Chevrolet&lt;\/field&gt;\n      &lt;field name=\"model\"&gt;TrailBlazer&lt;\/field&gt;\n      &lt;field name=\"year\"&gt;2007&lt;\/field&gt;\n      &lt;field name=\"price\"&gt;140000&lt;\/field&gt;\n      &lt;field name=\"engine_size\"&gt;3000&lt;\/field&gt;\n      &lt;field name=\"mileage\"&gt;418000&lt;\/field&gt;\n      &lt;field name=\"colour\"&gt;green&lt;\/field&gt;\n      &lt;field name=\"damaged\"&gt;false&lt;\/field&gt;\n      &lt;field name=\"city\"&gt;Warszawa&lt;\/field&gt;\n      &lt;field name=\"loc\"&gt;52.15,21.00&lt;\/field&gt;\n   &lt;\/doc&gt;\n&lt;\/add&gt;<\/pre>\n<h2>Let&#8217;s create queries<\/h2>\n<p>We have our localization data in the index, so all we need right now is to create queries that will satisfy our needs. Let&#8217;s imagine, that we are searching for announcements when being in Bia\u0142ystok city, which is located about 200 km away from the Warszawa city, about  400 km away from the Gda\u0144sk city, about  550 km away from the Koszalin city and about 650 km away from the Szczecin city.<\/p>\n<p>To execute the first point from the requirements specification, we add the special filter query to our request:\n<\/p>\n<pre class=\"brush:xml\">...&amp;fq={!geofilt sfield=loc}&amp;pt=53.08,23.09&amp;d=50<\/pre>\n<p>where:<\/p>\n<ul>\n<li><em>sfield<\/em> &#8211; the name of the field, where we have our localization data indexed.<\/li>\n<li><em>pt<\/em> &#8211; the localization of the starting point, it is the Bia\u0142ystok city in our case.<\/li>\n<li><em>d<\/em> &#8211; the distance used to narrow the search results. By using the 50,100,200,500,1000 values we can satisfy all our needs.<\/li>\n<\/ul>\n<p>Example:<\/p>\n<ol>\n<li>Query:\n<pre class=\"brush:xml\">q=*:*&amp;fq={!geofilt sfield=loc}&amp;pt=53.08,23.09&amp;d=200<\/pre>\n<\/li>\n<li>Search results:<\/li>\n<pre class=\"brush:xml\">&lt;result name=\"response\" numFound=\"2\" start=\"0\"&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Bia\u0142ystok&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;black&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;1000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;2&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Audi&lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;31369&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;A8&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;9078.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2009&lt;\/int&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Warszawa&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;green&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;3000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;5&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Chevrolet &lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;418000&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;TrailBlazer&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;140000.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2007&lt;\/int&gt;\n   &lt;\/doc&gt;\n&lt;\/result&gt;<\/pre>\n<\/ol>\n<p>That&#8217;s great, we don&#8217;t have any announcements from the Koszalin, Gda\u0144sk or Szczecin city, as these cities are located farther than 200 km from the Bia\u0142ystok city.<\/p>\n<p>To execute the second point from the requirements specification, we use the possibility to sort the search results by using the geodist function. The query would look like this:\n<\/p>\n<pre class=\"brush:xml\">...&amp;sfield=loc&amp;pt=53.08,23.09&amp;sort=geodist()+desc<\/pre>\n<p>The example of sorting the search results using the distance, starting from the Bia\u0142ystok city:<\/p>\n<ol>\n<li>Query:\n<pre class=\"brush:xml\">q=*:*&amp;sfield=loc&amp;pt=53.08,23.09&amp;sort=geodist()+asc<\/pre>\n<\/li>\n<li>Search results:<\/li>\n<pre class=\"brush:xml\">&lt;result name=\"response\" numFound=\"5\" start=\"0\"&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Bialystok&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;black&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;1000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;2&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Audi&lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;31369&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;A8&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;9078.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2009&lt;\/int&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Warszawa&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;green&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;3000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;5&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Chevrolet &lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;418000&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;TrailBlazer&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;140000.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2007&lt;\/int&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Gda\u0144sk&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;green&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;3000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;4&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;BMW&lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;418000&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;Seria 7&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;140000.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2007&lt;\/int&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Koszalin&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;green&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;false&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;2000&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;1&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Audi&lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;92467&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;80&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;9774.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;2008&lt;\/int&gt;\n   &lt;\/doc&gt;\n   &lt;doc&gt;\n      &lt;str name=\"city\"&gt;Szczecin&lt;\/str&gt;\n      &lt;str name=\"colour\"&gt;silver&lt;\/str&gt;\n      &lt;bool name=\"damaged\"&gt;true&lt;\/bool&gt;\n      &lt;int name=\"engine_size\"&gt;1299&lt;\/int&gt;\n      &lt;str name=\"id\"&gt;3&lt;\/str&gt;\n      &lt;str name=\"make\"&gt;Audi&lt;\/str&gt;\n      &lt;int name=\"mileage\"&gt;116987&lt;\/int&gt;\n      &lt;str name=\"model\"&gt;TT&lt;\/str&gt;\n      &lt;float name=\"price\"&gt;1109.0&lt;\/float&gt;\n      &lt;int name=\"year\"&gt;1997&lt;\/int&gt;\n   &lt;\/doc&gt;\n&lt;\/result&gt;<\/pre>\n<\/ol>\n<p>That&#8217;s correct! Mission accomplished.<\/p>\n<h2>The end<\/h2>\n<p>Once more we are up to our website users expectations. This time we have added the functionalities, which allow our users to filter and sort the search results using the localization and distance data. Full success!<\/p>","protected":false},"excerpt":{"rendered":"<p>The amount of announcements in our database is so large, that our web site users started to look for another option to filter search results and another way of sorting them. We need to add the functionality, which allows us<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[27],"tags":[288,182],"class_list":["post-221","post","type-post","status-publish","format-standard","hentry","category-solr-en","tag-howto-2","tag-schema-2"],"_links":{"self":[{"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/posts\/221","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/comments?post=221"}],"version-history":[{"count":1,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/posts\/221\/revisions"}],"predecessor-version":[{"id":222,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/posts\/221\/revisions\/222"}],"wp:attachment":[{"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/media?parent=221"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/categories?post=221"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solr.pl\/en\/wp-json\/wp\/v2\/tags?post=221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}