Elasticsearch多索引不同类型日期字段能否同时排序?
跨多索引日期字段排序的解决方案
这个问题很典型!针对你这种多索引里日期字段类型、名称都不统一的排序需求,咱们分情况来拆解解决方案:
一、全量跨索引排序(不同类型/名称的日期字段)
1. 脚本排序(最直接的即时方案)
你猜的没错,脚本排序确实是处理这种异构字段排序的常用方式。通过ES的Painless脚本,我们可以把不同格式的日期统一转换成可排序的时间戳,实现跨索引的统一排序。举个实际的脚本示例:
{ "sort": { "_script": { "type": "number", "script": { "lang": "painless", "source": """ if (doc.containsKey('First_date')) { if (doc['First_date'].size() == 0) return 0; // 处理index1的date类型,转成时间戳 if (doc['First_date'].value instanceof ZonedDateTime) { return doc['First_date'].value.toInstant().toEpochMilli(); } // 处理index2的integer年份 else if (doc['First_date'].value instanceof Integer) { return ZonedDateTime.of(doc['First_date'].value, 1, 1, 0, 0, 0, 0, ZoneId.of('UTC')).toInstant().toEpochMilli(); } } else if (doc.containsKey('justDate')) { // 处理index3的integer年份 return ZonedDateTime.of(doc['justDate'].value, 1, 1, 0, 0, 0, 0, ZoneId.of('UTC')).toInstant().toEpochMilli(); } else if (doc.containsKey('date')) { // 处理index4的字符串格式"May 2018" if (doc['date'].size() == 0) return 0; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM yyyy").withZone(ZoneId.of('UTC')); return ZonedDateTime.parse(doc['date'].value, formatter).toInstant().toEpochMilli(); } return 0; """ }, "order": "asc" } } }
⚠️ 注意:脚本排序会有一定性能开销,尤其是数据量很大的时候,如果是高频查询场景,更推荐下面的预处理方案。
2. 预处理方案(更高效的长期方案)
如果你的索引允许修改或者重新导入数据,最稳妥的方式是给每个索引新增一个标准化日期字段(比如统一命名为standardized_date),在数据写入时就把不同格式的日期转换成统一的date类型:
- index1:直接把
First_date的date类型值复制到standardized_date - index2:把年份整数转成
yyyy-MM-dd格式(比如2018→2018-01-01)存入standardized_date - index3:同理,把2017转成
2017-01-01存入standardized_date - index4:把"May 2018"解析成
2018-05-01存入standardized_date
之后跨索引排序就可以直接用这个统一字段,完全利用ES原生的日期排序能力,性能拉满:
{ "sort": [ { "standardized_date": { "order": "asc" } } ] }
二、同类型字段的排序
如果只针对同类型的日期字段排序,实现起来就简单多了:
1. 同字段名+同类型
比如只查询index1(First_date为date类型)和其他同样用First_date且类型为date的索引,直接按字段名排序即可:
{ "sort": [ { "First_date": { "order": "asc" } } ] }
2. 同类型但不同字段名
比如index2的First_date(integer年份)和index3的justDate(integer年份),可以用脚本快速统一处理,或者同样用上面的预处理新增统一字段的方式(长期更高效):
{ "sort": { "_script": { "type": "number", "script": { "lang": "painless", "source": """ return doc.containsKey('First_date') ? doc['First_date'].value : doc['justDate'].value; """ }, "order": "asc" } } }
内容的提问来源于stack exchange,提问作者Paweł
相关产品推荐
相关产品推荐

