Поиск вариантов слова в единственном числе в Sunspot/Solr

У меня есть приложение Rails+Sunspot, и я работаю над его настройкой, чтобы поиск возвращал единственную версию запроса. Например:

Я хочу, чтобы поиск "cookie" возвращал что-то с именем "cookie". В настоящее время мой поиск Sunspot возвращает «cookie», но не «cookie» (единственное число).

Я внес некоторые изменения в файл Solr schema.xml, добавив solr.EdgeNGramFilterFactory для обеспечения большей гибкости, но EdgeNGramFilterFactory не подходит для этого случая, так как он допускает совпадения только тогда, когда запрос является подстрокой имени результата. Насколько я понимаю, EdgeNGramFilterFactory будет возвращать «cookie», когда пользователь ищет «co», «coo», «cook» или «cooki», но не суперстроку «cookie» (то есть: cookies). Проще говоря, это связано с тем, что «cookies» не является подстрокой внутри «cookie».

Я пытался добавить все три встроенных фабрики Solr, но безрезультатно. Вы можете увидеть один закомментированный в моей схеме.

В schema.xml соответствующее поле выглядит следующим образом:

<fieldType name="text" class="solr.TextField" omitNorms="false">
  <analyzer type="index">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StandardFilterFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/>
    <!-- <filter class="solr.EnglishMinimalStemFilterFactory"/> -->
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StandardFilterFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

Я предполагал, что смогу сингуляризировать запрос пользователя, но я бы предпочел не трогать его запрос до того, как он попадет в Solr.

Вы можете поиграть с этим здесь: http://staging.zisboombah.com/parent/food_guide/?search=cookie. Попробуйте изменить запрос между «cookie» и «cookies».

Буду очень признателен за любые советы о том, как это сделать в Solr!


person Mike    schedule 21.12.2011    source источник


Ответы (2)


Параметры solr xml упорядочены. Вы хотите, чтобы стеммер располагался перед фильтром ngram, чтобы вы ngram-ize cookie, а не c, co и т. д.

Объединение фильтров таким образом может привести к странным результатам, в основном в зависимости от того, насколько агрессивен ваш стеммер. Вы определенно должны добавить стеммер в анализатор запросов, но это испортит ваше автозаполнение.

Лучшее решение: используйте copyField для создания независимых полей text_stemmed и text_autocomplete. Затем выполните поиск, используя запрос ИЛИ по обоим полям.

person Kyle Maxwell    schedule 21.12.2011
comment
Спасибо Кайл! Есть ли у вас какие-либо ссылки на ресурсы, которые могут дополнительно объяснить copyField? Может пример? - person Mike; 23.12.2011
comment
Расширение этой концепции в другом ответе ниже (слишком длинный для комментария). - person Nick Zadrozny; 03.01.2012

Как Кайл упоминает, вы, вероятно, хотите использовать больше типов текстовых полей для каждого из этих различных вариантов использования.

Вот мой пример:

schema.xml

<schema>
  <types>

    <fieldType name="text" class="solr.TextField" omitNorms="false">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StandardFilterFactory"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>

    <fieldType name="text_en" class="solr.TextField" omitNorms="false">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StandardFilterFactory"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.PorterStemFilterFactory"/>
      </analyzer>
    </fieldType>

    <fieldType name="text_stopwords" class="solr.TextField" omitNorms="false">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StandardFilterFactory"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
      </analyzer>
    </fieldType>

    <!-- ... -->
  </types>
  <fields>
    <!-- ... -->
  </fields>

  <copyField source="*_text"   dest="text"/>
  <copyField source="*_texts"  dest="text"/>
  <copyField source="*_textsv" dest="text"/>
  <copyField source="*_textv"  dest="text"/>

</schema>

Моделирование солнечных пятен

Использование директивы copyField может сэкономить некоторую работу по настройке модели. Однако Sunspot использует эти объявления text, чтобы решить, какие поля следует keywords искать по умолчанию, поэтому мне нравится включать отдельные text вызовы, которые используют :as для указания полного имени поля документа Solr.

searchable do
  text :name, stored: true, default_boost: 10
  text :name, as: 'name_text_en'
  text :description, stored: true
end
person Nick Zadrozny    schedule 03.01.2012
comment
Спасибо, Ник! Я провел несколько часов с вашими рекомендациями безрезультатно. Я пробовал много итераций pastie.org/3204079. Проблема, с которой я столкнулся сейчас, заключается в том, что стеммер работает, а EdgeNGramFactory, похоже, нет. Теперь файлы cookie вернут файл cookie (мой желаемый результат). Однако Cook НЕ возвращает cookie. Кроме того, мое сохраненное поле имени в моих записях возвращает ноль (все остальные сохраненные поля в порядке). Код моей модели выглядит так: text :name, :boost =› 2.0, :stored =› true; текст :имя, :as =› 'name_text_en' - person Mike; 18.01.2012