Статьи

Solr Autcomplete, часть 4 (Нграм и огранка)

В предыдущих частях серии автозаполнения мы представили два метода запросов автозаполнения. Чем мы расширили один из тех, у кого была возможность определять возвращаемую информацию . В сегодняшней записи мы вернулись к автозаполнению с помощью facet и ngram.

Требования

Наш механизм автозаполнения имеет следующие требования:

  1. Мы возвращаем целую фразу, а не только одно слово
  2. Возвращенная фраза может присутствовать несколько раз в индексе.
  3. Мы хотим знать количество результатов для возвращенной фразы
  4. Общие фразы должны быть показаны выше, чем менее распространенные
  5. Порядок слов, введенных пользователем, не имеет значения

Решение

Решение, данное в первой части серии, не будет соответствовать требованиям из-за первого требования. Конечно, мы можем изменить тип анализа, но мы не вернем всю фразу.

Решением вышеуказанных требований является модифицированный метод огранки. Вместо того, чтобы искать все элементы и сужать результаты с помощью параметра facet.prefix , мы можем искать только те элементы, которые имеют искомый фрагмент слова. Мы не хотим, чтобы использовался подстановочный запрос (из-за производительности), который мы вызываем ngram для спасения Это означает, что нам нужно записать нграммы в индекс (конечно, Solr сделает это за нас). Очевидным недостатком является рост размера индекса, но в этом случае мы можем с этим смириться.

Schema.xml

Мы определяем дополнительный тип:

<fieldType name="text_autocomplete" class="solr.TextField" positionIncrementGap="100">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter minGramSize="1" maxGramSize="25" />
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

Мы также определяем дополнительные поля: поле, значение которого мы планируем вернуть, и поле, которое будет использоваться для поиска:

<field name="tag_autocomplete" type="text_autocomplete" indexed="true" stored="true" omitNorms="true" omitTermFreqAndPositions="true"/>
<field name="tag" type="string" indexed="true" stored="true" />

И один copyField, чтобы сделать вещи проще:

<copyField source="tag" dest="tag_autocomplete"/>

запрос

После индексации мы готовы протестировать наши запросы:

  1. Мы сужаем результаты только для тех, у которых есть интересный фрагмент слова в поле tag_autocomplete , с: q = tag_autocomplete: (PHRASE)
  2. Нам нужны все фрагменты, введенные пользователем, поэтому мы используем AND в качестве логического оператора: q.op = AND
  3. Нас не интересуют фактические результаты запроса, мы будем использовать данные, возвращаемые фасетированием, поэтому мы говорим: rows = 0
  4. Нам нужна огранка: facet = true
  5. Нам нужно огранить поле, в котором мы храним исходную фразу: facet.field = tag
  6. Нас не интересуют пустые теги: facet.mincount = 1
  7. Нас интересуют только 5 значений автозаполнения: facet.limit = 5

И последний запрос:

?q=tag_autocomplete:(PHRASE)&q.op=AND&rows=0&facet=true&facet.field=tag&facet.mincount=1&facet.limit=5

Если мы настроим обработчик поиска для включения всех постоянных параметров, у нас будет следующий запрос:

?q=tag_autocomplete:(PHRASE)

В конце

Основным достоинством представленного метода является возможность использовать одно поле для поиска, а другое — для возврата результатов. Благодаря этому мы смогли вернуть целую фразу вместо одного слова.