Community Documentation

WHAT/WHERE search + Solr 3.6 + location(lat/lng) + radius based search

Last updated June 30, 2012. Created by amrit_b on June 7, 2012.
Log in to edit this page.

This doc will help you to

  • Modify schema.xml so that it supports geo location values
  • WHAT/WHERE search (radius based) - instead of a single keyword based search
  • Content-type based filtration
  • Implementation of hook_apachesolr_index_document_build, hook_apachesolr_query_alter

I am not going through the steps for installing / connecting solr with drupal. A lot of articles are already available online.

Case

Typically for job/property search sites, where you have two text fields: WHAT and WHERE. I am using the apachesolr search pages for this implementation.
Example search:
WHAT: drupal architect
WHERE: Mumbai, Maharashtra, India
(basically, the 'where' is an autofill textbox - which gets data from YQL - and its cached when search is being repeated)

Schema.xml

This file helps Solr to communicate with Drupal - also a lot of configurations to indexing/storing data, etc. The schema.xml which ships with apachesolr module doesn't provide the needed support for storing and searching based on location / radius. Here is an alternative schema.xml file submitted by pwolanin which supports the needed features alternate schema.xml

Storing / indexing data

I personally used YQL to auto fill location text in the search form as well as in the node create/edit form. Will contribute this module if I get some time to generalize it. This module also saves the lat/lng values retrieved from YQL. So, each node have multiple location fields and multiple hidden lat/lng fields which gets populated in the submit method from the cache table.

So now, I have nodes which have fields populated with location name and lat/lng values. I will now hook into apachesolr_index_document_build()

<?php
function example_search_apachesolr_index_document_build($document, $entity, $entity_type, $env_id) {
 
$location = array();
 
$country = array();
 
$lat_lng = array();
  if (isset(
$entity->field_address_or_location['und'])) {
    foreach (
$entity->field_address_or_location['und'] as $data) {
     
$location[] = $data['safe_value'];
    }
    foreach (
$entity->field_address_location_lat_lng['und'] as $data) {
     
$lat_lng[] = $data['safe_value'];
    }

   
//Now we have the prepared arrays, just send it to Solr
   
$document->locm_jem = $lat_lng;
   
$document->sm_location = $location;
  }
}
//Do check the raw indexed data - to actually see its being saved or not
?>

Now we are done with storing/indexing the data. Next step is to alter the query and search based on radius.

Query alter to search based on lat/lng values

Here I am doing a quick content-type filtration. The $_SESSION['jem_search_latlng'] is set on a custom-form submit - more on this later.

<?php
function example_search_apachesolr_query_alter($query) {
 
$radius = 200; //Later I will change this to a $_SESSION value, which will make it dynamic

 
if (arg(0) == 'Content-Type-A') {
   
$query->addFilter("bundle", "type_a"); //Content type filtration
 
}
  if (
arg(0) == 'Content-Type-A' && isset($_SESSION['search_latlng'])) {
   
$ll = str_replace(' ', '', $_SESSION['search_latlng']); //modifying a little to fit into solr requirements
   
$geo = "{!geofilt pt = $ll sfield=locm_jem d=$radius}";
   
$query->addFilter("_query_", $geo);
  }

  if (
arg(0) == 'Content-Type-B') {
   
$query->addFilter("bundle", "type_b");
  }
  if (
arg(0) == 'Content-Type-B' && isset($_SESSION['search_latlng'])) {
   
$ll = str_replace(' ', '', $_SESSION['search_latlng']);
   
$geo = "{!geofilt pt = $ll sfield=locm_jem d=$radius}";
   
$query->addFilter("_query_", $geo);
  }
}
?>

That's it! we are done with Solr. Now, we need to create a custom form, put it in a block, show it the search pages and hide the default Solr search form

Creation of form and putting in a block is easy and I hope you can do it on your own. Basically its a form with two text fields. On submit, it sets

<?php
$form_state
['redirect'] = 'Content-Type-B/' . $form_state['input']['what'];
?>

and sets the
<?php
$_SESSION
['search_latlng'];
?>
with lat/lng vaules.

I hope this doc helps you. If you need any more info/help in this regard, just put on comments.

Page status

Needs technical review

Log in to edit this page

About this page

Drupal version
Drupal 7.x
Audience
Contributors, Programmers
Level
Intermediate, Advanced
Keywords
Apache Solr, geo data, search, solr
Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.
nobody click here