>我有一个类似于这个的映射:
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime startTime;
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime endTime;
以及像这样的存储库中的请求:
@Query("{" +
" "nested": {" +
" "path" : "panel.channels"," +
" "query" : {" +
" "bool" : {" +
" "must" : [" +
" { "range" : { "panel.channels.startTime" : { "lte": "?1" } } }," +
" { "range" : { "panel.channels.endTime" : { "gte": "?0" } } } " +
" ]" +
" }" +
" }" +
" }" +
"}")
Flux<Document> search(LocalDateTime from, LocalDateTime to);
如果我提供日期时间的秒数为零,例如在一天开始时,例如 2021-03-15T00:00:00,则日期格式不正确,请求不返回任何结果,日志中出现此错误(在 ES 响应中):
"caused_by":{"type":"illegal_argument_exception","reason":"failed to parse date field [2021-03-15T00:00] with format [yyyy-MM-dd'T'HH:mm:ss]"
当我检查请求时确实错误:
{
"nested": {
"path": "panel.channels",
"query": {
"bool": {
"must": [
{
"range": {
"panel.channels.startTime": {
"lte": "2021-03-15T00:00"
}
}
},
{
"range": {
"panel.channels.endTime": {
"gte": "2020-01-01T00:00"
}
}
}
]
}
}
}
}
但是,如果本地日期时间中有秒,例如2021-03-15T00:00:01
,则有效!
我做了一些调试和测试;那么这里发生了什么?
您已在属性上使用@Field
注释定义了自定义日期格式。通过这个,内部为每个 在这些属性中,将创建一个自定义转换器,String
LocalDateTime
该转换器可以在 所需的格式和返回。重要:此转换器附加到实体的属性,而不是LocalDateTime
(对于不同的属性,您可能有不同的格式)。然后当弹簧时使用此转换器 数据弹性搜索存储或检索实体。
执行查询时,事情变得更加复杂。例如,当您创建CriteriaQuery
Spring 数据弹性搜索时 知道 查询中使用了哪些属性,可以使用相应的转换器正确转换属性 用于查询参数的值。对于由@Query
注释定义的查询,这是不可能的 存储库方法。这些查询仅用作字符串,参数部分(?0
,?1
)被替换为 转换方法的参数值。此处转换表示由默认转换转换可用,而不是附加到属性的那些,因为我们不知道参数到实体的哪个属性 可能相关。我们需要实现一个查询解析器来查找相应的属性 - 在您的情况下panel.channels.startTime
- 获取转换器,我认为我们不会实现这样的解析器。
因此,在您的情况下,默认转换服务将搜索LocalDateTime
实例的转换器,然后在那里 没有人注册。然后使用回退来调用要转换的对象toString()
,以防万一 的零秒返回您看到的字符串 - 仅包含小时和分钟,这就是实现 返回此值的LocalDateTime.toString()
。
我想到的第一个解决方法是为LocalDateTime
->String
定义一个转换器并注册 在 Spring 数据弹性搜索中,但我发现@Query
参数分辨率没有使用它 - 这 绝对是一个错误 - 我明天会修复。Spring Data Elasticsearch 的下一轮维护版本 4.1、4.2 和当前的主分支是下周五,所以你可以很快得到这个变化。我已经试过了 在本地,生成的查询已正确生成。
另一种可能的解决方案可能是在方法参数上引入额外的属性提示注释,即 会是这样的
Flux<Document> search(
@Property("panel.channels.endTime") LocalDateTime from,
@Property("panel.channels.startTime") LocalDateTime to);
但老实说,我不喜欢这样。
当我实施修复并发布修复版本时,我会使用额外的 有关如何将转换器添加到您的设置并使其运行的信息。