Elasticsearch 7.1.1如何动态传递范围查询的时间戳参数
Elasticsearch 7.1.1 @timestamp范围查询动态传参实现方案
Elasticsearch 7.1.1原生DSL不支持{{变量名}}这种模板占位符语法,你写的这种带双大括号的写法是上层可视化平台(Grafana、Kibana等)的模板变量规则,直接把这类DSL发给ES节点会直接报解析错误。根据你的参数存储位置,选下面两种实现方式即可:
- 应用层预拼接(性能最优,90%场景选这个)
如果dynamicValueLte、dynamicValueGte是在你的业务脚本/服务里可以提前拿到的值,根本不需要ES做动态解析,直接在代码里把值拼进DSL再发请求就行。
举个实际例子:脚本里取到dynamicValueLte = "7d"、dynamicValueGte = "30d",直接拼接生成合法DSL:
{ "query": { "bool": { "filter": [ { "range": { "@timestamp": { "lte": "now-7d", "gte": "now-30d" } } } ] } } }
拼接前必须做参数合法性校验,只允许数字+ES支持的时间单位(y/M/w/d/h/m/s)格式,避免非法参数导致查询报错,也杜绝DSL注入风险。
- ES侧脚本动态传参(适合参数必须在ES端计算的场景)
如果两个动态值是存在ES文档字段里、或者必须在查询执行时才能拿到确定值,没法在应用层提前拼接,就用脚本查询做范围判断,所有动态值通过params字段传入,不要硬拼脚本内容。7.1.1版本的实现示例如下:
{ "query": { "bool": { "filter": [ { "script": { "script": { "source": """ long currentTs = new Date().getTime(); // 下面的换算逻辑按参数单位是「天」写的,如果你存的是小时/分钟,自行调整毫秒换算值即可 long lteTs = currentTs - Long.parseLong(params.dynamicValueLte) * 86400000; long gteTs = currentTs - Long.parseLong(params.dynamicValueGte) * 86400000; long logTs = doc['@timestamp'].getValue().toInstant().toEpochMilli(); return logTs >= gteTs && logTs <= lteTs; """, "params": { "dynamicValueLte": "7", "dynamicValueGte": "30" } } } } ] } } }
脚本查询性能比原生range差,所有动态值必须放在params里传递,不要直接把值拼到script source字符串里,否则会触发ES脚本频繁编译,拖垮集群性能。
补充说明:如果你是在Kibana/Grafana这类可视化平台里写查询,
{{dynamicValueLte}}这类占位符会由平台在发请求前自动替换成对应变量值,不需要ES做额外处理,只要在平台侧把对应变量配置好即可。
内容的提问来源于stack exchange,提问作者akshay
相关产品推荐
相关产品推荐

