elastic search 是如何做sum操作的
简单来说,Elasticsearch SQL 的 SUM
操作是通过将其翻译(编译)成 Elasticsearch 原生的聚合查询来实现的,具体来说是 sum
度量聚合(Metric Aggregation)。
以下是详细的实现步骤和原理:
1. 架构概览:SQL 到 Elasticsearch DSL 的翻译
Elasticsearch 的 SQL 功能本质上是一个翻译层。它本身不直接执行 SQL 查询,而是做了以下工作:
- 1.
解析 (Parse): 将标准的 SQL 语句解析成抽象语法树 (AST)。
- 2.
翻译 (Translate): 将 AST 转换为等价的 Elasticsearch 原生 JSON 查询(即 Query DSL)。
- 3.
执行 (Execute): 将翻译好的 DSL 请求发送给 Elasticsearch 集群处理。
- 4.
格式化 (Format): 将 Elasticsearch 返回的 JSON 结果转换成 SQL 客户端期望的表格形式。
你的 SUM
操作主要发生在第 2 步和第 3 步。
2. SUM 操作的具体翻译过程
我们通过一个例子来看。假设你执行以下 SQL 查询:
SELECT SUM(price) FROM products;
Elasticsearch SQL 层会将其翻译为如下所示的 Elasticsearch 查询 DSL:
{ "size": 0, // 不需要返回任何原始文档(hits),只需要聚合结果 "aggs": { "SUM(price)": { // 聚合结果的名称直接来自 SQL 表达式 "sum": { "field": "price" // 对 price 字段进行求和 } } } }
如果带有分组呢? 再看一个更复杂的例子:
SELECT category, SUM(price) FROM products GROUP BY category;
这条 SQL 会被翻译为:
{ "size": 0, "aggs": { "groupby": { // 先进行分组聚合(桶聚合) "terms": { "field": "category", // 分组字段 "size": 10 // 默认返回前10个桶(分组)的结果 }, "aggs": { // 在每个分组桶内,进行子聚合 "SUM(price)": { "sum": { "field": "price" } } } } } }
这个过程清晰地展示了:∙
SELECT SUM(...)
-> "sum": { "field": ... }
(度量聚合)∙
GROUP BY
-> "terms": { "field": ... }
(桶聚合)
3. 分布式执行:如何在集群中计算
这才是 Elasticsearch 强大之处。翻译后的 DSL 被发送到协调节点(Coordinating Node),其执行流程如下:
- 1.
分发阶段: 协调节点将查询分发到所有相关的数据分片(Shards)。
- 2.
分片本地计算: 每个分片独立地在自己的数据子集上执行相同的聚合操作(即计算本分片内所有文档的
price
之和)。这是一个巨大的性能优势,因为计算是并行且分布式的,避免了传输所有原始数据。 - 3.
结果汇总: 每个分片将其本地计算出的
sum
值返回给协调节点。 - 4.
全局reduce: 协调节点收集所有分片的局部
sum
值,将它们简单相加,得到全局总和。 - 5.
返回结果: 协调节点将最终的总和返回给 SQL 层,SQL 层再将其格式化成 SQL 结果返回给用户。
对于分组求和 (GROUP BY
),过程类似:
- ∙
每个分片计算自己数据里每个
category
的局部sum(price)
。 - ∙
协调节点合并所有分片的结果:将相同
category
的局部sum
值相加,得到每个category
的全局sum
。
4. 关键技术点与优化
- ∙
使用
doc_values
: 为了高效聚合,Elasticsearch 强烈依赖倒排索引和doc_values
。doc_values
是一种列式存储结构,对于price
这样的数值字段,启用doc_values
(默认通常为开启)后,Elasticsearch 可以非常快速地在磁盘上遍历和累加所有值,而不需要加载整个原始文档。这是聚合性能高的根本原因。∙ 近似算法(用于海量数据): 对于
COUNT(DISTINCT)
这种操作,Elasticsearch 默认使用 HyperLogLog++ 算法来提供近似值,以极低的内存消耗换取极快的速度和可扩展性。但需要注意的是,SUM
操作是精确的,不是近似值。∙缓存: 聚合结果可能会被缓存(分片请求缓存),以加速后续相同的查询。
总结
Elasticsearch SQL 的 SUM
操作实现流程可以概括为:
SQL 语句 -> (SQL 翻译层) -> Elasticsearch 原生 sum
聚合查询 -> (分布式执行) -> 各分片本地求和 -> 协调节点汇总 -> (SQL 翻译层) -> 格式化 SQL 结果 -> 返回用户
其核心优势在于:
- 1.
翻译机制: 将熟悉的 SQL 语法无缝转换为 Elasticsearch 高性能的原生聚合 DSL。
- 2.
分布式计算: 利用分片架构,将计算任务下推到每个数据节点并行执行,极大提升了处理海量数据的效率。
- 3.
列式存储: 依赖
doc_values
进行快速字段值计算,避免解析整个 JSON 源文档。
因此,虽然表面是 SQL 接口,但其底层享受了 Elasticsearch 作为分布式搜索引擎为聚合分析提供的全部性能和扩展性优势。