public function SearchApiSolrService::getAutocompleteSuggestions in Search API Solr 7
File
- includes/
service.inc, line 2114
Class
- SearchApiSolrService
- Search service class using Solr server.
Code
public function getAutocompleteSuggestions(SearchApiQueryInterface $query, SearchApiAutocompleteSearch $search, $incomplete_key, $user_input) {
$suggestions = array();
// Reset request handler
$this->request_handler = NULL;
// Turn inputs to lower case, otherwise we get case sensivity problems.
$incomp = drupal_strtolower($incomplete_key);
$index = $query
->getIndex();
$fields = $this
->getFieldNames($index);
$complete = $query
->getOriginalKeys();
// Extract keys
$keys = $query
->getKeys();
if (is_array($keys)) {
$keys_array = array();
while ($keys) {
reset($keys);
if (!element_child(key($keys))) {
array_shift($keys);
continue;
}
$key = array_shift($keys);
if (is_array($key)) {
$keys = array_merge($keys, $key);
}
else {
$keys_array[$key] = $key;
}
}
$keys = $this
->flattenKeys($query
->getKeys());
}
else {
$keys_array = drupal_map_assoc(preg_split('/[-\\s():{}\\[\\]\\\\"]+/', $keys, -1, PREG_SPLIT_NO_EMPTY));
}
if (!$keys) {
$keys = NULL;
}
// Set searched fields
$search_fields = $this
->getQueryFields($query);
$qf = array();
foreach ($search_fields as $f) {
$qf[] = $fields[$f];
}
// Extract filters
$fq = $this
->createFilterQueries($query
->getFilter(), $fields, $index->options['fields']);
$index_id = $this
->getIndexId($index->machine_name);
$fq[] = 'index_id:' . call_user_func(array(
$this
->getConnectionClass(),
'phrase',
), $index_id);
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();
}
// Autocomplete magic
$facet_fields = array();
foreach ($search_fields as $f) {
$facet_fields[] = $fields[$f];
}
$limit = $query
->getOption('limit', 10);
$params = array(
'qf' => $qf,
'fq' => $fq,
'rows' => 0,
'facet' => 'true',
'facet.field' => $facet_fields,
'facet.prefix' => $incomp,
'facet.limit' => $limit * 5,
'facet.mincount' => 1,
'spellcheck' => !isset($this->options['autocorrect_spell']) || $this->options['autocorrect_spell'] ? 'true' : 'false',
'spellcheck.count' => 1,
);
// Retrieve http method from server options.
$http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
$call_args = array(
'query' => &$keys,
'params' => &$params,
'http_method' => &$http_method,
);
if ($this->request_handler) {
$this
->setRequestHandler($this->request_handler, $call_args);
}
$second_pass = !isset($this->options['autocorrect_suggest_words']) || $this->options['autocorrect_suggest_words'];
$alter_data = array(
'search' => $search,
'query' => $query,
'incomplete_key' => $incomplete_key,
'user_input' => $user_input,
);
for ($i = 0; $i < ($second_pass ? 2 : 1); ++$i) {
try {
// Send search request
$this
->connect();
drupal_alter('search_api_solr_query', $call_args, $query);
$this
->preQuery($call_args, $query);
$response = $this->solr
->search($keys, $params, $http_method);
$alter_data['responses'][] = $response;
if (!empty($response->spellcheck->suggestions)) {
$replace = array();
foreach ($response->spellcheck->suggestions as $word => $data) {
$replace[$word] = $data->suggestion[0];
}
$corrected = str_ireplace(array_keys($replace), array_values($replace), $user_input);
if ($corrected != $user_input) {
array_unshift($suggestions, array(
'prefix' => t('Did you mean') . ':',
'user_input' => $corrected,
));
}
}
$matches = array();
if (isset($response->facet_counts->facet_fields)) {
foreach ($response->facet_counts->facet_fields as $terms) {
foreach ($terms as $term => $count) {
if (isset($matches[$term])) {
// If we just add the result counts, we can easily get over the
// total number of results if terms appear in multiple fields.
// Therefore, we just take the highest value from any field.
$matches[$term] = max($matches[$term], $count);
}
else {
$matches[$term] = $count;
}
}
}
if ($matches) {
// Eliminate suggestions that are too short or already in the query.
foreach ($matches as $term => $count) {
if (strlen($term) < 3 || isset($keys_array[$term])) {
unset($matches[$term]);
}
}
// Don't suggest terms that are too frequent (by default in more
// than 90% of results).
$result_count = $response->response->numFound;
$max_occurrences = $result_count * variable_get('search_api_solr_autocomplete_max_occurrences', 0.9);
if (($max_occurrences >= 1 || $i > 0) && $max_occurrences < $result_count) {
foreach ($matches as $match => $count) {
if ($count > $max_occurrences) {
unset($matches[$match]);
}
}
}
// The $count in this array is actually a score. We want the
// highest ones first.
arsort($matches);
// Shorten the array to the right ones.
$additional_matches = array_slice($matches, $limit - count($suggestions), NULL, TRUE);
$matches = array_slice($matches, 0, $limit, TRUE);
// Build suggestions using returned facets
$incomp_length = strlen($incomp);
foreach ($matches as $term => $count) {
if (drupal_strtolower(substr($term, 0, $incomp_length)) == $incomp) {
$suggestions[] = array(
'suggestion_suffix' => substr($term, $incomp_length),
'term' => $term,
'results' => $count,
);
}
else {
$suggestions[] = array(
'suggestion_suffix' => ' ' . $term,
'term' => $term,
'results' => $count,
);
}
}
}
}
} catch (SearchApiException $e) {
watchdog_exception('search_api_solr', $e, "%type during autocomplete Solr query: !message in %function (line %line of %file).", array(), WATCHDOG_WARNING);
}
if (count($suggestions) >= $limit) {
break;
}
// Change parameters for second query.
unset($params['facet.prefix']);
$keys = trim($keys . ' ' . $incomplete_key);
}
drupal_alter('search_api_solr_autocomplete_suggestions', $suggestions, $alter_data);
return $suggestions;
}