Поиск в спящем режиме: индексированные данные с фильтром Ngram, которые при поиске дают неверный результат из-за токенизации при запросах - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть анализатор с этой конфигурацией,

searchMapping//
        .analyzerDef(BaseEntity.CUSTOM_SEARCH_INDEX_ANALYZER, WhitespaceTokenizerFactory.class)//
        .filter(LowerCaseFilterFactory.class)//
        .filter(ASCIIFoldingFilterFactory.class)//
        .filter(NGramFilterFactory.class).param("minGramSize", "1").param("maxGramSize", "200");

Так настроено поле моего объекта

@Field(analyzer = @Analyzer(definition = CUSTOM_SEARCH_INDEX_ANALYZER))
private String bookName;

Так я создаю поисковый запрос

queryBuilder.keyword().onField(prefixedPath).matching(matchingString).createQuery()

У меня есть сущность со значением bookName = "Gulliver", а другая сущность с bookName = "xGulliver";

Если я попытаюсь выполнить поиск по данным bookName = xG, тогда получаю обе сущности там, где я ожидаю сущность только с bookName="xGulliver"; Также посмотрел на запрос, который создается hibernate-search.

Выполнение запроса Lucene '+ (+ (+ (+ (bookName: x bookName: xg bookName: g))))

Выше Lucene запрос подготовлен с использованием BooleanJunction::must условий Lucene. Я думаю, это означает, что он должен соответствовать всем условиям. Тем не менее, почему это дает мне оба объекта данных. Я не понимаю здесь.

Я также могу переопределить анализатор при запросе, используя KeywordTokenizer вместо NGramFilterFactory, но это похоже на то, что мне нужно переопределить каждое поле перед созданием QueryBuilder, что не выглядит хорошо, потому что тогда мне нужно переопределить все индексные поля, в которых у меня около 100 полей, а некоторые из них являются динамическими c полями, и я создаю индивидуальный запрос для каждого поля.

Есть ли другой способ переопределить анализатор в версии 5.11 или он обрабатывается в каким-то другим способом проще использовать версию hibernate-search 6.x?

Используемые мной версии Hibernate:

hibernate-search -asticsearch, hibernate-search-orm = 5.11 .4.Final

1 Ответ

1 голос
/ 17 февраля 2020

Выше Lucene запрос подготовлен с использованием условий BooleanJunction :: must по Lucene. Я думаю, это означает, что он должен соответствовать всем условиям. Тем не менее, почему это дает мне оба объекта данных. Я не понимаю здесь.

Когда вы создаете запрос keyword с помощью Hibernate Search, строка, переданная этому запросу, анализируется, и, если есть несколько токенов, Hibernate Search создает логический запрос с одним предложение «следует» для каждого токена. Вы можете увидеть это здесь "bookName: x bookName: xg bookName: g": перед "bookName" нет знака "+", что означает, что это не предложения "must", а предложения "must".

Я также могу переопределить анализатор при запросе, используя KeywordTokenizer вместо NGramFilterFactory, но это похоже на то, что мне нужно переопределить каждое поле перед созданием QueryBuilder, что выглядит не очень хорошо, потому что тогда мне нужно переопределить все индексные поля, которые я имеет около 100 полей, а некоторые являются динамическими c полями, и я создаю индивидуальный запрос для каждого поля.

Правда, это раздражает.

Есть ли другой способ переопределить анализатор в версии 5.11

В 5.11 я не думаю, что есть какой-либо другой способ переопределить анализаторы.

При необходимости, и если вы используете бэкэнд Lucene, Я полагаю, что вы сможете обойти Hibernate Search DSL только для этого конкретного c запроса:

  • Получите нужный анализатор: что-то вроде Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("myAnalyzerWithoutNGramTokenFilter").
  • Проанализируйте условия поиска: позвоните analyzer.tokenStream(...) и используйте TokenStream в зависимости от ситуации. Вы получите список токенов.
  • Создайте Lucene Query: по сути это будет логический запрос с одним TermQuery для каждого токена.
  • Передать полученный Query в Hibernate Search как обычно.

или он обрабатывается другим способом в версии hibernate-search 6.x более простым способом?

В Hibernate Search 6.0.0.Beta4 все просто. Есть два решения:

  • Неявно: в вашем отображении вы можете указать не только анализатор (используя @FullTextField(analyzer = "myAnalyzer")), но и анализатор «поиска» с использованием @FullTextField(analyzer = "myAnalyzer", searchAnalyzer = "mySearchAnalyzer"). Анализатор «по умолчанию» будет использоваться при индексировании, а анализатор «поиска» будет использоваться при поиске (запросе).
  • Явно: во время запроса вы можете переопределить анализатор для данного предиката, вызвав .analyzer("mySearchAnalyzer") при построении предиката. В этом разделе документации есть один пример .

Обратите внимание, однако, что поля Dynami c еще не поддерживаются в Hibernate Search 6: HSEARCH-3273 .

...