/** * Tests the processor's preprocessSearchQuery() method. */ public function testPreprocessSearchQuery() { $index = $this->getMock('Drupal\\search_api\\IndexInterface'); $index->expects($this->any())->method('status')->will($this->returnValue(TRUE)); /** @var \Drupal\search_api\IndexInterface $index */ $this->processor->setIndex($index); $query = Utility::createQuery($index); $keys = array('#conjunction' => 'AND', 'foo', 'bar', 'bar foo'); $query->keys($keys); $this->processor->setConfiguration(array('stopwords' => array('foobar', 'bar', 'barfoo'))); $this->processor->preprocessSearchQuery($query); unset($keys[1]); $this->assertEquals($keys, $query->getKeys()); $results = Utility::createSearchResultSet($query); $this->processor->postprocessSearchResults($results); $this->assertEquals(array('bar'), $results->getIgnoredSearchKeys()); }
/** * {@inheritdoc} */ public function search(QueryInterface $query) { $this->checkError(__FUNCTION__); $results = Utility::createSearchResultSet($query); $result_items = array(); $datasources = $query->getIndex()->getDatasources(); /** @var \Drupal\search_api\Datasource\DatasourceInterface $datasource */ $datasource = reset($datasources); $datasource_id = $datasource->getPluginId(); if ($query->getKeys() && $query->getKeys()[0] == 'test') { $item_id = Utility::createCombinedId($datasource_id, '1'); $item = Utility::createItem($query->getIndex(), $item_id, $datasource); $item->setScore(2); $item->setExcerpt('test'); $result_items[$item_id] = $item; } elseif ($query->getOption('search_api_mlt')) { $item_id = Utility::createCombinedId($datasource_id, '2'); $item = Utility::createItem($query->getIndex(), $item_id, $datasource); $item->setScore(2); $item->setExcerpt('test test'); $result_items[$item_id] = $item; } else { $item_id = Utility::createCombinedId($datasource_id, '1'); $item = Utility::createItem($query->getIndex(), $item_id, $datasource); $item->setScore(1); $result_items[$item_id] = $item; $item_id = Utility::createCombinedId($datasource_id, '2'); $item = Utility::createItem($query->getIndex(), $item_id, $datasource); $item->setScore(1); $result_items[$item_id] = $item; } $results->setResultCount(count($result_items)); return $results; }
/** * Tests field highlighting and excerpts with two items. */ public function testPostprocessSearchResultsWithTwoItems() { $query = $this->getMock('Drupal\\search_api\\Query\\QueryInterface'); $query->expects($this->atLeastOnce())->method('getKeys')->will($this->returnValue(array('#conjunction' => 'OR', 'foo'))); /** @var \Drupal\search_api\Query\QueryInterface $query */ /** @var \Drupal\search_api\IndexInterface|\PHPUnit_Framework_MockObject_MockObject $index */ $index = $this->getMock('Drupal\\search_api\\IndexInterface'); $body_field = Utility::createField($index, 'body'); $body_field->setType('text'); $body_field->setDatasourceId('entity:node'); $body_field->setPropertyPath('body'); $index->expects($this->atLeastOnce())->method('getFields')->will($this->returnValue(array('body' => $body_field))); $this->processor->setIndex($index); $body_values = array('Some foo value', 'foo bar'); $fields = array('entity:node/body' => array('type' => 'text', 'values' => $body_values)); $items = $this->createItems($index, 2, $fields); $items[$this->itemIds[1]]->getField('body')->setValues(array('The second item also contains foo in its body.')); $results = Utility::createSearchResultSet($query); $results->setResultItems($items); $results->setResultCount(1); $this->processor->postprocessSearchResults($results); $output = $results->getExtraData('highlighted_fields'); $this->assertEquals('Some <strong>foo</strong> value', $output[$this->itemIds[0]]['body'][0], 'Highlighting is correctly applied to first body field value.'); $this->assertEquals('<strong>foo</strong> bar', $output[$this->itemIds[0]]['body'][1], 'Highlighting is correctly applied to second body field value.'); $this->assertEquals('The second item also contains <strong>foo</strong> in its body.', $output[$this->itemIds[1]]['body'][0], 'Highlighting is correctly applied to second item.'); $excerpt1 = '… Some <strong>foo</strong> value … <strong>foo</strong> bar …'; $excerpt2 = '… The second item also contains <strong>foo</strong> in its body. …'; $this->assertEquals($excerpt1, $items[$this->itemIds[0]]->getExcerpt(), 'Correct excerpt created from two text fields.'); $this->assertEquals($excerpt2, $items[$this->itemIds[1]]->getExcerpt(), 'Correct excerpt created for second item.'); }
/** * {@inheritdoc} */ public function search(QueryInterface $query) { $this->ignored = $this->warnings = array(); $index = $query->getIndex(); $db_info = $this->getIndexDbInfo($index); if (!isset($db_info['field_tables'])) { throw new SearchApiException(new FormattableMarkup('Unknown index @id.', array('@id' => $index->id()))); } $fields = $this->getFieldInfo($index); $db_query = $this->createDbQuery($query, $fields); $results = Utility::createSearchResultSet($query); $skip_count = $query->getOption('skip result count'); if (!$skip_count) { $count_query = $db_query->countQuery(); $results->setResultCount($count_query->execute()->fetchField()); } if ($skip_count || $results->getResultCount()) { if ($query->getOption('search_api_facets')) { $results->setExtraData('search_api_facets', $this->getFacets($query, clone $db_query)); } $query_options = $query->getOptions(); if (isset($query_options['offset']) || isset($query_options['limit'])) { $offset = isset($query_options['offset']) ? $query_options['offset'] : 0; $limit = isset($query_options['limit']) ? $query_options['limit'] : 1000000; $db_query->range($offset, $limit); } $sort = $query->getSorts(); if ($sort) { foreach ($sort as $field_name => $order) { if ($order != 'ASC' && $order != 'DESC') { $msg = $this->t('Unknown sort order @order. Assuming "ASC".', array('@order' => $order)); $this->warnings[(string) $msg] = 1; $order = 'ASC'; } if ($field_name == 'search_api_relevance') { $db_query->orderBy('score', $order); continue; } if ($field_name == 'search_api_id') { $db_query->orderBy('item_id', $order); continue; } if (!isset($fields[$field_name])) { throw new SearchApiException(new FormattableMarkup('Trying to sort on unknown field @field.', array('@field' => $field_name))); } $alias = $this->getTableAlias(array('table' => $db_info['index_table']), $db_query); $db_query->orderBy($alias . '.' . $fields[$field_name]['column'], $order); // PostgreSQL automatically adds a field to the SELECT list when // sorting on it. Therefore, if we have aggregations present we also // have to add the field to the GROUP BY (since Drupal won't do it for // us). However, if no aggregations are present, a GROUP BY would lead // to another error. Therefore, we only add it if there is already a // GROUP BY. if ($db_query->getGroupBy()) { $db_query->groupBy($alias . '.' . $fields[$field_name]['column']); } } } else { $db_query->orderBy('score', 'DESC'); } $result = $db_query->execute(); foreach ($result as $row) { $item = Utility::createItem($index, $row->item_id); $item->setScore($row->score / self::SCORE_MULTIPLIER); $results->addResultItem($item); } if ($skip_count && !empty($item)) { $results->setResultCount(1); } } $results->setWarnings(array_keys($this->warnings)); $results->setIgnoredSearchKeys(array_keys($this->ignored)); return $results; }
/** * Extract results from a Solr response. * * @param \Drupal\search_api\Query\QueryInterface $query * The Search API query object. * @param \Solarium\Core\Query\Result\ResultInterface $result * A Solarium select response object. * * @return \Drupal\search_api\Query\ResultSetInterface * A result set object. */ protected function extractResults(QueryInterface $query, ResultInterface $result) { $index = $query->getIndex(); $field_names = $this->getFieldNames($index); $fields = $index->getFields(); $site_hash = SearchApiSolrUtility::getSiteHash(); // We can find the item ID and the score in the special 'search_api_*' // properties. Mappings are provided for these properties in // SearchApiSolrBackend::getFieldNames(). $id_field = $field_names['search_api_id']; $score_field = $field_names['search_api_relevance']; // Set up the results array. $result_set = SearchApiUtility::createSearchResultSet($query); $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'); $docs = array(); if (!empty($grouping['use_grouping']) && $is_grouping) { // $docs = array(); // $result_set['result count'] = 0; // foreach ($grouping['fields'] as $field) { // if (!empty($response->grouped->{$fields[$field]})) { // $result_set['result count'] += $response->grouped->{$fields[$field]}->ngroups; // foreach ($response->grouped->{$fields[$field]}->groups as $group) { // foreach ($group->doclist->docs as $doc) { // $docs[] = $doc; // } // } // } // } } 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) { $doc_fields = $doc->getFields(); $item_id = $doc_fields[$id_field]; // For items coming from a different site, we need to adapt the item ID. if (!$this->configuration['site_hash'] && $doc_fields['hash'] != $site_hash) { $item_id = $doc_fields['hash'] . '--' . $item_id; } $result_item = SearchApiUtility::createItem($index, $item_id); $result_item->setScore($doc_fields[$score_field]); unset($doc_fields[$id_field], $doc_fields[$score_field]); // Extract properties from the Solr document, translating from Solr to // Search API property names. This reverses the mapping in // SearchApiSolrBackend::getFieldNames(). foreach ($field_names as $search_api_property => $solr_property) { if (isset($doc_fields[$solr_property])) { // Date fields need some special treatment to become valid date values // (i.e., timestamps) again. if (isset($fields[$search_api_property]) && $fields[$search_api_property]->getType() == 'date' && preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/', $doc_fields[$solr_property][0])) { $doc_fields[$solr_property][0] = strtotime($doc_fields[$solr_property][0]); } $field = SearchApiUtility::createField($index, $search_api_property); $field->setValues($doc_fields[$solr_property]); $result_item->setField($search_api_property, $field); } } $index_id = $this->getIndexId($index->id()); $solr_id = $this->createId($index_id, $result_item->getId()); $item_fields = $result_item->getFields(); $excerpt = $this->getSolrHelper()->getExcerpt($result->getData(), $solr_id, $item_fields, $field_names); if ($excerpt) { $result_item->setExcerpt($excerpt); } $result_set->addResultItem($result_item); } // Check for spellcheck suggestions. /*if (module_exists('search_api_spellcheck') && $query->getOption('search_api_spellcheck')) { $result_set->setExtraData('search_api_spellcheck', new SearchApiSpellcheckSolr($result)); }*/ return $result_set; }
/** * {@inheritdoc} */ public function search(QueryInterface $query) { // This plugin does not support searching and we therefore just return an empty search result. $results = Utility::createSearchResultSet($query); $results->setResultItems(array()); $results->setResultCount(0); return $results; }