Токенизатор пробелов не работает при использовании простой строки запроса

Сначала я реализовал поиск по запросу, используя SimpleQueryString, как показано ниже.

Определение сущности

@Entity
@Indexed
@AnalyzerDef(name = "whitespace", tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
    filters = {
        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
        @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class)
    })

public class AdAccount implements SearchableEntity, Serializable {

    @Id
    @DocumentId
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Field(store = Store.YES, analyzer = @Analyzer(definition = "whitespace"))
    @Column(name = "NAME")
    private String name;

    //other properties and getters/setters
}

Здесь я использую фабрику токенизатора пробелов, потому что стандартный анализатор по умолчанию игнорирует специальные символы, что не идеально в моем случае использования. Документ, на который я ссылался, называется https://lucene.apache.org/solr/guide/6_6/tokenizers.html#Tokenizers-WhiteSpaceTokenizer. В этом документе говорится, что простой токенизатор разбивает текстовый поток на пробелы и возвращает последовательности символов, отличных от пробелов, в качестве токенов.

Метод SimpleQueryString

protected Query inputFilterBuilder() {
    SimpleQueryStringMatchingContext simpleQueryStringMatchingContext = queryBuilder.simpleQueryString().onField("name");

    return simpleQueryStringMatchingContext
        .withAndAsDefaultOperator()
        .matching(searchRequest.getQuery() + "*").createQuery();
}

searchRequest.getQuery() возвращает строку поискового запроса, затем я добавляю префиксный оператор в конце, чтобы он поддерживал префиксный запрос.

Однако это не работает должным образом в следующем примере. Скажем, у меня есть объект с именем «Учетная запись AT&T», при поиске с помощью «AT&» он не возвращает этот объект.

Затем я внес следующие изменения, чтобы напрямую использовать анализатор пробелов. На этот раз поиск с помощью «AT&» работает как положено. Но поиск теперь чувствителен к регистру, то есть поиск с помощью «at&» теперь ничего не возвращает.

@Field
@Analyzer(impl = WhitespaceAnalyzer.class)
@Column(name = "NAME")
private String name;

Мои вопросы:

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

  2. Как сделать мой поиск нечувствительным к регистру, если я использую аннотацию @Analyzer, как во второй попытке?

Работает ли это при поиске AT* (т.е. без &)?

Guillaume Smet 12.04.2019 12:03

да, это работает без &.

Lyn 16.04.2019 19:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
586
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Why doesn't it work when I use the white space factory in my first attempt? I assume using the factory versus using the actual analyzer implementation is different?

Запросы с подстановочными знаками и префиксами (тот, который вы используете, когда добавляете суффикс * в строку запроса) никогда не применяют анализ. Это означает, что ваш фильтр нижнего регистра не применяется к вашему поисковому запросу, но он был применен к вашему проиндексированному тексту, что означает, что он никогда не будет соответствовать: AT&* не соответствует проиндексированному at&t.

Использование аннотации @Analyzer сработало только потому, что вы удалили строчные буквы во время индексации. С этим анализатором вы получили AT&T (верхний регистр) в индексе, а AT&*делает соответствует индексированному AT&T. Это просто случайно: если вы проиндексируете At&t, вы получите At&t в индексе, и вы столкнетесь с той же проблемой.

How to make my search case-insensitive if I use the @Analyzer annotation as in my second attempt?

Как я уже упоминал выше, аннотация @Analyzer — это не решение, вы на самом деле ухудшили свой поиск.

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

Вы можете восстановить свой первоначальный анализатор и самостоятельно преобразовать запрос в нижний регистр, но это только продвинет вас вперед: сворачивание ascii и другие функции анализа не будут работать.

Обычно я рекомендую использовать фильтр edge-ngrams. Идея состоит в том, чтобы индексировать каждый префикс каждого слова, чтобы «учетная запись AT&T» индексировалась как термины a, at, at&, at&t, a, ac, acc, acco, accou, accoun, account, а поиск «at&» давал правильные результаты даже без подстановочного знака.

См. этот ответ для более подробного объяснения.

Если вы используете интеграцию с Elasticsearch, вам придется полагаться на хак, чтобы анализатор «только для запросов» работал правильно. См. здесь.

Спасибо за подробное объяснение!

Lyn 16.04.2019 19:30

Другие вопросы по теме