You are here

protected function SearchApiSolrBackend::extractResults in Search API Solr 4.x

Same name and namespace in other branches
  1. 8.3 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::extractResults()
  2. 8 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::extractResults()
  3. 8.2 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::extractResults()

Extract results from a Solr response.

Parameters

\Drupal\search_api\Query\QueryInterface $query: The Search API query object.

\Solarium\Core\Query\Result\ResultInterface $result: A Solarium select response object.

Return value

\Drupal\search_api\Query\ResultSetInterface A result set object.

Throws

\Drupal\search_api\SearchApiException

1 call to SearchApiSolrBackend::extractResults()
SearchApiSolrBackend::search in src/Plugin/search_api/backend/SearchApiSolrBackend.php
Options on $query prefixed by 'solr_param_' will be passed natively to Solr as query parameter without the prefix. For example you can set the "Minimum Should Match" parameter 'mm' to '75%' like this:

File

src/Plugin/search_api/backend/SearchApiSolrBackend.php, line 2591

Class

SearchApiSolrBackend
Apache Solr backend for search api.

Namespace

Drupal\search_api_solr\Plugin\search_api\backend

Code

protected function extractResults(QueryInterface $query, ResultInterface $result) {
  $index = $query
    ->getIndex();
  $fields = $index
    ->getFields(TRUE);
  $site_hash = $this
    ->getTargetedSiteHash($index);

  // We can find the item ID and the score in the special 'search_api_*'
  // properties. Mappings are provided for these properties in
  // SearchApiSolrBackend::getSolrFieldNames().
  $language_unspecific_field_names = $this
    ->getSolrFieldNames($index);
  $id_field = $language_unspecific_field_names['search_api_id'];
  $score_field = $language_unspecific_field_names['search_api_relevance'];
  $language_field = $language_unspecific_field_names['search_api_language'];
  $backend_defined_fields = [];

  /** @var \Solarium\Component\Result\Debug\DocumentSet $explain */
  $explain = NULL;
  $search_api_retrieved_field_values = $query
    ->getOption('search_api_retrieved_field_values', []);
  if (in_array('search_api_solr_score_debugging', $search_api_retrieved_field_values)) {
    if ($debug = $result
      ->getDebug()) {
      $explain = $debug
        ->getExplain();
      $backend_defined_fields = $this
        ->getBackendDefinedFields($query
        ->getIndex());
    }
  }

  // Set up the results array.
  $result_set = $query
    ->getResults();
  $result_set
    ->setExtraData('search_api_solr_response', $result
    ->getData());

  // In some rare cases (e.g., MLT query with nonexistent ID) the response
  // will be NULL.
  $is_grouping = $result instanceof Result && $result
    ->getGrouping();
  if (!$result
    ->getResponse() && !$is_grouping) {
    $result_set
      ->setResultCount(0);
    return $result_set;
  }

  // If field collapsing has been enabled for this query, we need to process
  // the results differently.
  $grouping = $query
    ->getOption('search_api_grouping');
  if (!empty($grouping['use_grouping'])) {
    $docs = [];
    $resultCount = 0;
    if ($result_set
      ->hasExtraData('search_api_solr_response')) {
      $response = $result_set
        ->getExtraData('search_api_solr_response');
      foreach ($grouping['fields'] as $field) {

        // @todo handle languages
        $solr_field_name = $language_unspecific_field_names[$field];
        if (!empty($response['grouped'][$solr_field_name])) {
          $resultCount = count($response['grouped'][$solr_field_name]);
          foreach ($response['grouped'][$solr_field_name]['groups'] as $group) {
            foreach ($group['doclist']['docs'] as $doc) {
              $docs[] = $doc;
            }
          }
        }
      }

      // Set a default number then get the groups number if possible.
      $result_set
        ->setResultCount($resultCount);
      if (count($grouping['fields']) == 1) {
        $field = reset($grouping['fields']);

        // @todo handle languages
        $solr_field_name = $language_unspecific_field_names[$field];
        if (isset($response['grouped'][$solr_field_name]['ngroups'])) {
          $result_set
            ->setResultCount($response['grouped'][$solr_field_name]['ngroups']);
        }
      }
    }
  }
  else {
    $result_set
      ->setResultCount($result
      ->getNumFound());
    $docs = $result
      ->getDocuments();
  }

  // Add each search result to the results array.

  /** @var \Solarium\QueryType\Select\Result\Document $doc */
  foreach ($docs as $doc) {
    if (is_array($doc)) {
      $doc_fields = $doc;
    }
    else {

      /** @var \Solarium\QueryType\Select\Result\Document $doc */
      $doc_fields = $doc
        ->getFields();
    }
    if (empty($doc_fields[$id_field])) {
      throw new SearchApiSolrException(sprintf('The result does not contain the essential ID field "%s".', $id_field));
    }
    $item_id = $doc_fields[$id_field];

    // For items coming from a different site, we need to adapt the item ID.
    if (isset($doc_fields['hash']) && !$this->configuration['site_hash'] && $doc_fields['hash'] != $site_hash) {
      $item_id = $doc_fields['hash'] . '--' . $item_id;
    }
    $result_item = NULL;
    if (Utility::hasIndexJustSolrDatasources($index)) {
      $datasource = '';
      if ($index
        ->isValidDatasource('solr_document')) {
        $datasource = 'solr_document';
      }
      elseif ($index
        ->isValidDatasource('solr_multisite_document')) {
        $datasource = 'solr_multisite_document';
      }

      /** @var \Drupal\search_api_solr\SolrDocumentFactoryInterface $solr_document_factory */
      $solr_document_factory = \Drupal::getContainer()
        ->get($datasource . '.factory');
      $result_item = $this->fieldsHelper
        ->createItem($index, $datasource . '/' . $item_id);

      // Create the typed data object for the Item immediately after the query
      // has been run. Doing this now can prevent the Search API from having
      // to query for individual documents later.
      $result_item
        ->setOriginalObject($solr_document_factory
        ->create($result_item));
    }
    else {
      $result_item = $this->fieldsHelper
        ->createItem($index, $item_id);
    }
    if ($language_field && isset($doc_fields[$language_field])) {
      $language_id = $doc_fields[$language_field];
      $result_item
        ->setLanguage($language_id);
      $field_names = $this
        ->getLanguageSpecificSolrFieldNames($language_id, $index);
    }
    else {
      $field_names = $language_unspecific_field_names;
    }
    $result_item
      ->setExtraData('search_api_solr_document', $doc);
    if (isset($doc_fields[$score_field])) {
      $result_item
        ->setScore($doc_fields[$score_field]);
      unset($doc_fields[$score_field]);
    }
    unset($doc_fields[$id_field]);

    // The language field should not be removed. We keep it in the values as
    // well for backward compatibility and for easy access.
    // Extract properties from the Solr document, translating from Solr to
    // Search API property names. This reverses the mapping in
    // SearchApiSolrBackend::getSolrFieldNames().
    foreach ($field_names as $search_api_property => $solr_property) {
      if (isset($doc_fields[$solr_property]) && isset($fields[$search_api_property])) {
        $doc_field = is_array($doc_fields[$solr_property]) ? $doc_fields[$solr_property] : [
          $doc_fields[$solr_property],
        ];
        $field = clone $fields[$search_api_property];
        foreach ($doc_field as &$value) {

          // The prefixes returned by Utility::getDataTypeInfo() are suitable
          // even for non Drupal Solr Documents here.
          $type_info = Utility::getDataTypeInfo($field
            ->getType()) + [
            'prefix' => '_',
          ];
          switch (substr($type_info['prefix'], 0, 1)) {
            case 'd':

              // Field type conversions
              // Date fields need some special treatment to become valid date
              // values (i.e., timestamps) again.
              if (preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/', $value)) {
                $value = strtotime($value);
              }
              break;
            case 't':
              $value = new TextValue($value);
          }
        }
        unset($value);
        $field
          ->setValues($doc_field);
        $result_item
          ->setField($search_api_property, $field);
      }
    }
    $solr_id = Utility::hasIndexJustSolrDatasources($index) ? str_replace('solr_document/', '', $result_item
      ->getId()) : $this
      ->createId($this
      ->getTargetedSiteHash($index), $this
      ->getTargetedIndexId($index), $result_item
      ->getId());
    $this
      ->getHighlighting($result
      ->getData(), $solr_id, $result_item, $field_names);
    if ($explain) {
      if ($explain_doc = $explain
        ->getDocument($solr_id)) {
        $backend_defined_fields['search_api_solr_score_debugging']
          ->setValues([
          $explain_doc
            ->__toString(),
        ]);
        $result_item
          ->setField('search_api_solr_score_debugging', clone $backend_defined_fields['search_api_solr_score_debugging']);
      }
    }
    $result_set
      ->addResultItem($result_item);
  }
  return $result_set;
}