Recently I was working on a Drupal website project that had to be rescued. The previous development team took various approaches to work on functionality that had to be put together. However, when we started to release features, the pieces of functionality could not be stitched together.
A particular example (I wanted to talk about) relates to using Drupal Views and Search API modules in order to build search pages. Many developers who used Search API know that it provides nice views integration, allowing to build views that utilise Search API indexes and servers to display the desired search results, build and configure facets – all within the Views interface.
Unfortunately, in this case, the search API was using a search index but the View that meant to be displaying search results using the Views’ Exposed filters option in combination with Better Exposed Filters module (to achieve Facet-like search experience). The end result was satisfactory from the display point of view, but lacking good logic in getting the correct search results.
To avoid rebuilding the about to go-live search page, I decided to look into the way Search API module handles the search. This approach could be used to get the list of node IDs matching the search criteria.
After creating a Search API Server and Index (they both existed in my case), all I needed to do was to query the index, get the node IDs for the search results in the correct order and filter the views results using those node IDs.
The Views exposed form uses the URL query string to pass the values via GET. Let’s assume our exposed form uses a text field for full-text search and the query param machine name is ‘search’. We then could build a search_api_query following this example:
// Use params to grab our search phrase from the URI. $params = drupal_get_query_parameters(); $nids = array(); $content_type = 'page'; $search = search_api_query($content_type); $search->keys($params['search']); // Adding search field to use for Keys matching. // We use 'title' field only in this example. If more fields are required, // pass their machine names into the $search->fields() as array values: $search->fields(array('title')); // Order search results by keyword relevance. $search->sort('search_api_relevance'); $response = $search->execute();
Next, pass the node IDs from the Search API Index to our view via hook_views_query_alter(). If you used your view via views_embed_view(‘view_name’, ‘display_id’, array(nids-comma-separated) function, it takes multiple arguments (your view must be set up to use Contextual filter Node ID in order to use it this way).
Summary of Views and Search API. The end result
In our example, we used a custom module. We created hook_views_query_alter() and add the following complete code spinnet into it:
/** * Implements hook_views_query_alter(). */ function custommodule_views_query_alter(&$view, &$query) { switch ($view->name) { case '<fixme-view-name>': switch ($view->current_display) { case '<fixme-view-display>': // Use params to grab our search phrase from the URI. $params = drupal_get_query_parameters(); $nids = array(); $search = search_api_query('page'); $search->keys($params['search']); // Adding search field to use for Keys matching. // We use 'title' field only in this example. $search->fields(array('title')); // Order search results by reference. $search->sort('search_api_relevance'); $response = $search->execute(); if (!empty($response['results'])) { $nids = array_keys($response['results']); $query->add_where(1, 'node.nid', $nids, 'IN'); } break; } break; } }
Hello, I read your post and was wondering, if you could explain your phrase “The end result was satisfactory from the display point of view, but lacking good logic in getting the correct search results.”
Why is it “lacking good logic” to utilize exposed filters to narrow down the search api query results. It seems that in both cases the result count will be the same.
Regards, David
The order of search results delivered via a View with exposed filters does not align well with the configurable Search API’s “relevancy” factor. The Search API allows to configure the weight of different aspects of the rendered entity and gives the flexibility to deliver the search results in a more relevant way.
In that specific case, we had no time to rebuild the Views page, and the results were delivered in a wrong order. Plugging in a small in-code bridge to use the Search API, I was able to resolve the “relevancy” (order of search results) problem quickly.