ElasticsearchNotes

第 12 章:SQL 与 ES|QL

zjc 于 2026-01-12 发布

这是《Elasticsearch 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Query DSL 适合搜索和复杂控制,但很多数据分析师更熟悉 SQL。Elasticsearch 提供 SQL 能力;8.11 之后又逐步推出 ES|QL,用更贴近管道的语言做查询和分析。

本章介绍两者的能力、语法、访问方式和选型边界。

12.1 Elasticsearch SQL

POST /_sql
{
  "query": "SELECT brand, COUNT(*) AS cnt, AVG(price) AS avg_price FROM products GROUP BY brand ORDER BY cnt DESC LIMIT 10"
}

返回结构类似表格:

{
  "columns": [
    { "name": "brand", "type": "keyword" },
    { "name": "cnt", "type": "long" },
    { "name": "avg_price", "type": "double" }
  ],
  "rows": [
    ["NOVA", 120, 5999.5]
  ]
}

12.2 SQL 常用语法

条件过滤:

SELECT product_id, title, price
FROM products
WHERE status = 'ON_SALE'
  AND price BETWEEN 3000 AND 9000
ORDER BY price DESC
LIMIT 20

全文搜索:

SELECT product_id, title, SCORE()
FROM products
WHERE MATCH(title, '笔记本')
ORDER BY SCORE() DESC

聚合:

SELECT status, COUNT(*) AS cnt, SUM(amount) AS total
FROM orders
WHERE created_at > NOW() - INTERVAL 30 DAY
GROUP BY status
ORDER BY total DESC

嵌套字段的支持程度与版本、Mapping 和字段结构有关,复杂嵌套建议仍使用 Query DSL。

12.3 SQL TRANSLATE

查看 SQL 翻译后的 DSL:

POST /_sql/translate
{
  "query": "SELECT status, COUNT(*) FROM orders GROUP BY status"
}

用途:

  1. 学习 SQL 与 DSL 的对应关系;
  2. 检查 SQL 是否被下推为高效查询;
  3. 排查执行成本;
  4. 把 BI SQL 逐步迁移为 DSL。

12.4 SQL 分页与游标

POST /_sql
{
  "query": "SELECT product_id, title FROM products ORDER BY product_id",
  "filter": {
    "range": {
      "price": { "gte": 1000 }
    }
  },
  "fetch_size": 1000
}

返回 cursor 后可以继续:

POST /_sql
{
  "cursor": "..."
}

清理游标:

POST /_sql/close
{
  "cursor": "..."
}

12.5 SQL 限制

Elasticsearch SQL 不是完整的关系型数据库 SQL。

限制 说明
Join 支持有限 只支持有限类型和条件
事务不存在 只有查询和写入,不是 ACID
复杂子查询受限 并非所有 SQL 都可翻译
深分页受限 使用 cursor 或过滤条件
字段类型敏感 text 聚合需要 keyword 子字段
性能仍受 DSL 影响 慢查询同样会拖垮集群

它适合临时分析和简单报表,不适合替代数仓或 OLAP 引擎。

12.6 什么是 ES|QL

ES QL 是 Elasticsearch 8.11 引入、后续版本持续增强的管道式查询语言。它以一条事件流为中心,通过 | 管道逐层处理。
FROM orders
| WHERE created_at > NOW() - 30 DAYS
| EVAL profit = amount - cost
| STATS total_amount = SUM(amount), order_count = COUNT(*) BY status
| SORT total_amount DESC
| LIMIT 10

执行思路:

读取数据 -> 过滤 -> 派生字段 -> 聚合 -> 排序 -> 限制输出

12.7 ES|QL 常用命令

查询:

FROM logs-*
| LIMIT 10

过滤:

FROM logs-*
| WHERE log.level == "ERROR"
| LIMIT 100

选择字段:

FROM orders
| KEEP order_id, user_id, amount, status, created_at
| LIMIT 100

派生字段:

FROM orders
| EVAL amount_wan = amount / 10000.0
| KEEP order_id, amount, amount_wan

统计:

FROM orders
| STATS total = SUM(amount), cnt = COUNT(*), avg_amount = AVG(amount) BY status

时间处理:

FROM logs-*
| EVAL minute = DATE_TRUNC(1 MINUTE, @timestamp)
| STATS error_count = COUNT(*) BY minute
| SORT minute ASC

具体函数和能力与版本强相关,使用前应确认目标集群版本。

12.8 SQL 与 ES|QL 对比

维度 SQL ES QL
用户熟悉度 中等,需要学习管道语法  
查询形态 传统 SELECT 管道式  
生态 BI 工具支持较好 新生态逐步增强  
分析能力 常用 SQL 聚合 适合事件流和可观测性分析  
版本边界 较早版本可用 8.11+,能力随版本变化  
性能模型 翻译为 ES 查询 有专用执行引擎  
复杂查询 DSL 仍更强 持续演进  

12.9 选型建议

场景 建议  
应用搜索接口 Query DSL  
临时排查数据 SQL 或 ES QL
运维日志分析 ES QL 或 Kibana 查询
BI 简单报表 SQL  
复杂多维分析 DSL 聚合或数仓  
精确财务报表 数仓/数据库,ES 只做加速  
高并发线上接口 预聚合成物化结果  

12.10 权限与资源控制

SQL 和 ES QL 仍然是查询集群的入口,必须做权限控制:
  1. 只开放必要索引;
  2. 限制查询时间范围;
  3. 禁止普通用户全量扫描;
  4. 限制返回行数和并发;
  5. 对 BI 用户使用独立角色;
  6. 开启慢查询日志;
  7. 敏感字段使用字段级安全策略。

12.11 本章小结

12.12 思考题

  1. SQL MATCH 和普通 LIKE 有什么区别?
  2. 如何查看 SQL 翻译后的 Query DSL?
  3. SQL 游标适合什么场景?为什么不能无限翻页?
  4. ES QL 的管道模型有什么优势?
  5. 哪些报表不应该使用 Elasticsearch 实时聚合?