DrupalCon Paris 2009
Using Apache Solr for site-wide searching is fast, relatively simple to implement and povides a much slicker searching experience to your users than the default Drupal core search. Faceted searching is provided by the Apache Solr Search module. Fantastic!
If you're only interested in searching default node attributes and cck fields that use option widgets, that is.
This is how to add your own custom field to the index, and make it available to be searched on, assuming you have an Apache Solr instance up and running on your server.
I am also assuming you know how to write a module. The code here is to be added to your module, replacing my_module with your modules' name.
<?php
function my_module_apachesolr_update_index(&$document, $node){
// Get the value of the field from the node
// Note that this doesn't have to be a straight forward value... it can be the result of a query, the sum of two fields, anything really
$my_indexed_value = $node->field_myfield[0]['value'];
// Add the value to the document object that is sent to Apache Solr
$document->ss_myfield = $my_indexed_value;
}
?>It is very important to note the "ss_" bit of the ss_myfield attribute we created. This tells Apache Solr that this is a "String that is Sortable". We could also use "fs_" that would translate to "Float Sortable". For a complete listing of these naming convensions, look at schema.xml in the Apache Solr module directory.
This is the section you're interested in, in my currently instaled Apache Solr:
<dynamicField name="is_*" type="integer" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="im_*" type="integer" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="sis_*" type="sint" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="sim_*" type="sint" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="sm_*" type="string" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="tm_*" type="text" indexed="true" stored="true" multiValued="true" termVectors="true"/>
<dynamicField name="ss_*" type="string" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="ts_*" type="text" indexed="true" stored="true" multiValued="false" termVectors="true"/>
<dynamicField name="ds_*" type="date" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="dm_*" type="date" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="bm_*" type="boolean" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="bs_*" type="boolean" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="fs_*" type="sfloat" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="fm_*" type="sfloat" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="ps_*" type="sdouble" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="pm_*" type="sdouble" indexed="true" stored="true" multiValued="true"/>
<!-- Sortable version of the dynamic string field -->
<dynamicField name="sort_ss_*" type="sortString" indexed="true" stored="false"/>
<copyField source="ss_*" dest="sort_ss_*"/>
<!-- This field is used to store node access records, as opposed to CCK field data -->
<dynamicField name="nodeaccess*" type="integer" indexed="true" stored="false" multiValued="true"/>
<!-- The following causes solr to ignore any fields that don't already match an existing
field name or dynamic field, rather than reporting them as an error.
Alternately, change the type="ignored" to some other type e.g. "text" if you want
unknown fields indexed and/or stored by default -->
<dynamicField name="*" type="ignored" multiValued="true" />Great, now that it's added (and will now run on the next indexing of any content) we can re-index our content by going to admin/settings/apachesolr/index and clicking "Re-index all content" or even better "Delete the index". Click on the "running chron" link at the top of the content until all your content has been sent to Apache Solr for indexing.
After two minutes, Apache Solr will process all your indexing requests and your field should be visible in the index if you go to admin/reports/apachesolr.
Now that we have a custom field being indexed, we'll want to filter results based on its value...
<?php
function my_module_apachesolr_modify_query(&$query, &$params, $caller){
$query->add_filter('ss_my_field', 'My query');
}
?>And that's it! Check out http://lucene.apache.org/java/2_9_1/queryparsersyntax.html for the syntax of the filters you may add.
For a float range filter you may specify:
<?php
$query->add_filter('fs_my_field', '[50.00 TO 1000.00]');
?>Thanks to Robert Douglass and Diricia De Wet for their help in getting this to work!