Поиск в режиме гибернации: с возможностью поиска и сортировки по одному и тому же полю

#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);