Поиск с различными комбинациями пространства, дефиса, обсадной колонны и пунктуации

Моя схема:

<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
  <analyzer>
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.StopFilterFactory"
            ignoreCase="true"
            words="stopwords.txt"
            enablePositionIncrements="true"
            />
    <filter class="solr.WordDelimiterFilterFactory"
            generateWordParts="1" generateNumberParts="1"
            catenateWords="1" catenateNumbers="1" catenateAll="0"
            splitOnCaseChange="1" splitOnNumerics="0"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.SnowballPorterFilterFactory" language="English"
            protected="protwords.txt"/>
  </analyzer>
</fieldType>

Комбинации, которые я хочу работать:

"Walmart", "WalMart", "Wal Mart", "Wal-Mart", "Wal-mart"

Учитывая любую из этих строк, я хочу найти другую.

Таким образом, существует 25 таких комбинаций, как указано ниже:

(Первый столбец обозначает входной текст для поиска, второй столбец обозначает ожидаемое совпадение)

(Walmart,Walmart)
(Walmart,WalMart)
(Walmart,Wal Mart)
(Walmart,Wal-Mart)
(Walmart,Wal-mart)
(WalMart,Walmart)
(WalMart,WalMart)
(WalMart,Wal Mart)
(WalMart,Wal-Mart)
(WalMart,Wal-mart)
(Wal Mart,Walmart)
(Wal Mart,WalMart)
(Wal Mart,Wal Mart)
(Wal Mart,Wal-Mart)
(Wal Mart,Wal-mart)
(Wal-Mart,Walmart)
(Wal-Mart,WalMart)
(Wal-Mart,Wal Mart)
(Wal-Mart,Wal-Mart)
(Wal-Mart,Wal-mart)
(Wal-mart,Walmart)
(Wal-mart,WalMart)
(Wal-mart,Wal Mart)
(Wal-mart,Wal-Mart)
(Wal-mart,Wal-mart)

Текущие ограничения с моей схемой:

1. "Wal-Mart" -> "Walmart",
2. "Wal Mart" -> "Walmart",
3. "Walmart"  -> "Wal Mart",
4. "Wal-mart" -> "Walmart",
5. "WalMart"  -> "Walmart"

Снимок экрана анализатора:

Analyzer screenshot using initial schema

Я пробовал различные комбинации фильтров, пытаясь разрешить эти ограничения, поэтому я наткнулся на решение, предоставленное по адресу: Solr - нечувствительный к регистру поиск не работает p >

В то время как кажется, что преодолевает одно из ограничений, которые у меня есть (см. № 5 WalMart → Walmart), это в целом хуже, чем у меня раньше. Теперь это не работает для таких случаев, как:

(Wal Mart,WalMart), 
(Wal-Mart,WalMart), 
(Wal-mart,WalMart), 
(WalMart,Wal Mart)
besides cases 1 to 4 as mentioned above

Анализатор после изменения схемы: enter image description here

Вопросы:

  • Почему "WalMart" не соответствует "Walmart" с моей начальной схемой? Анализатор Solr ясно показывает мне, что во время индексации он выдал 3 жетона: wal, mart, walmart. Во время запроса: он выдал 1 токен: walmart (пока не понятно, почему он будет производить только 1 токен), я не понимаю, почему он не соответствует, если walmart содержится в токенах запроса и индекса.

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

    Слова с апострофами: "Mc Donalds", "Mc Donald's", "McDonald's", "Mc donalds", "Mc Donald's", "Mcdonald's"

    Слова с различными пунктуациями: "Mc-Donald Engineering Company, Inc."

