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

Моя схема:

<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>

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

"Уолмарт", "Уолмарт", "Уолмарт", "Уолмарт", "Уолмарт"

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

Итак, таких комбинаций, как указано ниже, 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"

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

Скриншот анализатора с исходной схемой

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

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

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

Анализатор после изменения схемы: введите здесь описание изображения

Вопросы:

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

  2. #P15# <блочная цитата> #P16# #P17#

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

РЕДАКТИРОВАТЬ: оператор по умолчанию в моей схеме Solr - AND. Я не могу изменить его на ИЛИ.


person Sudheer Aedama    schedule 21.04.2015    source источник


Ответы (4)


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

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

person Sujit Pal    schedule 22.04.2015
comment
Спасибо, что нашли время ответить. Фильтры синонимов работали бы, если бы у меня был хороший набор данных синонимов, что, к сожалению, неверно в моем случае. - person Sudheer Aedama; 22.04.2015
comment
Нельзя ли просканировать индекс на наличие слов, написанных через дефис, и работать с ними? Это может быть не идеально, но это начало. - person Sujit Pal; 23.04.2015
comment
дефис - это всего лишь один сценарий из нескольких. Существуют и другие виды знаков препинания. Боюсь, мы могли бы даже масштабироваться с такими особыми случаями :) - person Sudheer Aedama; 23.04.2015
comment
Я объединяю ваш ответ с ответом femtoRgon, и это будет именно то, что я хочу. Не могли бы вы указать пример написания пользовательского SynonymFilter и того, как он используется в пользовательском анализаторе? - person Sudheer Aedama; 17.06.2015
comment
Пример, на котором я основывал свой код, можно найти в Lucene в действии (раздел 4.6) — я полагаю, что версия Lucene здесь — 3.x, против которой также был написан наш исходный код. Код необходимо будет обновить для версии 4.x, поскольку между версиями 3.x и 4.x в API анализа вносились изменения. - person Sujit Pal; 18.06.2015

Почему «WalMart» не соответствует «Walmart» с моей исходной схемой?

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

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

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

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

Есть более сложные, такие как [ ... ] «Макдональдс» [ чтобы соответствовать ] Слова с другими знаками препинания: «Мак-Дональд Инжиниринг Компани, Инк.»

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

В общем, как лучше всего моделировать схему с такими требованиями?

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

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

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

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

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


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

person cheffe    schedule 11.05.2015

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

<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=""/>

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

person femtoRgon    schedule 22.04.2015
comment
Хотя это снимает ограничение для случая Walmart --> Wal Mart, в целом ситуация хуже, поскольку эти 3 случая, которые проходят раньше, терпят неудачу: Wal-Mart -> Wal Mart, Wal-mart -> Wal Mart, WalMart -> Wal Mart. Кроме того, для другого варианта использования McDonald's эти случаи также не будут выполнены: McDonald's -> Mc Donald's, McDonald's -> Mc Donalds, McDonald's -> Mc donald's, McDonald's -> Mc donalds. - person Sudheer Aedama; 22.04.2015
comment
Вы переиндексировали после внесения изменений в анализатор? - person femtoRgon; 22.04.2015
comment
Я начал с чистого листа, перезапустил Solr и перезапустил свои тесты (которые выполняют индексирование с последующим запросом). - person Sudheer Aedama; 22.04.2015
comment
Не знаю, что тебе сказать. Похоже, где-то несогласованный анализатор. Я попробовал несколько таких случаев точно, и они работают для меня. - person femtoRgon; 22.04.2015
comment
Могу я узнать, какую версию Solr вы используете? Также версия Lucene, если это имеет значение? - person Sudheer Aedama; 22.04.2015
comment
Не могли бы вы также поделиться своим файлом схемы и настройками Solr, если вы не возражаете, если я спрошу? - person Sudheer Aedama; 22.04.2015

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

person Sudheer Aedama    schedule 14.05.2015
comment
Переход с 4.4 на 4.10 - это обновление... :) - person cheffe; 18.05.2015