在 Grafana 中驾驭 ES|QL:Elasticsearch 管道查询实战指南

第一章:概述

从 Lucene 到管道语言的演进

在 Grafana 生态中,Elasticsearch 长期是最受欢迎的数据源之一。然而,在 ES|QL 出现之前,用户只能通过两种方式来查询数据:

  • Lucene 语法:适合简单的全文检索,但难以表达复杂的聚合与转换
  • 原生 Query DSL:功能强大,但需要编写嵌套层级极深的 JSON,可读性差,维护成本高

Elasticsearch 在 8.11 版本引入了 ES|QL(Elasticsearch Query Language) ,这是一种受 Unix 管道启发的声明式查询语言。它允许你将数据操作拆解为一系列线性步骤:先 FROM 数据源,再 WHERE 过滤,再 STATS 聚合,最后 SORT 排序。每一步的输出作为下一步的输入,逻辑像流水一样清晰。
原始数据
FROM 选择索引
WHERE 过滤行
STATS 聚合计算
KEEP/SORT/LIMIT 格式化输出
Grafana 面板渲染

这种管道模型不仅降低了心智负担,也让"查询即代码"成为可能------你可以像阅读一段数据处理脚本一样阅读查询,而不需要在 JSON 的括号海洋中迷失。

社区背景 :Grafana 用户对 ES|QL 的支持呼声由来已久。自 2024 年初起,社区便通过 Issue #81765 持续跟踪这一需求。经过 Elastic 与 Grafana Labs 的协作开发,该功能终于在 Grafana 13.0 中作为实验特性落地。


第二章:启用 ES|QL 支持

2.1 开启 Feature Toggle

ES|QL 查询编辑器在 Grafana 13.0 中默认关闭,需要通过特性开关显式启用。修改你的 grafana.ini 配置文件:

ini 复制代码
[feature_toggles]
elasticsearchESQLQuery = true

保存后重启 Grafana 服务即可生效。

⚠️ 重要警告 :Grafana 官方文档明确将 ES|QL 查询编辑器标记为实验性功能(Experimental) 。这意味着它不提供工程支持或 SLA 保障,文档也可能不完整。不建议在生产环境中启用此功能

2.2 验证启用状态

重启后,进入任意 Elasticsearch 数据源的查询面板,你会在右上角看到查询语言选择器,可在以下三种模式间切换:

  • Lucene(传统默认)
  • Raw DSL (原始 JSON,需额外开启 elasticsearchRawDSLQuery 开关)
  • ES|QL(管道查询语言)

默认
开启 elasticsearchRawDSLQuery
开启 elasticsearchESQLQuery
语法高亮/自动补全/错误提示
Builder模式
Lucene
RawDSL
ES|QL
Monaco编辑器


第三章:查询编辑器深度体验

3.1 Monaco 编辑器加持

选择 ES|QL 后,查询编辑器会切换为 Monaco Editor(VS Code 同款内核)。开箱即用的能力包括:

  • 语法高亮:关键字、函数、字符串、字段名按语义着色
  • 自动补全:输入命令或函数名时触发智能提示
  • 实时代码校验:语法错误会在编辑器内直接标红
  • 内联错误反馈:查询执行失败时,Elasticsearch 返回的结构化错误会直接显示在编辑器下方

3.2 索引选择的智能处理

:"首次点击编辑器会自动插入 FROM <index>",这一表述不够准确。实际情况是:

  • 若数据源配置中已指定索引名称,编辑器会自动预填充 FROM $__index。这里的 $__index 是一个模板变量,由 Grafana 后端在查询执行时解析为配置的实际索引名。
  • 若未配置索引,则 FROM 子句留空,由用户在查询中显式指定。

这种设计的精妙之处在于可移植性:同一条 ES|QL 查询可以在不同的数据源配置之间复用,无需硬编码索引名。

建议 :如果你在多个环境(开发/测试/生产)中使用相同 Dashboard,建议统一使用 $__index 占位符,配合 Grafana 的数据源变量功能,实现查询模板化。


第四章:日志分析实战查询

日志场景是 ES|QL 最自然的用武之地。以下示例假设索引模式为 logs-*

4.1 按日志级别统计条目数

esql 复制代码
FROM logs-*
| STATS count = COUNT(*) BY log.level
| SORT count DESC

原理STATS 是 ES|QL 的聚合命令,类似于 SQL 的 GROUP BYCOUNT(*) 统计每组行数,BY log.level 指定分组键。整个管道先读取所有日志文档,按级别分组计数,最后按数量降序排列。在 Grafana 的 Table(表格) 面板类型下,你会直接看到各级别的计数分布。

4.2 浏览最近的错误日志

esql 复制代码
FROM logs-*
| WHERE log.level == "ERROR"
| KEEP @timestamp, message, host.name
| SORT @timestamp DESC
| LIMIT 20

关键命令解析

  • WHERE:行级过滤,仅保留满足条件的文档
  • KEEP:字段投影,只保留你关心的列,减少数据传输量
  • SORT + LIMIT:经典的 Top-N 模式,先排序后截断

