You are here

public function SearchApiSolrBackend::search in Search API Solr 8

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::search()
  2. 8.2 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::search()
  3. 4.x src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::search()

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:

$query
  ->setOption('solr_param_mm', '75%');

Overrides BackendSpecificInterface::search

File

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

Class

SearchApiSolrBackend
Apache Solr backend for search api.

Namespace

Drupal\search_api_solr\Plugin\search_api\backend

Code

public function search(QueryInterface $query) {
  $mlt_options = $query
    ->getOption('search_api_mlt');
  if (!empty($mlt_options)) {
    $query
      ->addTag('mlt');
  }

  // Call an object oriented equivalent to hook_search_api_query_alter().
  $this
    ->alterSearchApiQuery($query);

  // Get field information.

  /** @var \Drupal\search_api\Entity\Index $index */
  $index = $query
    ->getIndex();
  $index_id = $this
    ->getIndexId($index
    ->id());
  $field_names = $this
    ->getSolrFieldNames($index);
  $connector = $this
    ->getSolrConnector();
  $solarium_query = NULL;
  $index_fields = $index
    ->getFields();
  $index_fields += $this
    ->getSpecialFields($index);
  if ($query
    ->hasTag('mlt')) {
    $solarium_query = $this
      ->getMoreLikeThisQuery($query, $index_id, $index_fields, $field_names);
  }
  else {

    // Instantiate a Solarium select query.
    $solarium_query = $connector
      ->getSelectQuery();

    // Extract keys.
    $keys = $query
      ->getKeys();
    if (is_array($keys)) {
      $keys = $this
        ->flattenKeys($keys);
    }
    if (!empty($keys)) {

      // Set them.
      $solarium_query
        ->setQuery($keys);
    }

    // Set searched fields.
    $search_fields = $this
      ->getQueryFulltextFields($query);
    $query_fields = [];
    $query_fields_boosted = [];
    foreach ($search_fields as $search_field) {
      $query_fields[] = $field_names[$search_field];

      /** @var \Drupal\search_api\Item\FieldInterface $field */
      $field = $index_fields[$search_field];
      $boost = $field
        ->getBoost() ? '^' . $field
        ->getBoost() : '';
      $query_fields_boosted[] = $field_names[$search_field] . $boost;
    }
    $solarium_query
      ->getEDisMax()
      ->setQueryFields(implode(' ', $query_fields_boosted));

    // Set highlighting and excerpt.
    $this
      ->setHighlighting($solarium_query, $query, $query_fields);
  }
  $options = $query
    ->getOptions();

  // Set basic filters.
  $filter_queries = $this
    ->getFilterQueries($query, $field_names, $index_fields, $options);
  foreach ($filter_queries as $id => $filter_query) {
    $solarium_query
      ->createFilterQuery('filters_' . $id)
      ->setQuery($filter_query['query'])
      ->addTags($filter_query['tags']);
  }
  $query_helper = $connector
    ->getQueryHelper($solarium_query);

  // Set the Index filter.
  $solarium_query
    ->createFilterQuery('index_id')
    ->setQuery('index_id:' . $query_helper
    ->escapePhrase($index_id));

  // Set the site hash filter, if enabled.
  if ($this->configuration['site_hash']) {
    $site_hash = $query_helper
      ->escapePhrase(SearchApiSolrUtility::getSiteHash());
    $solarium_query
      ->createFilterQuery('site_hash')
      ->setQuery('hash:' . $site_hash);
  }

  // @todo Make this more configurable so that Search API can choose which
  //   fields it wants to fetch. But don't skip the minimum required fields as
  //   currently set in the "else" path.
  //   @see https://www.drupal.org/node/2880674
  if (!empty($this->configuration['retrieve_data'])) {
    $solarium_query
      ->setFields([
      '*',
      'score',
    ]);
  }
  else {
    $returned_fields = [
      $field_names['search_api_id'],
      $field_names['search_api_language'],
      $field_names['search_api_relevance'],
    ];
    if (!$this->configuration['site_hash']) {
      $returned_fields[] = 'hash';
    }
    $solarium_query
      ->setFields($returned_fields);
  }

  // Set sorts.
  $this
    ->setSorts($solarium_query, $query, $field_names);

  // Set facet fields. setSpatial() might add more facets.
  $this
    ->setFacets($query, $solarium_query, $field_names);

  // Handle spatial filters.
  if (isset($options['search_api_location'])) {
    $this
      ->setSpatial($solarium_query, $options['search_api_location'], $field_names);
  }

  // Handle spatial filters.
  if (isset($options['search_api_rpt'])) {
    if (version_compare($connector
      ->getSolrVersion(), 5.1, '>=')) {
      $this
        ->setRpt($solarium_query, $options['search_api_rpt'], $field_names);
    }
    else {
      \Drupal::logger('search_api_solr')
        ->error('Rpt data type feature is only supported by Solr version 5.1 or higher.');
    }
  }

  // Handle field collapsing / grouping.
  $grouping_options = $query
    ->getOption('search_api_grouping');
  if (!empty($grouping_options['use_grouping'])) {
    $this
      ->setGrouping($solarium_query, $query, $grouping_options, $index_fields, $field_names);
  }
  if (isset($options['offset'])) {
    $solarium_query
      ->setStart($options['offset']);
  }
  $rows = isset($options['limit']) ? $options['limit'] : 1000000;
  $solarium_query
    ->setRows($rows);
  if (!empty($options['search_api_spellcheck'])) {
    $solarium_query
      ->getSpellcheck();
  }
  foreach ($options as $option => $value) {
    if (strpos($option, 'solr_param_') === 0) {
      $solarium_query
        ->addParam(substr($option, 11), $value);
    }
  }
  $this
    ->applySearchWorkarounds($solarium_query, $query);
  try {

    // Allow modules to alter the solarium query.
    $this->moduleHandler
      ->alter('search_api_solr_query', $solarium_query, $query);
    $this
      ->preQuery($solarium_query, $query);

    // Send search request.
    $response = $connector
      ->search($solarium_query);
    $body = $response
      ->getBody();
    if (200 != $response
      ->getStatusCode()) {
      throw new SearchApiSolrException(strip_tags($body), $response
        ->getStatusCode());
    }
    $this
      ->alterSolrResponseBody($body, $query);
    $response = new Response($body, $response
      ->getHeaders());
    $result = $connector
      ->createSearchResult($solarium_query, $response);

    // Extract results.
    $results = $this
      ->extractResults($query, $result);

    // Add warnings, if present.
    if (!empty($warnings)) {
      foreach ($warnings as $warning) {
        $results
          ->addWarning($warning);
      }
    }

    // Extract facets.
    if ($result instanceof Result) {
      if ($facets = $this
        ->extractFacets($query, $result, $field_names)) {
        $results
          ->setExtraData('search_api_facets', $facets);
      }
    }
    $this->moduleHandler
      ->alter('search_api_solr_search_results', $results, $query, $result);
    $this
      ->postQuery($results, $query, $result);
  } catch (\Exception $e) {
    throw new SearchApiSolrException($this
      ->t('An error occurred while trying to search with Solr: @msg.', array(
      '@msg' => $e
        ->getMessage(),
    )), $e
      ->getCode(), $e);
  }
}