#hibernate-search
#переход в режим гибернации-поиск
Вопрос:
Я использую поиск в режиме гибернации 5.11.1, и мне необходимо поддерживать поиск и сортировку по одному и тому же полю типа String. После прочтения справочного руководства я нашел следующую документацию об использовании нормализаторов для сортировки анализируемого текста.
Ссылка из официального руководства:
Анализаторы великолепны, когда вам нужно выполнить поиск в текстовых документах, но что, если вы хотите отсортировать анализируемый текст? Тогда у вас возникнут небольшие проблемы, потому что анализируемый текст многозначен: при индексировании книги с названием «Рефакторинг: улучшение дизайна существующего кода» анализируемый заголовок фактически представляет собой (неупорядоченный) набор {«рефакторинг», «улучшение», «дизайн», «существующий», «код»}. Если вы попытаетесь выполнить сортировку по названию после такого анализа, может быть использовано любое из этих слов, так что ваша книга может оказаться на букве D (из-за «дизайна»), или на букве R (из-за «рефакторинга»), или на букве E и т.д.
Итак, в конце концов, вы, вероятно, не хотите, чтобы ваши поля были маркированы при сортировке по этим полям. Нормализаторы решают именно эту проблему: они являются анализаторами, но без токенизатора и с некоторыми проверками во время выполнения, которые не позволяют анализу выдавать несколько токенов, тем самым гарантируя, что ваши сортировки всегда будут согласованными.
Поиск в режиме гибернации предоставляет эквивалент нормализатора для соответствующих аннотаций анализатора: @Normalizer, @NormalizerDef, @NormalizerDefs. Как и в случае с analyzer, вы можете использовать реализации напрямую (например, @Normalizer(impl = MyCollactionKeyAnalyzer.class )) или именованные нормализаторы (например, @Normalizer (определение = «myNormalizer») с помощью @NormalizerDef(фильтры = @TokenFilterDef(factory = LowerCaseFilterFactory.class )).
Основываясь на вышесказанном, я написал следующий код:
@Entity
@Indexed
@AnalyzerDef(name = "en", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = ASCIIFoldingFilterFactory.class)
})
@NormalizerDef(name = "lowercase", filters = {
@TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),
@TokenFilterDef(factory = LowerCaseFilterFactory.class)
}
)
@Table(name = "ORDER")
public class Order {
//Some other fields that are omitted for brevity here
@Field(name = "orderName_Search", store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "en"))
@Field(name = "orderName_Sort", store = Store.YES, analyze = Analyze.NO, normalizer = @Normalizer(definition = "lowercase"))
@SortableField(forField = "orderName_Sort")
@Column(name = "ORDER_NAME")
private String orderName;
}
Однако, похоже, это не работает, поскольку я столкнулся со следующей ошибкой.
[ОШИБКА] com.appnexus.konnect.web.exceptions.Организация исключений ConnectExceptionHandler.hibernate.search.exception.Исключение SearchException: не удается автоматически определить тип поля для поля ‘orderName’. Используйте byField(String, Sort.Type), чтобы явно указать тип сортировки
Мой вопрос в том, где что-то пошло не так? Это работает только при использовании любой аннотации @Field, но не работает при использовании обеих.
Ответ №1:
Судя по сообщению об ошибке, вы написали что-то вроде этого:
qb.sort().byField("orderName").createSort()
Но поле orderName
не существует для поиска в режиме гибернации. Существуют только orderName_Search
и orderName_Sort
. В этом случае вам следует написать:
qb.sort().byField("orderName_Sort").createSort()
Кроме того, имейте в виду, что установка analyze = Analyze.NO
вкл orderName_Sort
фактически отключит ваш нормализатор. Вероятно, вы захотите это исключить.
Комментарии:
1. Да, вы совершенно правы! Даже о той части, о которой вы догадались, что я сделал. Спасибо, детектив @yrodiere!
Ответ №2:
Для тех, кто испытывает трудности с поиском в режиме гибернации 6, я тоже пытался выполнить сортировку по имени поля. Например.
@FullTextField(analyzer = "custom_analyzer") @GenericField(name = "story_sort", sortable = Sortable.YES)
Однако я понял, что мне нужно заменить «story» на «story_sort» в функции сортировки:
SearchResult<Story> result = searchSession.search(Story.class).where( f -> f.match().field("story").matching(param)).sort( f -> f.field( "story_sort" //was "story" before).desc()).fetch(offset,5);