Elasticsearch中如何对text类型的非空date_field_2执行范围查询?
如何对text类型的日期字段执行范围查询
结论
可以对date_field_2的非空文档执行范围查询,但不能直接用text类型做原生range查询,需要通过调整字段映射或使用脚本查询实现。
最优解决方案:修改字段映射为date类型
text类型不适合做日期范围查询,最稳妥的方式是将date_field_2的类型改为date,同时处理空字符串的问题:
- 创建新索引并设置正确映射:
定义映射时,将date_field_2设为date类型,通过ignore_malformed忽略无效值,空字符串会被自动视为null(range查询会忽略含null值的文档):{ "mappings": { "properties": { "date_field_1": { "type": "date" }, "date_field_2": { "type": "date", "ignore_malformed": true } } } } - 迁移数据:
使用Elasticsearch的_reindexAPI将原索引的数据迁移到新索引,迁移过程中非空的date_field_2值会被解析为date类型,空字符串则会转为null。 - 执行范围查询:
之后就可以用和date_field_1相同的range查询语句,自动只返回date_field_2非空且符合日期范围的文档。
临时解决方案:使用脚本查询(不推荐大数据量)
如果无法修改索引映射,可以在查询时通过脚本将text类型的date_field_2转换为日期后做范围判断:
{ "query": { "bool": { "filter": [ { "script": { "script": { "source": "doc['date_field_2'].value != '' && Date.parse('yyyy-MM-dd', doc['date_field_2'].value).toInstant().toEpochMilli() >= params.gte && Date.parse('yyyy-MM-dd', doc['date_field_2'].value).toInstant().toEpochMilli() <= params.lte", "params": { "gte": 1653264000000, // 对应2022-05-23 00:00:00的时间戳 "lte": 1653350399999 // 对应2022-05-23 23:59:59的时间戳 } } } } ] } } }
注意:脚本查询会遍历符合条件的文档,性能远低于原生date类型的range查询,仅适合小数据量场景临时使用。
原查询失败的原因
date_field_2被设为text类型时,range查询是基于字符串的字典序而非日期逻辑进行判断,且空字符串的存在会干扰查询匹配逻辑,因此无法返回正确结果。
内容的提问来源于stack exchange,提问作者ashfak
相关产品推荐
相关产品推荐

