第六阶段 57 · ES|QL 与 SQL API(用 SQL 查 ES)

57 · ES|QL 与 SQL API(用 SQL 查 ES)

阶段:第六阶段 / 进阶专题

ES:ES|QL(_query)+ SQL API(_sql) | PostgreSQL:直接写 SQL


1. 概念

前面 56 篇都在教你把 SQL「翻译」成 DSL。但 ES 其实提供了两条直接写类 SQL的路:

能力 端点 定位 适用
SQL API _sql ANSI SQL 子集,DSL 的「SQL 外壳」 熟悉 SQL、做过滤/聚合报表、BI 工具接入
ES|QL _query ES 8.11+ 全新管道式查询语言 数据探索、多步转换、聚合、可读性强

对 PostgreSQL 用户,这两个是「学习成本最低」的入口:不用记 bool/must/filter 嵌套,直接写 WHERE ... GROUP BY ...

定位提醒:ES|QL / SQL 适合分析与报表 ;对全文相关性打分(_score)、高并发点查、复杂 nested/join,仍以 DSL 为主(见 10/13/25/51 篇)。


2. PostgreSQL 对照

你在 PG 里怎么写,这里几乎照搬:

sql 复制代码
SELECT region, SUM(amount) AS total
FROM sales
WHERE amount >= 1000
GROUP BY region
ORDER BY total DESC
LIMIT 5;

差异点:

  • ES 表名 = 索引名 (可带通配符 sales-*)。
  • 没有 JOIN(ES|QL 有实验性 LOOKUP JOIN,SQL API 无 JOIN);关联优先反范式(见 51 篇)。
  • text 字段做精确/分组要用其 keyword 子字段(见 02 篇)。

3. ES DSL

3.1 SQL API(_sql

复制代码
POST _sql?format=txt
{
  "query": "SELECT region, SUM(amount) AS total FROM \"sales_idx\" WHERE amount >= 1000 GROUP BY region ORDER BY total DESC LIMIT 5"
}
  • formattxt(表格,人看)/ json / csv / tsv

  • 分页:响应里返回 cursor,下一页把 cursor 传回:

    POST _sql
    { "cursor": "<上一页返回的 cursor>" }

  • 不会写 SQL 对应的 DSL? 用翻译端点直接看它生成了什么:

    POST _sql/translate
    { "query": "SELECT region, SUM(amount) FROM sales_idx WHERE amount >= 1000 GROUP BY region" }

_sql/translate 是学 DSL 的神器:写你熟的 SQL,反查它对应的 bool/aggs 写法。

3.2 ES|QL(_query

管道式:数据从上一段「流」到下一段,用 | 串联,非常像 Unix 管道。

复制代码
POST _query?format=txt
{
  "query": """
    FROM sales_idx
    | WHERE amount >= 1000
    | STATS total = SUM(amount) BY region
    | SORT total DESC
    | LIMIT 5
  """
}

常用命令对照:

ES|QL SQL / 说明
FROM idx FROM 表
WHERE WHERE
STATS agg BY col GROUP BY + 聚合
SORT col DESC ORDER BY
LIMIT n LIMIT
KEEP col1, col2 SELECT col1, col2(字段裁剪)
DROP col 排除字段
EVAL new = a + b 计算列(生成新字段)
RENAME a AS b 列改名
DISSECT / GROK 解析文本抽字段

EVAL 示例(计算列 + 过滤):

复制代码
FROM sales_idx
| EVAL net = amount - discount
| WHERE net > 0
| STATS avg_net = AVG(net) BY region

4. Spring Boot 实现

官方 ElasticsearchClient 同时支持 sql()esql()

java 复制代码
@Component
public class Doc57SqlEsql {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /** SQL API:返回列名 + 行数据 */
    public void runSql(String sql) throws IOException {
        SqlQueryResponse resp = elasticsearchClient.sql().query(q -> q
                .query(sql)
                .fetchSize(1000));          // 每批行数

        // 列元数据
        List<String> cols = resp.columns().stream()
                .map(Column::name).collect(Collectors.toList());

        // 行数据(每行是 JsonData 列表)
        for (List<JsonData> row : resp.rows()) {
            // row.get(i) 对应 cols.get(i)
        }

        // 分页:resp.cursor() 非空则继续取下一批
        String cursor = resp.cursor();
        if (cursor != null && !cursor.isEmpty()) {
            elasticsearchClient.sql().query(q -> q.cursor(cursor));
        }
    }

    /** ES|QL:直接映射成对象 */
    public List<SalesRow> runEsql() throws IOException {
        // 8.17 客户端提供对象映射入口
        BinaryResponse bin = elasticsearchClient.esql().query(q -> q
                .query("""
                    FROM sales_idx
                    | WHERE amount >= 1000
                    | STATS total = SUM(amount) BY region
                    | SORT total DESC
                    | LIMIT 5
                    """)
                .format("json"));
        // 读取 bin.content()(InputStream)自行解析,
        // 或使用 ElasticsearchClient 的 ES|QL object-mapping helper 映射到 SalesRow。
        return parse(bin);
    }
}

import:co.elastic.clients.elasticsearch.sql.SqlQueryResponse...sql.Column

co.elastic.clients.json.JsonDataco.elastic.clients.transport.endpoints.BinaryResponse

ES|QL 结果是「列式」的(columns + values),映射对象时按列顺序对齐。


5. 坑与最佳实践

  1. text 字段别直接 GROUP BY / = :用 col.keyword 子字段,否则报错或结果不符预期(见 02/43 篇)。
  2. SQL API 无 JOIN :需要关联先反范式,或 ES|QL 用实验性 LOOKUP JOIN(见 51 篇)。
  3. 深分页 :SQL API 用 cursor 顺序翻页,用完 POST _sql/close 释放;别用大 LIMIT 跳页(见 40 篇)。
  4. 相关性打分不是强项 :要 _score、高亮、match 分词打分,回到 DSL(10/26 篇)。
  5. 报表/BI 首选:SQL API 可接 JDBC/ODBC 驱动,给不懂 DSL 的分析师用最省事。
  6. 学 DSL 的捷径 :写 SQL → _sql/translate 反查 DSL,比死记 bool 嵌套快得多。
  7. ES|QL 是趋势:8.11+ 持续增强,新分析场景优先考虑,可读性和多步转换远胜手写 DSL。

相关推荐
努力进修2 小时前
“数据心脏” 驱动能源自主:国产数据库支撑 Cemsol 实现固井全流程数字化闭环
数据库·人工智能·能源
vHelios2 小时前
SQL不会写?不会找关联表?复杂SQL语句编写逻辑实现思路请查收✉
数据库·sql
DB哥讲数据库2 小时前
【ClickHouse安装教程】从零开始部署高性能列式数据库(附ClickHouse安装包)
数据库·clickhouse
TDengine (老段)3 小时前
TDengine 第三方工具 — Telegraf、Kafka Connect、Flink、Spark
大数据·数据库·物联网·flink·kafka·时序数据库·tdengine
guwentian11 小时前
Git Worktree 实战:用并行多 Agent 把开发提速 N 倍
大数据·git·elasticsearch·wroktree
小白勇闯网安圈11 小时前
Django 响应对象、文件上传与类视图
数据库·django·sqlite
努力的小雨12 小时前
同一份 SQL 跑多套环境:Ksql 变量怎么用才安全
数据库
科技绘图13 小时前
快鲸GEO vs 传统AI搜索优化:全链路自动化与高效内容生产在转化闭环上的对比
数据库·人工智能·自动化
ltl13 小时前
数据库作为 LLM 记忆体:语义缓存、RAG 与一致性
数据库