Elasticsearch中如何在text类型字段上实现日期范围查询?
解决思路与可行方案
因为remark是text类型,无法直接用range查询日期,以下是两种可行的解决办法:
方案一:正则表达式查询(适用于固定日期或小范围日期)
由于字段内的日期格式是dd/mm/yyyy,先将目标日期范围(2023-02-15至2023-02-16)转换为对应的15/02/2023和16/02/2023,然后使用regexp查询匹配这些日期。如果你的索引中remark字段有自动生成的keyword子字段(默认配置会生成),用该子字段查询效果更好(避免分词对匹配逻辑的干扰):
GET myindex/_search { "query": { "bool": { "must": [ { "regexp": { "remark.keyword": ".*(15/02/2023|16/02/2023).*" } } ] } }, "highlight": { "fields": { "remark": { "type": "unified", "fragment_size": 150, "number_of_fragments": 3, "pre_tags": ["<em>"], "post_tags": ["</em>"] } } }, "size": 1000 }
注意:如果日期范围更大,正则表达式会变得复杂冗余,这种情况下推荐使用脚本查询。
方案二:脚本查询(适用于任意日期范围)
通过Painless脚本遍历remark字段内容,提取所有符合dd/mm/yyyy格式的日期字符串,转换为日期对象后判断是否在目标范围内:
GET myindex/_search { "query": { "bool": { "must": [ { "script": { "script": { "source": """ def pattern = /(\d{2}\/\d{2}\/\d{4})/; def matcher = pattern.matcher(doc['remark.keyword'].value); def startDate = LocalDate.parse('2023-02-15'); def endDate = LocalDate.parse('2023-02-16'); while (matcher.find()) { def dateStr = matcher.group(1); def parts = dateStr.split('/'); def docDate = LocalDate.of(Integer.parseInt(parts[2]), Integer.parseInt(parts[1]), Integer.parseInt(parts[0])); if (docDate.isAfter(startDate.minusDays(1)) && docDate.isBefore(endDate.plusDays(1))) { return true; } } return false; """, "lang": "painless" } } } ] } }, "highlight": { "fields": { "remark": { "type": "unified", "fragment_size": 150, "number_of_fragments": 3, "pre_tags": ["<em>"], "post_tags": ["</em>"] } } }, "size": 1000 }
脚本逻辑说明:
- 用正则匹配所有
dd/mm/yyyy格式的日期字符串 - 将提取的日期按
/拆分后,转换为标准LocalDate对象 - 对比该日期是否落在目标范围内,只要有一个符合就返回匹配结果
额外提示
你原查询中的highlight字段指定错误,应该配置remark而非content,否则无法正确高亮目标字段的匹配内容。
内容的提问来源于stack exchange,提问作者Manoj Agarwal
相关产品推荐
相关产品推荐

