【问题标题】:Date range query not returning any results hibernate search with elasticsearch日期范围查询不返回任何结果休眠搜索弹性搜索
【发布时间】:2019-06-19 10:41:01
【问题描述】:

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

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

我们在 elasticsearch 之上使用休眠搜索,我们的所有查询都按预期运行,除了我们尝试在给定范围内查找日期的查询。

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

用 Luke 检查索引,日期似乎按预期编入索引。

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

@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;
}

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

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

我们将以下代码添加到我们的查询中,该代码旨在查找从 UI 传递的年龄范围内的所有人

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

在执行前检查查询显示

+dateOfBirths.dateOfBirth:[33590595604 TO 1106595795604]

查看带有 Luke 的示例文档,有人的出生日期的索引值为 320976000000,位于范围的下限和上限之间。

来自 Kibana 的 Person 映射的相关部分

      "datesOfBirth": {
        "properties": {
          "currentDateOfBirth": {
            "type": "boolean"
          },
          "dateOfBirth": {
            "type": "date",
            "store": true
          }
        }
      },

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

我们希望至少返回这个人,但无论我们尝试什么范围,我们总是返回 0 个结果。

任何想法将不胜感激。

【问题讨论】:

  • 你能为你的索引提供一个映射吗?
  • @КириллПолищук 我已经从索引映射中添加了相关部分。

标签: hibernate elasticsearch hibernate-search


【解决方案1】:

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

看起来您正在使用 java.util.Date 存储数据。以我的经验,这不会将时区信息传递给 Elasticsearch。 Elasticsearch stores dates internally using UTC。如果通过了时区,ES 将在实际存储时将其转换为 UTC。如果没有传递时区,ES 将假定您的日期是 UTC,原样。

这意味着:假设您在美国西部时区 (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

【讨论】:

    【解决方案2】:

    如果我们用注释来证明

    @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");
    

    它按预期工作。

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

    看起来有点乱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多