В общем, что лучший способ для моделирования схемы с таким требованием? NGrams? Индексируйте те же данные в разных полях (в разных форматах) и используйте директиву copyField (https://wiki.apache.org/solr/SchemaXml#Indexing_same_data_in_multiple_fields)? Каковы последствия этого для производительности?

EDIT: Оператором по умолчанию в моей схеме Solr является AND. Я не могу изменить его на OR.

Ответ 1

Обновление версии Lucene (4.4 до 4.10) в файле solrconfig.xml исправило проблему магически! У меня больше нет ограничений, и мой анализатор запросов ведет себя так же, как ожидалось.

Ответ 2

Мы рассмотрели переносимые слова как частный случай и написали пользовательский анализатор, который использовался во время индекса, чтобы создать три версии этого токена, поэтому в вашем случае wal-mart станет walmart, wal mart и wal-mart. Каждый из этих синонимов был написан с использованием специального SynonymFilter, который был первоначально адаптирован из примера в книге Lucene in Action. SynonymFilter сидел между токенизатором Whitespace и нижним токенизатором.

В момент поиска любая из трех версий будет соответствовать одному из синонимов в индексе.

Ответ 3

Почему "WalMart" не соответствует "Walmart" с моей начальной схемой?

Потому что вы определили параметр mm вашего обработчика DisMax/eDismax со слишком высоким значением. Я играл с ним. Когда вы определяете значение mm до 100%, вы не получите соответствия. Но почему?

Потому что вы используете тот же анализатор для запроса и времени индекса. Ваш поисковый термин "WalMart" разделен на 3 жетона (слова). А именно это "wal", "mart" и "walmart". Теперь Solr обрабатывает каждое слово индивидуально, если рассчитывать на <str name="mm">100%</str> *.

Кстати, я воспроизвел вашу проблему, но там проблема возникает при индексировании Walmart, но запросы с WalMart. При выполнении этого наоборот, он отлично работает.

Вы можете переопределить это, используя LocalParams, вы можете перефразировать свой запрос следующим образом {!mm=1}WalMart.

Есть несколько более сложные, такие как [...] "Мак Дональд" [в соответствии] Слова с различными пунктуациями: "Mc-Donald Engineering Company, Inc."

Здесь также играет с параметром mm.

В общем, что лучший способ обойти моделирование с таким требованием?

Здесь я согласен с Sujit Pal, вы должны пойти и реализовать собственную копию SynonymFilter. Зачем? Потому что он работает иначе, чем другие фильтры и токенизаторы. Он создает токены вместо смещения индексированных слов.

Что там? Он не увеличит количество токенов вашего запроса. И вы можете выполнить перенос назад (объединение двух слов, разделенных пробелом).

Но нам не хватает хорошего файла synonyms.txt и он не может поддерживать его в актуальном состоянии.

При расширении или копировании SynonymFilter игнорировать статическое сопоставление. Вы можете удалить код, который отображает слова. Вам просто нужна обработка смещения.

Обновить. Я думаю, вы также можете попробовать PatternCaptureGroupTokenFilter, но поиск имен компаний с регулярными выражениями скоро может оказаться "ограниченным". Я расскажу об этом позже.


* Вы можете найти это в своем файле solrconfig.xml, ищите свой <requestHandler ... />

Ответ 4

Я позволю себе сначала внести некоторые изменения в анализатор. Я бы подумал, что WordDelimiterFilter функционально является второстепенной токенизацией, поэтому пусть это сразу после Tokenizer. После этого нет необходимости в обслуживании, поэтому нижний регистр следующий. Это лучше для вашего StopFilter, так как нам больше не нужно беспокоиться о ignorecase. Затем добавьте штекера.

<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" splitOnNumerics="0"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.StopFilterFactory"
        words="stopwords.txt"
        enablePositionIncrements="true"
        />
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>

В целом, это не слишком далеко. Главная проблема - "Wal Mart" и "Walmart". Для каждого из них WordDelimiterFilter не имеет к этому никакого отношения, это токенизатор, который здесь расщепляется. "Wal Mart" разделяется токенизатором. "Walmart" никогда не разделяется, поскольку ничто не может разумно знать, где его нужно разделить.

Одним из решений для этого было бы использовать KeywordTokenizer вместо этого, и пусть WordDelimiterFilter сделает все токенизацию, но это приведет к другим проблемам (в частности, при работе с более длинным и сложным текстом, например, Mc-Donald Engineering Company, Inc. "пример будет проблематичным).

Вместо этого я бы рекомендовал ShingleFilter. Это позволяет объединить соседние маркеры в один токен для поиска. Это означает, что при индексировании "Wal Mart" он будет принимать токены "wal" и "mart", а также индексировать термин "walmart". Обычно он также вставляет разделитель, но для этого случая вы захотите переопределить это поведение и указать разделитель "".

Теперь мы поместим ShingleFilter в конец (это будет иметь тенденцию заворачиваться, если вы положите его перед стволовым):

<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" splitOnNumerics="0"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.StopFilterFactory"
        words="stopwords.txt"
        enablePositionIncrements="true"
        />
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.ShingleFilterFactory" maxShingleSize="2" tokenSeparator=""/>

Это создаст только гальки из двух последовательных жетонов (а также оригинальные одиночные жетоны), поэтому я предполагаю, что вам не нужно больше сочетаться (если вам нужно "дореми", чтобы соответствовать "Do Re Mi", например). Но для приведенных примеров это работает в моих тестах.