Elasticsearch执行Painless脚本遇BadRequestError,求最长开放事件聚合方案
问题解决与聚合实现
一、脚本查询错误修复
你的脚本查询触发运行时错误,核心原因是未处理日期字段的空值情况,直接访问.date.millis会抛出异常。以下是修复后的查询(同时过滤开放事件state: "open"):
场景1:开放事件有明确结束日期
{ "query": { "bool": { "must": [ {"term": {"state": "open"}}, { "script": { "script": """ if (doc['event_end_date'].empty || doc['event_start_date'].empty) { return false; } def durationDays = (doc['event_end_date'].date.millis - doc['event_start_date'].date.millis) / (1000 * 86400); return durationDays < 365; """ } } ] } } }
场景2:开放事件无结束日期(用当前时间计算持续时长)
{ "query": { "bool": { "must": [ {"term": {"state": "open"}}, { "script": { "script": """ def startMillis = doc['event_start_date'].empty ? 0 : doc['event_start_date'].date.millis; def endMillis = doc['event_end_date'].empty ? new Date().getTime() : doc['event_end_date'].date.millis; def durationDays = (endMillis - startMillis) / (1000 * 86400); return durationDays < 365; """ } } ] } } }
二、按事件类型聚合,提取最长持续时间的开放事件
要实现「按事件类型列出持续时间最长的开放事件」,可以通过terms聚合分组,嵌套top_hits聚合获取每组内时长最长的文档:
完整查询(含过滤+聚合)
{ "size": 0, // 不返回原始文档,仅输出聚合结果 "query": { "bool": { "must": [{"term": {"state": "open"}}] } }, "aggs": { "group_by_event_type": { "terms": { "field": "type", "size": 100 // 根据实际事件类型数量调整 }, "aggs": { "longest_duration_event": { "top_hits": { "size": 1, "sort": [ { "_script": { "type": "number", "script": { "source": """ def startMillis = doc['event_start_date'].date.millis; def endMillis = doc['event_end_date'].empty ? new Date().getTime() : doc['event_end_date'].date.millis; return endMillis - startMillis; """ }, "order": "desc" // 按时长降序,取第一条即为最长事件 } } ], "_source": { // 指定返回需要的字段 "includes": ["id", "type", "title", "event_start_date", "event_end_date"] } } } } } } }
聚合结果解析
group_by_event_type下的每个桶对应一种事件类型longest_duration_event.hits.hits[0]即为该类型下持续时间最长的开放事件- 脚本自动处理了
event_end_date为空的开放事件(用当前时间计算时长)
三、Python客户端调用示例
from elasticsearch import Elasticsearch # 初始化ES客户端 es = Elasticsearch("http://your-es-host:9200") # 构造查询体 query_body = { "size": 0, "query": { "bool": { "must": [{"term": {"state": "open"}}] } }, "aggs": { "group_by_event_type": { "terms": {"field": "type", "size": 100}, "aggs": { "longest_duration_event": { "top_hits": { "size": 1, "sort": [ { "_script": { "type": "number", "script": { "source": """ def startMillis = doc['event_start_date'].date.millis; def endMillis = doc['event_end_date'].empty ? new Date().getTime() : doc['event_end_date'].date.millis; return endMillis - startMillis; """ }, "order": "desc" } } ], "_source": {"includes": ["id", "type", "title", "event_start_date", "event_end_date"]} } } } } } } # 执行查询 response = es.search(index="your-index-name", body=query_body) # 解析并打印结果 for type_bucket in response["aggregations"]["group_by_event_type"]["buckets"]: event_type = type_bucket["key"] longest_event = type_bucket["longest_duration_event"]["hits"]["hits"][0]["_source"] print(f"事件类型: {event_type}") print(f"最长开放事件详情: {longest_event}\n")
内容的提问来源于stack exchange,提问作者UmerF92
相关产品推荐
相关产品推荐

