public function SearchApiSolrService::searchMultiple in Search API Solr 7
Implements SearchApiMultiServiceInterface::searchMultiple().
File
- includes/
service.inc, line 2329
Class
- SearchApiSolrService
- Search service class using Solr server.
Code
public function searchMultiple(SearchApiMultiQueryInterface $query) {
$time_method_called = microtime(TRUE);
// Get field information
$solr_fields = array(
'search_api_id' => 'item_id',
'search_api_relevance' => 'score',
'search_api_multi_index' => 'index_id',
);
$fields = array(
'search_api_multi_index' => array(
'type' => 'string',
),
);
foreach ($query
->getIndexes() as $index) {
if (empty($index->options['fields'])) {
continue;
}
$prefix = $this
->getIndexId($index->machine_name) . ':';
foreach ($this
->getFieldNames($index) as $field => $key) {
if (!isset($solr_fields[$field])) {
$solr_fields[$prefix . $field] = $key;
}
}
foreach ($index->options['fields'] as $field => $info) {
$fields[$prefix . $field] = $info;
}
}
// Extract keys
$keys = $query
->getKeys();
if (is_array($keys)) {
$keys = $this
->flattenKeys($keys);
}
// Set searched fields
$search_fields = $query
->getFields();
$qf = array();
foreach ($search_fields as $f) {
$boost = isset($fields[$f]['boost']) ? '^' . $fields[$f]['boost'] : '';
$qf[] = $solr_fields[$f] . $boost;
}
// Extract filters
$filter = $query
->getFilter();
$fq = $this
->createFilterQueries($filter, $solr_fields, $fields);
// Restrict search to searched indexes.
$index_filter = array();
$indexes = array();
foreach ($query
->getIndexes() as $index) {
$index_id = $this
->getIndexId($index->machine_name);
$indexes[$index_id] = $index;
$index_filter[] = 'index_id:' . call_user_func(array(
$this
->getConnectionClass(),
'phrase',
), $index_id);
}
$fq[] = implode(' OR ', $index_filter);
if (!empty($this->options['site_hash'])) {
// We don't need to escape the site hash, as that consists only of
// alphanumeric characters.
$fq[] = 'hash:' . search_api_solr_site_hash();
}
// Extract sort
$sort = array();
foreach ($query
->getSort() as $f => $order) {
$f = $solr_fields[$f];
if (substr($f, 0, 3) == 'ss_') {
$f = 'sort_' . substr($f, 3);
}
$order = strtolower($order);
$sort[] = "{$f} {$order}";
}
// Get facet fields
$facets = $query
->getOption('search_api_facets') ? $query
->getOption('search_api_facets') : array();
$facet_params = $this
->getFacetParams($facets, $solr_fields, $fq);
// Handle highlighting.
$highlight_params = $this
->getHighlightParams($query);
// Set defaults
if (!$keys) {
$keys = NULL;
}
$options = $query
->getOptions();
// Collect parameters
$params = array(
'fl' => 'item_id,index_id,score',
'qf' => $qf,
'fq' => $fq,
);
if (isset($options['offset'])) {
$params['start'] = $options['offset'];
}
if (isset($options['limit'])) {
$params['rows'] = $options['limit'];
}
if ($sort) {
$params['sort'] = implode(', ', $sort);
}
if (!empty($facet_params['facet.field'])) {
$params += $facet_params;
}
if (!empty($highlight_params)) {
$params += $highlight_params;
}
if (!empty($this->options['retrieve_data'])) {
$params['fl'] = '*,score';
}
// Retrieve http method from server options.
$http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
// Send search request
$time_processing_done = microtime(TRUE);
$this
->connect();
$call_args = array(
'query' => &$keys,
'params' => &$params,
'http_method' => &$http_method,
);
drupal_alter('search_api_solr_multi_query', $call_args, $query);
$response = $this->solr
->search($keys, $params, $http_method);
$time_query_done = microtime(TRUE);
// Extract results
$results = array();
$results['result count'] = $response->response->numFound;
$results['results'] = array();
$fulltext_fields_by_index = array();
foreach ($search_fields as $field) {
list($index_id, $field) = explode(':', $field, 2);
$fulltext_fields_by_index[$index_id][] = $field;
}
foreach ($response->response->docs as $id => $doc) {
$index_id = $doc->index_id;
if (isset($indexes[$index_id])) {
$index = $indexes[$index_id];
}
else {
$index = new SearchApiIndex(array(
'machine_name' => $index_id,
));
}
$fields = $this
->getFieldNames($index);
$field_options = $index->options['fields'];
$result = array(
'id' => NULL,
'index_id' => $index_id,
'score' => NULL,
'fields' => array(),
);
$solr_id = $this
->createId($index_id, $doc->item_id);
foreach ($fields as $search_api_property => $solr_property) {
if (isset($doc->{$solr_property})) {
$value = $doc->{$solr_property};
// Date fields need some special treatment to become valid date values
// (i.e., timestamps) again.
$first_value = $value;
while (is_array($first_value)) {
$first_value = reset($first_value);
}
if (isset($field_options[$search_api_property]['type']) && search_api_extract_inner_type($field_options[$search_api_property]['type']) === 'date' && preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/', $first_value)) {
$value = is_array($value) ? array_map('strtotime', $value) : strtotime($value);
}
$result['fields'][$search_api_property] = $value;
}
}
$fulltext_fields = isset($fulltext_fields_by_index[$index_id]) ? $fulltext_fields_by_index[$index_id] : array();
$excerpt = $this
->getExcerpt($response, $solr_id, $result['fields'], $fields, $fulltext_fields);
if ($excerpt) {
$result['excerpt'] = $excerpt;
}
// We can find the item id and score in the special 'search_api_*'
// properties. Mappings are provided for these properties in
// SearchApiSolrService::getFieldNames().
$result['id'] = $result['fields']['search_api_id'];
$result['score'] = $result['fields']['search_api_relevance'];
$results['results'][$id] = $result;
}
// Extract facets
if (isset($response->facet_counts->facet_fields)) {
$results['search_api_facets'] = array();
$facet_fields = $response->facet_counts->facet_fields;
// The key for the "missing" facet (empty string in the JSON). This will
// be either "" or "_empty_", depending on the PHP version.
$empty_key = key((array) json_decode('{"":5}'));
foreach ($facets as $delta => $info) {
$field = $solr_fields[$info['field']];
if (!empty($facet_fields->{$field})) {
$min_count = $info['min_count'];
$terms = $facet_fields->{$field};
if ($info['missing']) {
// We have to correctly incorporate the "missing" term ($empty_key).
// This will ensure that the term with the least results is dropped,
// if the limit would be exceeded.
if (isset($terms->{$empty_key})) {
if ($terms->{$empty_key} < $min_count) {
unset($terms->{$empty_key});
}
else {
$terms = (array) $terms;
arsort($terms);
if ($info['limit'] > 0 && count($terms) > $info['limit']) {
array_pop($terms);
}
}
}
}
elseif (isset($terms->{$empty_key})) {
$terms = clone $terms;
unset($terms->{$empty_key});
}
$type = isset($fields[$info['field']]['type']) ? search_api_extract_inner_type($fields[$info['field']]['type']) : 'string';
foreach ($terms as $term => $count) {
if ($count >= $min_count) {
if ($term === $empty_key) {
$term = '!';
}
elseif ($type == 'boolean') {
if ($term == 'true') {
$term = '"1"';
}
elseif ($term == 'false') {
$term = '"0"';
}
}
elseif ($type == 'date') {
$term = $term ? '"' . strtotime($term) . '"' : NULL;
}
else {
$term = "\"{$term}\"";
}
if ($term) {
$results['search_api_facets'][$delta][] = array(
'filter' => $term,
'count' => $count,
);
}
}
}
if (empty($results['search_api_facets'][$delta])) {
unset($results['search_api_facets'][$delta]);
}
}
}
}
drupal_alter('search_api_solr_multi_search_results', $results, $query, $response);
// Compute performance
$time_end = microtime(TRUE);
$results['performance'] = array(
'complete' => $time_end - $time_method_called,
'preprocessing' => $time_processing_done - $time_method_called,
'execution' => $time_query_done - $time_processing_done,
'postprocessing' => $time_end - $time_query_done,
);
return $results;
}