Проблемы с индексом Lucene с символом "-"

У меня возникают проблемы с индексом Lucene, который имеет индексированные слова, содержащие символы "-" .

Он работает для некоторых слов, содержащих "-" , но не для всех, и я не нахожу причины, почему он не работает.

Поле, в котором я ищу, анализируется и содержит версию слова с символом "-" и без него.

Я использую анализатор: org.apache.lucene.analysis.standard.StandardAnalyzer

вот пример:

Если я ищу "gsx- *", я получил результат, индексированное поле содержит "SUZUKI GSX-R 1000 GSX-R1000 GSXR"

но если я ищу "v- *", я не получил результата. Индексированное поле ожидаемого результата содержит: "SUZUKI DL 1000 V-STROM DL1000V-STROMVSTROM V STROM"

Если я ищу "v-strom" без "*", это работает, но если я просто ищу "v-str", например, я не получаю результат. (Должен быть результат, потому что он для поиска в реальном времени для интернет-магазина)

Итак, какова разница между двумя ожидаемыми результатами? почему он работает для "gsx-", но не для "v-"?

Ответ 1

StandardAnalyzer будет рассматривать дефис как пробел, я считаю. Поэтому он превращает ваш запрос "gsx-*" в "gsx*" и "v-*" в ничто, поскольку также устраняет однобуквенные токены. То, что вы видите как содержимое поля в результатах поиска, - это сохраненное значение поля, которое полностью не зависит от терминов, которые были проиндексированы для этого поля.

Итак, вы хотите, чтобы "v-strom" в целом был индексированным термином. StandardAnalyzer не подходит для такого типа текста. Возможно, пойдите с WhitespaceAnalyzer или SimpleAnalyzer. Если это еще не сократило его, у вас также есть возможность сбрасывать свой собственный анализатор или просто начинать с тех двух, которые были изложены и составлены с последующим TokenFilters. Очень хорошее объяснение дано в пакете Lucene Analysis Javadoc.

Нет необходимости вводить все варианты в индексе, такие как V-strom, V-Strom и т.д. Идея состоит в том, чтобы тот же анализатор нормализовал все эти варианты в одну и ту же строку как в индексе, так и при синтаксическом анализе запрос.

Ответ 2

ClassicAnalyzer обрабатывает '-' как полезный символ без разделителя. Как я понимаю, ClassicAnalyzer, он обрабатывает "-", как и до 3.1 StandardAnalyzer, потому что ClassicAnalyzer использует ClassicTokenizer, который обрабатывает числа со встроенным '-' как код продукта, поэтому все это обозначается как один термин.

Когда я был в Институте Regenstrief, я заметил это после обновления Luke, поскольку стандартные медицинские термины LOINC (LOINC был инициирован RI) идентифицированы числом, за которым следует '-' и checkdigit, например '1-8' или "2857-1". Мои поиски LOINC, например, "45963-6", не удалось использовать StandardAnalyzer в Luke 3.5.0, но сменили его на ClassicAnalyzer (и это было потому, что мы построили индекс с 2.9.2 Lucene.NET).

Ответ 3

ClassicAnalzer рекомендуется индексировать текст, содержащий коды продуктов, такие как "GSX-R1000". Он признает это как единый термин и не разделяет его части. Но, например, текст "Европа/Берлин" будет разделен ClassicAnalzer на слова "Европа" и "Берлин". Это означает, что если у вас есть текст, индексированный ClassicAnalyzer, содержащий фразу

Europe/Berlin GSX-R1000

вы можете искать "europe", "berlin" или "GSX-R1000".

Но будьте осторожны, какой анализатор вы используете для поиска. Я думаю, что лучшим выбором для поиска индекса Lucene является KeywordAnalyzer. С помощью KeywordAnalyzer вы также можете искать определенные поля в документе, и вы можете создавать сложные запросы, например:

(processid:4711) (berlin) 

Этот запрос будет искать документы с фразой "berlin", а также поле "processid", содержащее номер 4711.

Но если вы ищете индекс для фразы "europe/berlin", вы не получите никакого результата! Это связано с тем, что KeywordAnalyzer не изменил вашу поисковую фразу, но фраза "Европа/Берлин" была разделена на два отдельных слова ClassicAnalyzer. Это означает, что вам нужно искать "европе" и "берлин" отдельно.

Чтобы решить этот конфликт, вы можете перевести поисковый запрос, введенный пользователем, в поисковый запрос, который вам подходит, используя следующий код:

QueryParser parser = new QueryParser("content", new ClassicAnalyzer());
Query result = parser.parse(searchTerm);
searchTerm = result.toString("content");

Этот код будет транслировать serach pharse

Europe/Berlin

в

europe berlin

что приведет к ожидаемому набору документов.

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

Europe/Berlin GSX-R1000

будет переведено на:

(europe berlin) GSX-R1000

который будет корректно искать все фразы в комбинации с помощью KeyWordAnalyzer.