SQL 与 ES|QL 查询:_sql 接口、管道语法与 BI 对接

系统讲解 Elasticsearch 的 SQL 与 ES|QL 查询能力:_sql 接口与翻译机制、JDBC/ODBC 驱动与 BI 工具对接、ES|QL 管道语法与聚合统计表达,以及与 Query DSL 的能力取舍和限制。

对熟悉关系型数据库的团队来说,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 加 avgSTATS 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 与本地时间
ESQL 管道
EVAL 计算查询内做算术与函数计算,无需脚本
聚合表达STATS 一命令覆盖分组与指标,可后处理
能力取舍搜索用 DSL,报表用 SQL,分析用 ESQL

SQL 与 ES|QL 把 Elasticsearch 从「搜索引擎」扩展成「可被 BI 消费的分析平台」,代价是表达力的边界。理解哪条路径适合哪类需求,比纠结「哪种语言更好」更重要。查询语言最终要落到数据模型上,字段类型与 keyword 子字段的设计见《数据建模与 Mapping 设计》;SQL 背后的聚合机制见《聚合分析:从指标统计到多维下钻》;BI 场景下的权限控制见《安全加固与访问控制》。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「elasticsearch」更多文章

  1. 可搜索快照与冻结层:把冷数据放进对象存储还能查
  2. 分页与深度分页:from/size、search_after、PIT 与 scroll
  3. 嵌套与父子关联查询:nested、join 字段与性能取舍