StarRocks array_sum 数组求和函数详解:语法、类型映射与 NULL 语义
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
array_sum()是 StarRocks 内置的数组聚合函数,用于对数组中的全部元素求和,返回单个数值。本文围绕 array_sum 官方文档 展开,结合 BE 端源码实现与单元测试,系统讲解其语法、支持的数据类型、返回值类型映射、NULL 处理语义,以及如何与array_map()配合使用 lambda 表达式完成"先变换、再求和"的复合计算,帮助你写出类型安全、行为可预期的高效查询。
功能概述
array_sum(array)接收一个数组参数,返回该数组中所有元素的累加和。它适用于 StarRocks 中的 Array 类型列,典型场景包括:
- 对一维数组列(如标签权重、评分序列、交易明细列表)直接求和;
- 结合 lambda 表达式对元素先做变换(平方、缩放、条件映射)后再求和,例如计算向量的平方和。
从 StarRocks 2.5 版本开始,array_sum()支持以 lambda 表达式作为参数,但它不能直接与 lambda 表达式协同工作,必须作用于array_map()转换后的结果之上,即array_sum(lambda_function, arr1, arr2...)等价于array_sum(array_map(lambda_function, arr1, arr2...))。
语法
array_sum(array(type)) array_sum(lambda_function, arr1, arr2...) = array_sum(array_map(lambda_function, arr1, arr2...))两种形式分别对应:
| 形式 | 说明 |
|---|---|
array_sum(array(type)) | 直接对数组array中的元素求和,最常见的基本用法 |
array_sum(array_map(lambda_function, arr1, arr2...)) | 先用 lambda 函数对多个数组做逐元素变换,再对结果求和;array_sum(lambda_function, arr1, arr2...)仅是这种写法的简写 |
参数说明
array(type):要求和的数组。数组元素支持以下数据类型:BOOLEAN、TINYINT、SMALLINT、INT、BIGINT、LARGEINT、FLOAT、DOUBLE、DECIMALV2。lambda_function:用于计算目标数组的 lambda 表达式,配合array_map()使用。例如x -> x * x表示对每个元素取平方后再交由array_sum()求和。
返回值类型:由元素类型推导
array_sum()的返回类型并非与输入类型完全一致,而是按照"防止溢出、保证精度"的原则向上提升。从 BE 端实现 array_functions.tpp 的ArrayArithmetic::array_sum可以看出类型映射关系:
| 数组元素类型 | 求和返回类型 | 说明 |
|---|---|---|
BOOLEAN/TINYINT/SMALLINT/INT | BIGINT | 小整数类型统一提升为 64 位整数,避免累加溢出 |
BIGINT | BIGINT | 保持原类型 |
LARGEINT | LARGEINT | 128 位大整数 |
FLOAT/DOUBLE | DOUBLE | 浮点类型统一提升为双精度 |
DECIMALV2 | DECIMALV2 | 保持十进制高精度语义 |
其他DECIMAL类型 | DECIMAL128 | 提升为 128 位十进制,扩大精度与取值范围 |
因此文档中"Returns a numeric value(返回一个数值)"的表述,其确切含义是:返回值类型是上表中与元素类型匹配的数值类型,具体类型取决于数组元素类型。这种提升策略意味着对小整数数组求和时无需担心中间结果溢出,而对浮点数组求和则统一到DOUBLE精度。
使用示例
直接对数组求和(无 lambda)
对整数数组求和:
mysql> select array_sum([11, 11, 12]); +-----------------------+ | array_sum([11,11,12]) | +-----------------------+ | 34 | +-----------------------+对浮点数数组求和:
mysql> select array_sum([11.33, 11.11, 12.324]); +---------------------------------+ | array_sum([11.33,11.11,12.324]) | +---------------------------------+ | 34.764 | +---------------------------------+结合 lambda 表达式求和
先对[1, 2, 3]的每个元素求平方(得到[1, 4, 9]),再求和:
-- Multiply [1,2,3] by [1,2,3] and sum the elements. select array_sum(array_map(x->x*x,[1,2,3])); +---------------------------------------------+ | array_sum(array_map(x -> x * x, [1, 2, 3])) | +---------------------------------------------+ | 14 | +---------------------------------------------+该写法等价于array_sum(x -> x * x, [1, 2, 3]),两者结果一致,均返回14。关于array_map()的完整语法与 lambda 书写规范,可参见 array_map 函数文档。
NULL 与空数组语义
理解array_sum()对 NULL 的处理,对正确解读结果至关重要。从 array_functions.tpp 中ArraySumAvg的实现逻辑,以及 array_functions_test.cpp 的单元测试,可以归纳出以下规则:
- 数组本身为 NULL:直接返回 NULL(实现中当数组列仅有 NULL 时原样返回,见 array_functions.tpp)。
- 空数组:返回 NULL。测试用例
array_sum_empty_array明确验证了空数组[]的求和结果为 NULL(对应 array_functions_test.cpp)。 - 数组中存在 NULL 元素:NULL 元素会被跳过,不参与累加;只要数组中存在至少一个非 NULL 元素,就返回其余元素的累加和。对应测试用例
array_sum_has_null_element(见 array_functions_test.cpp)。 - 全 NULL 或空数组等无有效数据的情形:结果为 NULL(实现中
has_data为 false 时写入默认值并置 NULL 标记,见 array_functions.tpp)。
换言之,array_sum()对 NULL 元素的语义与标准 SQL 聚合函数SUM一致:忽略 NULL、仅累加有效值,但没有有效值时结果为 NULL,而不是 0。这在处理稀疏数组(如含缺失值的评分序列)时尤为关键,可避免将缺失值误当作 0 参与求和。
底层实现原理
array_sum()在 BE 端经由 array_functions.h 注册到ArrayArithmetic::array_sum,其核心流程为:
- 类型分派:根据模板参数
ElementType在编译期确定结果类型(BIGINT/LARGEINT/DOUBLE/DECIMALV2/DECIMAL128),不支持的输入类型会直接报错(见 array_functions.tpp)。 - 按行遍历:通过数组列的 offsets 定位每个数组的起止下标,逐元素累加(见 array_functions.tpp);若元素列带 NULL 标记,则跳过 NULL 元素。
- 结果写出:将每行的累加和写入结果列,无有效数据的行写入 NULL。整个计算对 Array 列逐行独立完成,天然支持向量化批处理,适合在海量 Array 行上做列级聚合。
测试覆盖了空数组、含 NULL 元素、可空数组、无 NULL 元素等多种组合(array_functions_test.cpp),可作为理解边界行为的参考。
注意事项与最佳实践
- 使用前确认元素类型:
array_sum()不支持 STRING、DATE、DATETIME 等非数值类型,也不支持 ARRAY 嵌套数组的直接求和;若需对嵌套数组求和外层和内层需分别处理。 - 大数组注意数值范围:整数类型求和结果会自动提升(如
INT→BIGINT),但超大LARGEINT累加仍需留意是否超出表示范围。 - NULL 不会当作 0:若业务上希望"缺失即 0",可先用
array_map(x -> ifnull(x, 0), arr)之类的变换将 NULL 替换为 0,再调用array_sum()。 - 复合计算推荐 lambda 写法:需要先变换再求和时,使用
array_sum(array_map(lambda, arr))或简写array_sum(lambda, arr),一次查询即可完成"逐元素变换 + 汇总",避免中间结果落地。
相关文档
- array_sum 函数文档
- array_map 函数文档
- 实现与测试:array_functions.tpp、array_functions.h、array_functions_test.cpp
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考