部分日期匹配与hibernate搜索

o4hqfura  于 2021-06-14  发布在  ElasticSearch
关注(0)|答案(1)|浏览(400)

我们有以下要求
作为搜索的一部分,用户可以搜索一个人的出生日期。一般来说,这样做很好,用户从前端的日期选择器中进行选择,搜索也会按预期进行。
但是,我们现在有一个要求,用户可能不知道确切的出生日期,例如,他们可能只知道出生年份。
我试过的

@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\u字符串字段时
我们将以下内容作为整个查询的一部分

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,但最终会出现不同的错误
只是想知道有没有可能在一个日期做这种类型的通配符搜索?如果有人知道怎么做。
谢谢

egmofgnx

egmofgnx1#

首先,我推荐一种不同的方法,因为通配符查询,特别是带有前导通配符的通配符的查询,执行起来非常糟糕。
相反,保留一个日期字段,并利用数字查询。
移开你的桥,让日期保持一个日期
依靠范围查询查找特定年、月或日内的日期。
例如,要搜索给定的年份:

// 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());

现在,如果你真的想用一个字符串字段。。。问题出在elasticsearchMap中。字段 dob_string 在elasticsearch的Map中注册为“日期”字段,而您希望它是字符串。
您应该能够通过实现 MetadataProvidingFieldBridge 在桥中,并通过以下方式提供字段类型:

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

别忘了删除并重新创建elasticsearch索引。
或者,您也可以移动到hibernate search 6。它是beta版的,但它很稳定,即将发布,elasticsearch支持在那里要好得多(不再是实验性的)。但是,api是不同的,因此如果您已经有了扩展的代码库,那么将有大量的工作要迁移。我正在写迁移指南。

相关问题