Сначала я реализовал поиск по запросу, используя 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;
Мои вопросы:
Почему это не работает, когда я использую фабрику пробелов с первой попытки? Я предполагаю, что использование фабрики отличается от использования фактической реализации анализатора?
Как сделать мой поиск нечувствительным к регистру, если я использую аннотацию @Analyzer, как во второй попытке?
да, это работает без &.
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, вам придется полагаться на хак, чтобы анализатор «только для запросов» работал правильно. См. здесь.
Спасибо за подробное объяснение!
Работает ли это при поиске
AT*
(т.е. без&
)?