Java调用Elasticsearch range日期查询格式异常无法返回全部结果
问题根因
问题的核心是createdDate字段的类型设置错误:你当前使用keyword类型做范围查询,而keyword类型的range比较是按字符串字典序逐字符比对,并非按日期逻辑比对:
- 9月的日期字符串以
29/09/xxxx开头,10月的日期以01/10/xxxx开头 - 字符串比对时第一位字符
0<2,系统会判定01/10/2021<29/09/2021,所以查询早于等于10月1日的记录时,9月29日的记录会被判定为不满足条件被过滤 - 你给keyword字段加
format参数是无效的,format参数仅对date类型的字段生效,对keyword类型没有任何作用。
解决方案
临时解决方案(无需重建索引)
使用脚本查询实现日期逻辑比对,将字符串转为日期对象后再做范围判断,Java代码修改如下:
BoolQueryBuilder query = QueryBuilders.boolQuery() .filter(QueryBuilders.termsQuery(customerKeywordField, customerName)) .filter(QueryBuilders.scriptQuery(new Script(ScriptType.INLINE, "painless", "def date = LocalDateTime.parse(doc['createdDate.keyword'].value, DateTimeFormatter.ofPattern('dd/MM/yyyy HH:mm:ss'));" + "def targetDate = LocalDateTime.parse(params.target, DateTimeFormatter.ofPattern('dd/MM/yyyy HH:mm:ss'));" + "return date.isBefore(targetDate) || date.isEqual(targetDate);", Collections.singletonMap("target", timestamp))));
该方案性能较低,仅适合数据量不大的场景临时使用。
长期最优方案(推荐)
重建索引,将createdDate字段修改为date类型,并指定正确的日期格式,对应mapping修改如下:
"createdDate" : { "type" : "date", "format": "dd/MM/yyyy HH:mm:ss", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }
修改完成后你原来的range查询逻辑基本不需要改动,直接查询createdDate字段即可,性能和准确性都有保障:
QueryBuilders.rangeQuery("createdDate").lte(timestamp)
内容的提问来源于stack exchange,提问作者Shreyas
相关产品推荐
相关产品推荐