4.3 日志量时间趋势

esql 复制代码
FROM logs-*
| STATS count = COUNT(*) BY bucket = BUCKET(@timestamp, 1 hour)
| SORT bucket ASC

这里引入了 BUCKET 函数,它按时间维度对数据进行分桶。与 Grafana 传统的日期直方图聚合不同,ES|QL 将分桶逻辑显式写在查询中,让你对时间粒度有完全的控制权。配合 Grafana 的 Time series(时序图) 面板,可绘制出每小时日志量的趋势线。

4.4 最活跃的主机 Top 10

esql 复制代码
FROM logs-*
| STATS log_count = COUNT(*) BY host.name
| SORT log_count DESC
| LIMIT 10

第五章:时序指标高级分析------TS 命令详解

5.1 为什么指标查询需要 TS?

:"using Elasticsearch as a native Prometheus PromQL data source",这一表述过于绝对且易误导 。ES|QL 确实提供了 RATEAVG_OVER_TIME 等类 PromQL 的时序聚合函数,但它并非将 Elasticsearch 变成了原生的 Prometheus 数据源。准确的定位是:ES|QL 通过 TS 命令为 Time Series Data Streams(TSDS)提供了专门的时序分析语义,让你在 Elasticsearch 内部以类似 PromQL 的思维模型来分析指标,而无需额外部署 Prometheus。

在传统的 FROM 查询中,每条文档被视为独立的行。这对于日志和事件数据是正确的,但对于指标数据(尤其是 Counter 类型)会产生语义错误。例如:

esql 复制代码
FROM metrics-*
| STATS SUM(request_count) BY BUCKET(@timestamp, 5m)

这条查询会把所有主机在每个采样点的累计计数值直接相加。由于 Counter 是单调递增的,结果会无限增长,它既不是速率,也不是某个时间窗口内的实际请求数。

5.2 TS 命令的两层聚合模型

TS 是专为 TSDS 设计的源命令。它在聚合前会先按时间序列 (由维度字段和 _tsid 标识)对数据点进行分组,从而支持 per-series 计算。
外层聚合: Cross-Series
最终结果

AVG = 16%
内层聚合: Per-Series
host: A Series

AVG = 11%
host: B Series

AVG = 21%
原始 TSDS 数据
host: A

14:00, cpu: 10%
host: A

14:01, cpu: 12%
host: B

14:00, cpu: 20%
host: B

14:01, cpu: 22%

两层聚合的原理

  1. 内层聚合(Inner) :在每一条时间序列内部执行。例如 RATE(request_count) 会计算该序列每秒的变化率并处理 Counter 重置;AVG_OVER_TIME(cpu_usage) 会在序列内做滑动窗口平均。
  2. 外层聚合(Outer) :将每条时间序列的内层结果,按你指定的维度(如 host.namedatacenter)和时间桶(TBUCKET)进行标准 ES|QL 聚合(SUMAVGMAX 等)。

5.3 常用 TS 时序函数

函数 类型 作用
RATE() Counter 计算每秒变化率,自动处理重置
INCREASE() Counter 计算时间窗口内的总增量
AVG_OVER_TIME() Gauge 滑动窗口平均值
MAX_OVER_TIME() Gauge 滑动窗口最大值
LAST_OVER_TIME() Gauge 窗口内最新样本(默认隐式内层聚合)
TBUCKET() 时间分桶 等效于 BUCKET(@timestamp, ...),专用于 TS

5.4 实战示例

计算所有主机的总 CPU 时间变化率

esql 复制代码
TS metrics-*
| STATS SUM(RATE(metrics.system.cpu.time)) BY TBUCKET(10m)

计算每台主机内存利用率的峰值(10分钟桶)

esql 复制代码
TS metrics-*
| STATS MAX(AVG_OVER_TIME(metrics.system.memory.utilization)) BY host.name, TBUCKET(10m)

关键细节 :在 TS | STATS 查询中,如果你未显式指定内层聚合,ES|QL 会默认使用 LAST_OVER_TIME。这意味着:

esql 复制代码
TS metrics | STATS AVG(cpu_usage) BY TBUCKET(5m)

实际上等效于:

esql 复制代码
TS metrics | STATS AVG(LAST_OVER_TIME(cpu_usage)) BY TBUCKET(5m)

这与 FROM metrics | STATS AVG(cpu_usage) 的结果可能不同------FROM 是对所有原始文档做平均(上报频率高的主机权重更大),而 TS 是先按序列压缩为单值,再跨序列等权平均。

建议 :对于 Gauge 型指标,如果你关心的是时间桶内的真实平均而非最新值,请显式使用 AVG_OVER_TIME 作为内层聚合,避免被默认的 LAST_OVER_TIME 误导。


第六章:错误处理与调试体验

6.1 内联错误提示

ES|QL 查询通过 Elasticsearch 的 /_query REST 端点执行。当查询存在语法错误或引用了不存在的字段时,Elasticsearch 会返回结构化的错误响应。Grafana 插件会将这些错误直接渲染在查询编辑器下方,无需查看浏览器控制台或服务器日志。

