Точный поиск по максимуму в многозначном поле с пробелами

#solr

#solr

Вопрос:

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

Он работает довольно хорошо, за исключением слов с пробелами. Например, я хочу добавить тег «одежда», когда пользователь вводит следующие слова в таком порядке: «футболка» или «футболки». Предложение «моя футболка синяя» должно принести результат, поскольку «футболка» написана правильно в этом порядке, но ни «футболка моя рубашка», ни «моя рубашка» не должны возвращать результат.

Для этого у меня есть специальное ядро «теги». Я создаю пустое ядро с

   /opt/solr/bin/solr create -c "tags"
 

и обновите основную схему с помощью curl

   curl -X POST -H 'Content-type:application/json' --data-binary '{ "add-field-type" : { "name":"myShingleTextField", "class":"solr.TextField", "positionIncrementGap":"100", "analyzer" : { "tokenizer":{ "class":"solr.StandardTokenizerFactory" }, "filters":[ { "class":"solr.LowerCaseFilterFactory" }, { "class":"solr.ShingleFilterFactory", "maxShingleSize":"3",  "outputUnigrams":"true" }, ]}} }' http://localhost:8983/solr/tags/schema
  curl -X POST -H 'Content-type:application/json' --data-binary '{ "add-field": { "name":"keywords", "type":"myShingleTextField", "multiValued":true, "indexed":true, "stored":true, "required":true, "docValues":false } }' http://localhost:8983/solr/tags/schema
  curl -X POST -H 'Content-type:application/json' --data-binary '{ "add-field": { "name":"results", "type":"string", "multiValued":true, "indexed":true, "stored":true, "required":true, "docValues":true } }' http://localhost:8983/solr/tags/schema
 

Затем я / обновляю его следующим (упрощенным) документом:

 { "add": { "doc": { "keywords": ["tee shirt", "tee shirts"], "results": ["clothes"] } }, "commit": { } }
 

Я, наконец, выполняю свой запрос:

 /select?defType=dismaxamp;q=tee my shirtamp;qf=keywords
 

Он возвращает документ, в то время как я его не хочу («мой» между «футболкой» и «рубашкой»).

Может быть, это проблема с токенизатором или, может быть, запрос dismax — это не то, что мне нужно. Я попытался избежать кавычек или пробелов, изменив параметр mm на 2 (что вроде работает, но не позволяет сопоставлять одно слово) и другие настройки, которые не сработали.

Есть идеи?

Комментарии:

1. Звучит так, как будто вы хотите выполнить поиск по фразе, вы пробовали заключать q= аргумент в кавычки?

2. Не совсем. Параметр «q» устанавливается в любое значение, введенное пользователем. Если пользователь введет «моя футболка синего цвета», я буду искать эту строку (в кавычках), и solr ничего не вернет, пока слова на футболке расположены правильно. Если я добавлю документ с одним словом, например keywords = «airmax» results =»shoes», он работает нормально.

3. Действует ли то же правило для более длинных предложений? Т.Е. Вы всегда ищете точные совпадения фраз с тем, что есть в индексе? Возможно, это решит фильтр shingle для запроса и отдельных токенов при индексации. Фильтр shingle при индексации будет генерировать tee , tee_my , tee_my_shirt , my_shirt , в то время как индекс будет содержать tee_shirt . Ни один из них не сгенерирует совпадение. Индексация будет представлять собой keywordtokenizer со строчными буквами и регулярным выражением для замены пробелов на _

4. Does the same rule hold for longer sentences? I.e. are you always looking for exact phrase matches against what's in the index? Да, я запрашиваю solr с длинным предложением, и я хочу найти в нем ключевые слова (точное совпадение). The shingle filter on indexing would generate... Я думаю, вы хотели ввести здесь «при запросе». Я не знал, что могу использовать фильтр shingle для запроса. Я думаю, что предложенное вами решение будет работать, спасибо за подсказку! Я проверю это (возможно, в эти выходные) и отмечу ваш ответ как действительный, если окажется, что вы правы. Еще раз спасибо!

Ответ №1:

Благодаря подсказкам @MatsLindth я нашел решение.

Во-первых, мне нужно было заменить пробелы в нескольких словах на ‘_’ и использовать KeywordTokenizerFactory tokenizer для их дословного сохранения. На стороне запроса мне пришлось указать параметр «tokenSeparator» как «_».

Итак, моя команда определения пользовательского типа поля теперь :

   curl -X POST -H 'Content-type:application/json' --data-binary '{ "add-field-type" : { "name":"myShingleTextField", "class":"solr.TextField", "positionIncrementGap":"100", "indexAnalyzer": { "tokenizer":{ "class":"solr.KeywordTokenizerFactory" } }, "queryAnalyzer" : { "tokenizer":{ "class":"solr.StandardTokenizerFactory" }, "filters":[ { "class":"solr.LowerCaseFilterFactory" }, { "class":"solr.ShingleFilterFactory", "maxShingleSize":"3",  "outputUnigrams":"true", "tokenSeparator":"_" }, ]}} }' http://localhost:8983/solr/tags/schema
 

Моя команда обновления теперь:

 { "add": { "doc": { "keywords": ["tee_shirt", "tee_shirts"], "results": ["clothes"] } }, "commit": { } }
 

Поэтому, когда я делаю :

 /select?defType=dismaxamp;q=tee my shirtamp;qf=keywords
 

мы имеем

«футболка моя рубашка»

«футболка» «моя» «рубашка» (StandardTokenizerFactory LowerCaseFilterFactory)

«tee» «tee_my» «tee_my_shirt» «my» «my_shirt» «рубашка» (ShingleFilterFactory)

Ничто не соответствует ожидаемому, но запрос «моя футболка» выдает «tee_shirt», который, очевидно, соответствует «tee_shirt», ура!

Еще раз спасибо @MatsLindth и странице анализа Solr!