对熟悉关系型数据库的团队来说,Query DSL 的嵌套 JSON 是一道不低的门槛:聚合怎么写、分组怎么表达、结果怎么摊平成表格,都要重新学一遍。Elasticsearch 为此提供了两条 SQL 风格的路径:_sql 接口把标准 SQL 翻译成 Query DSL,配合 JDBC/ODBC 驱动让 BI 工具零改造接入;ES|QL 则是 8.11 引入的新一代管道查询语言,用 | 串联处理步骤,专门为分析场景设计。两者定位不同:SQL 面向兼容与工具生态,ES|QL 面向表达力与性能。本文讲清它们的语法、对接方式与取舍边界。
1. 为什么需要 SQL 接口
一句话总结: SQL 接口降低了 Elasticsearch 的使用门槛,让熟悉关系型数据库的团队和既有 BI 工具能直接消费 ES 数据。
1.1 门槛问题
Query DSL 是 Elasticsearch 的原生语言,表达力强但学习曲线陡峭。对数据分析师而言,写一个分组统计要理解 aggs 的嵌套结构、terms 与 date_histogram 的区别、doc_count 的含义;对已有报表体系而言,BI 工具只会说 SQL,无法直接对接 JSON 接口。
1.2 两条路径
- SQL(
_sql):8.x 之前就有,把 SQL 语句翻译成 Query DSL 执行。配套 JDBC/ODBC 驱动,BI 工具当普通数据库连接。 - ES|QL:8.11+ 的新查询语言,不翻译成 DSL,而是走新的执行引擎,支持管道式的逐步变换,专为分析与可观测性场景设计。
两者不是替代关系:SQL 负责兼容生态,ES|QL 负责新场景的表达与性能。
1.3 适用边界
SQL 与 ES|QL 都适合「表格化」的分析查询:过滤、分组、聚合、排序、分页。它们不适合需要精细控制相关性打分、自定义分析器、复杂嵌套聚合的场景——这些仍要用 Query DSL。把 SQL 当作便捷入口,而不是全功能替代。
2. _sql 接口与查询翻译
一句话总结:
_sql接收标准 SQL,翻译成 Query DSL 后执行,用format=txt看翻译结果,是理解 SQL 与 DSL 映射关系的最佳工具。
2.1 基本用法
curl -X POST "localhost:9200/_sql?format=txt" -H "Content-Type: application/json" -d'
{
"query": "SELECT service, COUNT(*) AS cnt FROM \"logs-*\" WHERE level = '"'"'ERROR'"'"' GROUP BY service ORDER BY cnt DESC LIMIT 5"
}
'
format 支持 txt、json、csv、yaml、cbor。默认 json 返回行列元数据。
2.2 翻译成 Query DSL
加 "translate": { "query": "..." } 只看翻译结果不执行:
curl -X POST "localhost:9200/_sql/translate" -H "Content-Type: application/json" -d'
{
"query": "SELECT service, COUNT(*) FROM \"logs-*\" WHERE level = '"'"'ERROR'"'"' GROUP BY service"
}
'
返回的就是等价的 Query DSL,这对学习 DSL 或排查 SQL 结果异常极有帮助。
2.3 关键映射规则
FROM后面是索引或别名,支持通配,需要双引号包裹。WHERE的等值条件翻译成term,范围翻译成range,LIKE翻译成wildcard。GROUP BY翻译成terms或date_histogram聚合。COUNT(*)对应doc_count,AVG/SUM/MIN/MAX对应 metric 聚合。ORDER BY在聚合场景下对应terms的order,普通场景下对应sort。
2.4 分页与游标
LIMIT 支持分页,但深分页同样受 max_result_window 限制。对全量拉取用游标:
curl -X POST "localhost:9200/_sql?format=json" -H "Content-Type: application/json" -d'
{ "query": "SELECT * FROM \"logs-*\"", "fetch_size": 1000 }
'
响应带 cursor 字段,后续用 POST /_sql?cursor=... 逐页拉取,直到返回空。游标有超时,需及时消费。
2.5 结果格式
默认返回 columns 与 rows 分离的结构,rows 是二维数组。BI 工具靠 columns 里的 name 与 type 建表。注意 ES 的字段类型会映射成 SQL 类型,keyword 与 text 都表现为字符串,date 表现为时间戳。
3. JDBC/ODBC 与 BI 工具对接
一句话总结: 官方 JDBC/ODBC 驱动让 Elasticsearch 以标准数据库身份接入 BI 工具,配合 Kibana 的 SQL 面板可快速出报表。
3.1 驱动选择
Elastic 官方提供 JDBC 与 ODBC 驱动,分别对应 Java 生态与 Windows/BI 生态。驱动本质是把 SQL 走 _sql 接口,把结果集包装成标准的 ResultSet。Tableau、Power BI、DBeaver、Metabase 等工具都可通过 JDBC/ODBC 连接。
3.2 连接参数
JDBC 连接串形如:
jdbc:elasticsearch://host:9200/?ssl=true&timeZone=Asia/Shanghai
关键参数包括 SSL、时区、fetchSize(对应游标分页)、allowPartialSearchResults。时区参数尤其重要,ES 内部按 UTC 存储,BI 展示本地时间全靠驱动转换。
3.3 与 Kibana 的集成
Kibana 的 Discover 与 Canvas 支持 SQL 查询,也可以在可视化里用 SQL 定义数据源。对临时分析,直接在 Kibana Dev Tools 里跑 SQL 比写 DSL 快得多;对固定报表,建议沉淀成 SQL 语句并在版本库管理。
3.4 BI 工具的常见坑
- 全表扫描:BI 默认可能拉全量数据,必须强制加时间过滤,否则会压垮集群。
- 频繁刷新:报表自动刷新间隔过短,会持续产生
_sql请求,配合游标可能堆积。 - 类型推断错误:
text字段不能用于分组或排序,需在映射里加keyword子字段。 - 深分页:BI 的翻页可能触发
from/size深分页,应改用游标或限制页数。
3.5 权限与审计
对接 BI 时使用专门的只读角色,限制可访问索引与字段。SQL 接口同样受文档级与字段级安全约束,SELECT * 只会返回角色可见的字段,越权字段被静默过滤。审计日志能记录 SQL 查询,便于合规追溯。
4. ES|QL 管道语法
一句话总结: ES|QL 用管道符把处理步骤从左到右串联,每一步的输出是下一步的输入,表达分析流程比嵌套 DSL 直观得多。
4.1 管道模型
ES|QL 的核心是 | 管道:FROM ... | WHERE ... | STATS ... | SORT ... | LIMIT ...。每一步对上一行的结果集做变换,读起来就是数据处理流程本身。
curl -X POST "localhost:9200/_query?format=txt" -H "Content-Type: application/json" -d'
{
"query": "FROM logs-* | WHERE level == \"ERROR\" | STATS cnt = COUNT(*) BY service | SORT cnt DESC | LIMIT 5"
}
'
注意字符串用双引号,字段名不加引号,== 表示相等。
4.2 常用处理命令
- FROM:指定数据源,支持索引通配与数据流。
- WHERE:过滤,支持
==、!=、>、<、LIKE、IN、RLIKE。 - KEEP / DROP:保留或丢弃列,控制输出字段。
- EVAL:新增计算列,如
EVAL mb = bytes / 1048576。 - STATS:分组聚合,如
STATS avg_cpu = AVG(cpu) BY host。 - SORT / LIMIT:排序与截断。
- RENAME:列重命名。
4.3 EVAL 的计算能力
EVAL 让 ES|QL 具备在查询里做计算的能力,无需写脚本:
FROM metrics-*
| WHERE @timestamp > NOW() - 1 hour
| EVAL cpu_pct = cpu * 100
| STATS avg_pct = AVG(cpu_pct) BY host
| SORT avg_pct DESC
支持算术、字符串函数(CONCAT、SUBSTRING)、日期函数(DATE_TRUNC)、类型转换(TO_DOUBLE)等。
4.4 管道顺序很重要
过滤尽量前移,让后续步骤处理更少数据:
FROM logs-*
| WHERE @timestamp > NOW() - 15 minutes
| WHERE level == "ERROR"
| STATS cnt = COUNT(*) BY service
时间过滤放最前能大幅减少扫描。ES|QL 引擎会做下推优化,但显式前置仍然更稳妥。
4.5 结果与格式
_query 接口同样支持 format,默认返回 columns 与 values。ES|QL 的结果天然是列式的,与 BI 表格模型契合,也便于转成 DataFrame 做二次分析。
5. ES|QL 的聚合与统计表达
一句话总结: ES|QL 用 STATS 一个命令覆盖分组与指标聚合,配合 BY 多列分组和时间函数,能表达大部分常见的统计分析需求。
5.1 STATS 基本形式
FROM logs-*
| STATS
total = COUNT(*),
errors = COUNT(*) WHERE level == "ERROR",
p95 = PERCENTILE(duration, 95)
BY service, DATE_TRUNC(1 hour, @timestamp)
STATS 后跟任意多个「别名 = 聚合函数」,BY 后跟分组列,支持表达式(如时间截断)。条件聚合用 COUNT(*) WHERE ... 表达,等价于 SQL 的 COUNT(CASE WHEN ...)。
5.2 常用聚合函数
COUNT、SUM、AVG、MIN、MAX、PERCENTILE、MEDIAN、STD_DEV、COUNT_DISTINCT、VALUES(收集去重值)、TOP(取最高频值)。基本覆盖了 metric 聚合的常用集合。
5.3 时间序列分析
FROM metrics-*
| WHERE @timestamp > NOW() - 24 hours
| STATS avg_cpu = AVG(cpu) BY bucket = DATE_TRUNC(5 minutes, @timestamp), host
| SORT bucket ASC
DATE_TRUNC 按固定或日历间隔分桶,等价于 date_histogram。配合多列 BY 可做「按主机分组的时序曲线」,正是仪表盘最常见的形态。
5.4 与 DSL 聚合的对比
| 需求 | DSL 写法 | ESQL 写法 |
|---|---|---|
| 分组计数 | terms 聚合嵌套 | STATS COUNT 按字段分组 |
| 时序均值 | date_histogram 加 avg | STATS AVG 按 DATE_TRUNC 分桶 |
| 条件计数 | filter 子聚合 | COUNT 加 WHERE 条件 |
| 多级下钻 | 嵌套 aggs | 多个 BY 列 |
| 管道后处理 | 需 pipeline 聚合 | 后续管道直接处理 |
ES|QL 在可读性上优势明显,尤其在多级聚合场景,嵌套 aggs 的缩进很容易写错。
5.5 后处理能力
ES|QL 的独特之处是「聚合后还能继续处理」:STATS 之后可以再 WHERE、再 EVAL、再 SORT。这在 DSL 里要靠 pipeline 聚合(bucket_script、bucket_selector)实现,写起来繁琐。ES|QL 把「先聚合再筛选」变成自然的管道步骤。
6. 与 Query DSL 的能力取舍
一句话总结: SQL/ES|QL 擅长表格化分析,Query DSL 擅长相关性、分析与精确控制,生产上按场景分工而非二选一。
6.1 SQL 做不到的
- 相关性打分控制:无法调 BM25 参数、无法用
function_score加权。 - 自定义分析器:
_analyze相关能力不暴露。 - 复杂查询类型:
nested、has_child、span_near、more_like_this无对应 SQL。 - 精细聚合:
composite、cardinality精度控制、scripted_metric不可用。 - 高亮、建议器、地理查询:SQL 层完全没有。
6.2 ES|QL 的当前限制
ES|QL 仍在快速演进,早期版本不支持更新写入(只读),部分函数与类型受限,跨集群与远程索引支持有限。使用前务必对照目标版本的文档确认能力边界。
6.3 按场景分工
- 搜索业务:一律用 Query DSL,相关性是核心诉求。
- 固定报表与 BI:用 SQL + JDBC,兼容既有工具链。
- 探索式分析:用 ES|QL,管道语法迭代快。
- 可观测性告警:ES|QL 与告警规则结合,表达阈值条件简洁。
6.4 混用的正确姿势
应用层可以封装:搜索走 DSL,报表走 SQL,两者共享同一份索引与映射。不必为了统一而强行把搜索塞进 SQL,那会丢掉 Elasticsearch 的核心竞争力。反过来,报表也不必非写 DSL 不可,SQL 的维护成本更低。
7. 限制与生产实践
一句话总结: 生产上要把 SQL/ES|QL 当作受限的只读分析入口,做好时间过滤、权限控制与资源隔离,避免拖垮集群。
7.1 性能与资源
SQL 与 ES|QL 查询同样消耗搜索线程池。BI 工具的并发刷新、大范围聚合会挤占搜索资源。建议给 BI 流量单独的角色与限流,或指向只读副本。
7.2 强制时间过滤
对日志与时序索引,SQL 查询若不带时间条件会扫描全部历史索引。可以在应用层拼接时间条件,或用索引模板 + 别名限制可查范围。这是 BI 接入最常见的性能事故来源。
7.3 结果集大小
SELECT * 在大索引上会返回海量行。用 LIMIT 与游标分批,避免一次性拉取。同时限制单次查询的 fetch_size,防止内存暴涨。
7.4 权限模型
SQL 接口遵守 Elasticsearch 的 RBAC,文档级与字段级安全在翻译层生效。为 BI 账号创建最小权限角色,只授予必要索引的 read 权限,禁用写入。审计日志记录 SQL 语句与执行者,满足合规要求。
7.5 版本演进
ES|QL 的能力随版本快速增强,升级时要关注语言层面的破坏性变更。把 ES|QL 查询纳入测试用例,升级前在预发环境验证结果一致,避免报表静默出错。
8. 总结
| 环节 | 要点 |
|---|---|
| SQL 接口 | _sql 翻译成 DSL,format 控制输出 |
| 翻译查看 | _sql/translate 看等价 DSL,学习与排错利器 |
| 游标分页 | fetch_size + cursor 支持全量拉取 |
| JDBC/ODBC | 官方驱动让 BI 工具零改造接入 |
| 时区处理 | 驱动参数转换 UTC 与本地时间 |
| ES | QL 管道 |
| EVAL 计算 | 查询内做算术与函数计算,无需脚本 |
| 聚合表达 | STATS 一命令覆盖分组与指标,可后处理 |
| 能力取舍 | 搜索用 DSL,报表用 SQL,分析用 ESQL |
SQL 与 ES|QL 把 Elasticsearch 从「搜索引擎」扩展成「可被 BI 消费的分析平台」,代价是表达力的边界。理解哪条路径适合哪类需求,比纠结「哪种语言更好」更重要。查询语言最终要落到数据模型上,字段类型与 keyword 子字段的设计见《数据建模与 Mapping 设计》;SQL 背后的聚合机制见《聚合分析:从指标统计到多维下钻》;BI 场景下的权限控制见《安全加固与访问控制》。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。