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()
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.
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
$form_state['redirect'] = 'Content-Type-B/' . $form_state['input']['what'];
and sets the $_SESSION['search_latlng'];
with lat/lng vaules.
Comments
Is the radius in KM or miles?
What are the units of the radius?