日期范围查询不返回任何结果使用Elasticsearch进行休眠搜索

时间:2019-01-25 15:07:37

标签: hibernate elasticsearch hibernate-search

当我们在索引日期上使用日期范围查询时,休眠搜索不会返回任何结果。

所有其他范围查询均按预期工作

除了Elasticsearch尝试在给定范围内查找日期的查询之外,我们还在elasticsearch之上使用休眠搜索。

我们还有其他有关体重,身高等范围的查询,可以按预期工作。

用卢克(Luke)检查索引,看来日期已按预期索引。

我们有以下域对象仅显示相关字段

$('commentcounter'+e.target.id).text(parseInt($('commentcounter'+e.target.id).text())+1)

我也在dateOfBirth字段上尝试了以下方法

@Indexed
public class Person{

      @IndexedEmbedded
      @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
      @Cascade({org.hibernate.annotations.CascadeType.PERSIST})
      private Set<DateOfBirth> datesOfBirth = new HashSet<>();
}

public class DateOfBirth{

     @Basic
     @Field
     @DateBridge(resolution = Resolution.MILLISECOND)
     @Column(name = "date_of_birth")
     private Date dateOfBirth;
}

我们将以下代码添加到查询中,以查找从用户界面传递的所有年龄段的人

@Basic
@Field(bridge = @FieldBridge( impl = ElasticsearchDateBridge.class))
@Column(name = "date_of_birth")
@JsonFormat(pattern = "dd/MM/yyyy")
private Date dateOfBirth;

在执行查询之前先对其进行检查

public void withAgeRange(Integer lowerAge, Integer upperAge){

    if(lowerAge != null || upperAge != null){

        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime lowerLocalDateTime = localDateTime.withYear(localDateTime.getYear() - upperAge);
        LocalDateTime upperLocalDateTime = localDateTime.withYear(localDateTime.getYear() - lowerAge);

        Date lowerDate = Date.from(lowerLocalDateTime.atZone(ZoneId.systemDefault()).toInstant());
        Date upperDate = Date.from(upperLocalDateTime.atZone(ZoneId.systemDefault()).toInstant());

        bool.must(getQueryBuilder().range().onField("datesOfBirth.dateOfBirth").from(lowerDate).to(upperDate).createQuery());
    }
}

以卢克(Luke)为例查看示例文档,该人的出生日期的索引值为320976000000,该范围介于上下限之间。

来自Kibana的人员映射的相关部分

+dateOfBirths.dateOfBirth:[33590595604 TO 1106595795604]

如前所述,我们所有其他范围查询均按预期工作。

我们希望至少返回一个人,但是无论我们尝试在什么范围内,我们始终会返回0个结果。

任何想法都将不胜感激。

2 个答案:

答案 0 :(得分:1)

看起来像这样可能是时区问题...

好像您正在使用java.util.Date存储数据。以我的经验,这不会将时区信息传递给Elasticsearch。 Elasticsearch stores dates internally using UTC。如果经过了时区,则ES会在实际存储时区时将其转换为UTC。如果未经过任何时区,则ES会假设您的日期为世界标准时间。

这是什么意思:假设您正在美国西部时区(GMT-8)上运行,这意味着ES会认为您的意思是您的日期要比传递的日期早8小时成为。例如,您输入的出生日期为“ 01/25/19:12:00:00”,ES会在UTC中将其视为实际日期,实际上是您的“ 01/25/19:4:00:00”时间。意思是,您尝试运行的任何查询都需要在-8个小时内进行调整,以使文档目前处于索引状态。从您的代码来看,您正在调整查询以适应您的时区,但实际上并未编入索引。

为什么您所有其他查询都能按预期运行,但我不确定这不是,但是我的直觉是上面的。

为了解决日期问题,我在UTC使用ZonedDateTime为文档建立了索引。

作为参考,这是一个问题,当我弄清楚它是在我处理类似查询问题时发布的,随后的答案是:Query to pull with timestamps that were updated more than 30m ago not working

答案 1 :(得分:0)

如果我们用

进行注释
@Basic
@Field(bridge = @FieldBridge( impl = ElasticsearchDateBridge.class))
@Column(name = "date_of_birth")
@JsonFormat(pattern = "dd/MM/yyyy")  
private Date dateOfBirth;

并将查询更改为

      bool.must(getQueryBuilder().range().onField("datesOfBirth.dateOfBirth").ignoreFieldBridge().from(dateFormat.format(lowerDate)).to(dateFormat.format(upperDate)).createQuery());

dateFormat在哪里

 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

它按预期工作。

不确定这是否是最好的方法。还是有更好的方法呢?

似乎有点混乱。