Grouping Values in Apache Solr Facets

It is common nowadays for Drupal sites to offload search duties to Solr by employing the Apache Solr Search and Facet API modules. Working together, these two modules can automatically build search facets that display filters for various aspects of the content, such as the content type, or taxonomy terms. In certain cases, it might be necessary to influence the way those facets filter content. This post will discuss a scenario where we may want to group multiple filters together inside a facet block such that they only appear as one item.

This method may be useful if the site has too many items in a facet — for instance, too many content types, or taxonomy terms — or some of them are secondary with less importance. In this following example, we have three content types, Article, Blog post, and Discussion, and we wish to group Article and Blog post so that they appear as Press instead. Selecting Press in the facet would therefore yield both Article and Blog post results. The content type facet for this site would look as follows:

In order to change how items appear in the facet, we need to modify the corresponding values in the search index. The Apache Solr module provides the hook_apachesolr_index_document_build hook for this exact purpose. This hook is called before the Drupal module sends data to the Solr server, and gives us a chance to modify what will be stored in the index. The hook signature is the following:

hook_apachesolr_index_document_build(ApacheSolrDocument $document, $entity, $entity_type)

$document is an object representing the data that will be sent to Solr, and $entity is the entity — most often node — being indexed. Here we can change the value of the bundle field in the Solr document. This will cause Solr to record this entity as if it was a different content type, which, in turn, will also change the facet filter appearing on the site. The code snippet below shows the implementation of the Solr hook that achieves this.

/**
 * Implements hook_apachesolr_index_document_build().
 */
function group_facet_apachesolr_index_document_build(ApacheSolrDocument $document, $entity, $entity_type) {

  if (in_array($entity->type, array('article', 'blog_post'))) {
    // These types are grouped into the 'Press' content type.
    $document->setField('bundle', array('Press'));
  }

}

In the $document object, the properties are protected, so we need to call the setField() method to modify them. This hook implementation will change the bundle property to Press for each Article and Blog post content as they are being indexed. As an end result, the content type facet will have one Press item in place of the former Article and Blog post items, as the screenshot illustrates below.