例如,将 host.name 误写为 host.nam

复制代码
verification_exception: Cannot find field 'host.nam'

这种即时反馈循环大幅缩短了调试时间。

6.2 技术实现差异

Elasticsearch ES 插件后端 Grafana 前端 Elasticsearch ES 插件后端 Grafana 前端 alt [ES|QL 查询] [Lucene / Raw DSL] 发送 ES|QL 字符串 POST /_query Content-Type: application/json 结构化响应(列+行数组) 解析为 DataFrame 发送 DSL JSON POST /_msearch Content-Type: application/x-ndjson 多搜索响应(聚合/命中结构) 解析为 DataFrame

说明 :两种查询路径使用不同的 Elasticsearch 端点和内容类型,返回的数据结构也截然不同。/msearch 返回的是传统的搜索命中或聚合桶结构;而 /_query 返回的是关系型表格(列定义 + 行数组),插件需要独立的解析逻辑将其转换为 Grafana 的 DataFrame 格式。这种分离是刻意设计的,以确保各自的语义不被混淆。


第七章:最佳实践与注意事项

7.1 FROM vs TS:选择正确的入口

场景 推荐命令 原因
日志、追踪、审计事件 FROM 每行是独立事件,无时间序列语义
指标仪表盘、告警查询 TS 需要 per-series 聚合,正确计算 Rate/Counter
查看原始指标文档 FROM 仅需原始文档检索,不做时序归约

7.2 时间范围过滤

在 Grafana Dashboard 中,面板时间范围由 UI 控件自动注入,你通常无需在 ES|QL 中手写 @timestamp 过滤。但若在 Explore 或外部工具中测试查询,建议显式限制时间范围以避免全表扫描:

esql 复制代码
FROM logs-*
| WHERE @timestamp >= NOW() - 1h
| ...

对于 TS 查询,可使用 TRANGE

esql 复制代码
TS metrics-*
| WHERE TRANGE(1h)
| ...

7.3 生产环境建议

  1. 不要在生产环境启用实验性功能:等待 Grafana 官方将其标记为 GA(General Available)。
  2. 渐进式迁移:可以先用 ES|QL 构建新的仪表盘,保留旧的 Lucene/DSL 仪表盘作为备份。
  3. 查询性能:ES|QL 底层采用向量化执行引擎(Vectorized Compute Engine),对 TSDS 数据有显著性能优势。但具体提升幅度取决于数据特征和查询复杂度,建议以实际压测为准,而非依赖理论值。
  4. 版本兼容性:确保 Elasticsearch 版本 ≥ 8.11(ES|QL 引入版本),Grafana 版本 ≥ 13.0。

第八章:总结

ES|QL 的引入为 Grafana + Elasticsearch 的组合注入了新的活力。它将原本隐藏在复杂 JSON 中的聚合逻辑,转化为可读、可维护、可迭代的管道表达式。通过 TS 命令,Elasticsearch 的时序数据流(TSDS)终于拥有了一等公民的查询语义,让指标分析不再依赖外部 Prometheus 中转。

然而,作为一项实验性功能,它目前更适合在开发环境、POC 场景或非关键仪表盘中尝鲜。随着 Elastic 与 Grafana Labs 的持续协作,我们可以期待未来的版本会带来更完善的自动补全、更丰富的函数库,以及正式的生产级支持。

核心要点回顾

  • 通过 elasticsearchESQLQuery = true 开启实验性支持
  • 索引预填充使用 $__index 模板变量,而非硬编码
  • 日志分析用 FROM,指标分析用 TS
  • TS 查询遵循"内层 per-series → 外层 cross-series"的两层聚合模型
  • 始终关注官方文档的实验性警告,谨慎用于生产

相关推荐
zuozewei1 小时前
AI-7D-SATS平台的harness engineering设计:让 AI Agent 从“工具堆叠”长成“工程制品”
大数据·人工智能
AI周红伟1 小时前
All in Token,百度李彦宏指出:Token经济,阿里,百度,腾讯,字节,移动,电信,联通,华为,开启新的Token战争
大数据·人工智能·windows·百度·copilot·openclaw
黎阳之光2 小时前
应急管理一张图|黎阳之光全域实景技术,支撑突发事件快速响应
大数据·人工智能
黎阳之光2 小时前
数智孪生,全景可视——黎阳之光透明仓库,重构智慧仓储新范式
大数据·人工智能·算法·安全·数字孪生
AI周红伟2 小时前
Token工厂落地:移动,电信,华为,阿里,从流量到Token,All in Token
大数据·人工智能·百度·华为·copilot·openclaw
黎阳之光2 小时前
智慧公安视频孪生平台:构建全域治安防控可视化体系
大数据·人工智能·算法·安全·数字孪生
多年小白2 小时前
A股算力租赁板块 深度分析
大数据·人工智能·ai·金融·区块链
小仙女的小稀罕3 小时前
适合企业行政开部门会议用的,会议同步行动项整理方法
大数据·人工智能
糖果店的幽灵3 小时前
【股票基础】股票指标概念
大数据