Частичное совпадение даты с поиском в режиме гибернации

#hibernate #elasticsearch #hibernate-search

#переход в режим гибернации #elasticsearch #переход в режим гибернации-поиск

Вопрос:

У нас есть следующее требование

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

Однако теперь у нас есть требование, при котором пользователь может не знать точную дату рождения, например, он может знать только год рождения.

Что я пробовал

 @Basic
@Field
@Field(name = "dob_string", bridge = @FieldBridge(impl = CustomDateStringBridge.class) 
,analyzer = @Analyzer(definition = "dob_string_analyzer"))
@Column(name = "date_of_birth")
private Date dateOfBirth;
  

Класс CustomDateStringBridge просто возвращает дату в виде строки, например 19780418, которая работает должным образом.

Проблема заключается в том, что мы пытаемся выполнить запрос в поле dob_string

У нас есть следующее как часть общего запроса

              partialDOB = DIGIT_ONLY_PATTERN.matcher(partialDOB).replaceAll("");
             bool.must(queryBuilder.keyword()
            .wildcard()
            .onField("datesOfBirth.dob_string")
            .ignoreFieldBridge()
            .ignoreAnalyzer()
            .matching("*" partialDOB "*")
            .createQuery());
  

Однако это приводит к следующей ошибке

 "type": "parse_exception",
    "reason": "failed to parse date field [*1979*] with format [ 
strict_date_optional_time||epoch_millis]"
  

Я пробовал без ignoreAnalyzer и ignoreFieldBridge, но в итоге получаю разные ошибки

Просто интересно, возможно ли выполнить этот тип поиска по шаблону по дате? И если у кого-нибудь есть какие-либо идеи о том, как это сделать.

Спасибо

Комментарии:

1. У меня была аналогичная проблема (у меня был пользовательский ввод либо год, либо месяц год), но мой подход заключался в том, чтобы проанализировать ввод в приложении, а затем просто использовать функции sql month() и year()

Ответ №1:

Прежде всего, я бы рекомендовал другой подход, потому что запросы с подстановочными знаками, особенно с ведущим подстановочным знаком, могут работать очень плохо.

Вместо этого сохраните поле даты и воспользуйтесь числовыми запросами.

  • Удалите свой мост, чтобы дата оставалась датой
  • Для поиска дат в пределах определенного года, месяца или дня полагайтесь на запросы диапазона.

Например, для поиска заданного года:

 // Input
int yearAsInteger = ...;

// Replace this with the user timezone if your Date instances
// are created for a user timezone different from the system default
ZoneId timezone = ZoneId.systemDefault();
Year year = Year.of( yearAsInteger );
Date startOfYear = Date.from( year.atDay( 1 ).atStartOfDay( timezone ).toInstant() );
Date startOfNextYear = Date.from( year.plusYear( 1L ).atDay( 1 ).atStartOfDay( timezone ).toInstant() );

bool.must(queryBuilder.range()
            .onField("datesOfBirth.dateOfBirth")
            .from(startOfYear)
            .to(startOfNextYear).excludeLimit()
            .createQuery());
  

Теперь, если вы действительно хотите использовать строковое поле… Проблема в вашем сопоставлении Elasticsearch. Поле dob_string зарегистрировано в сопоставлении Elasticsearch как поле «дата», тогда как вы хотите, чтобы оно было строкой.

Вы должны быть в состоянии сообщить Hibernate Search, что это строковое поле, внедрив MetadataProvidingFieldBridge его в свой мост и указав тип поля таким образом:

   @Override
  public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
      builder.field( name, FieldType.STRING );
  }
  

Не забудьте удалить и заново создать свои индексы Elasticsearch после этого изменения.

Кроме того, вы также можете перейти к поиску в режиме гибернации 6. Это бета-версия, но она стабильна, приближается к выпуску, и поддержка Elasticsearch там намного лучше (больше не экспериментальная). Однако API отличается, поэтому, если у вас уже есть расширенная кодовая база, потребуется значительная работа по миграции. Я пишу руководство по миграции, пока мы говорим.