Multi-value spatial search with Solr 4.x and Drupal 7

For some time, Solr 3.x and Drupal 7 have been able to do geospatial search (using the location module, geofield, or other modules that stored latitude and longitude coordinates in Drupal that could be indexed by Apache Solr). Life was good—as long as you only had one location per node!

Sometimes, you may have a node (say a product, or a personality) affiliated with multiple locations. Perhaps you have a hammer that's available in three of your company's stores, or a speaker who is available to speak in two locations. When solr 3.x and Drupal 7 encountered this situation, you would either use a single location value in the index (so the second, third, etc. fields weren't indexed or searched), or if you put multiple values into solr's search index using the LatLonType, solr could throw out unexpected results (sometimes combining the closest latitude and closest longitude to a given point, meaning you get strange search results).

With Solr 4.x, especially Solr 4.3 and 4.5, there were some great improvements to spatial search, mostly enabled by switching from the old and trusty single-value LatLonType to the new (but slightly slower) SpatialRecursivePrefixTreeFieldType, or RPT for short.

Enabling this field type for the multi-value location field used by Apache Solr Search Integration and Search API involves an addition and a change in your schema.xml file. First, add the following after the "location" fieldType definition:

<fieldtype name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" disterrpct="0.025" maxdisterr="0.000009" units="degrees"></fieldtype>

Then, find the locm_* dynamicField definition later in the file, and update it to use the new location_rpt fieldType we just defined:

<dynamicfield name="locm_*" type="location_rpt" indexed="true" stored="true" multivalued="true"></dynamicfield>

Once this is done, you will need to reindex your site (or at least all the content with location/geo fields). Once that's done, your search results can use a location filter (perhaps a user's entered or detected location), and that filter will apply to all the values attached to a particular node.

Some other advantages offered by the RPT field type (as opposed to the LatLonType) include:

  • Query by polygons and other complex shapes, in addition to circles & rectangles
  • Multi-valued indexed fields
  • Ability to index non-point shapes (e.g. polygons) as well as point shapes
  • Rectangles with user-specified corners that can cross the dateline
  • Multi-value distance sort and score boosting (warning: non-optimized)
  • Well-Known-Text (WKT) shape syntax (required for specifying polygons & other complex shapes)

Some of these features (not including the multi-value support) also require the addition of the property spatialContextFactory="com.spatial4j.core.context.jts.JtsSpatialContextFactory" to the fieldType definition in schema.xml as well as the installation of the JTS library to your Solr class path.

See more in the Apache Solr docs: SpatialRecursivePrefixTreeFieldType (abbreviated as RPT). Also, check out this issue proposing we add the above configuration (and updated documentation) to the shared configuration for Apache Solr/Search API: Spatial search improvements - new spatial fieldType on Solr 4.

Comments

Hi Thanks, Very usefull article i just wanted to ask that i have to do spatial search on multi-valued address field in Drupal 7 using Seacrh api and search api solr module i did what u suggest. but i have couple of questions.
1. In which format i have to index data in the location_rpt field.
2. What is the format of query with distance parameter.

Thanks.

Sort By geodist() is not working in drupal 7 ? Do have any idea

Hi Jeff,

Thanks for this useful post and the linked issue on drupal.org.

You mention a "location filter (perhaps a user's entered or detected location), and that filter will apply to all the values attached to a particular node". Any suggestion on how I do this? It this a Views filter using Search Api Location? I'm a little lost here. Ideally what I am looking to do is create a range facet to find the distance from the user, to the nearest Polygon/Point indexed as a WKT

Any idea?