StarRocks MAP 函数详解:cardinality() 如何统计 Map 元素个数及其底层实现
发布时间:2026/9/18 15:38:41来源:尧图网络
StarRocks MAP 函数详解cardinality() 如何统计 Map 元素个数及其底层实现【免费下载链接】starrocksThe worlds 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本文聚焦 StarRocks 的 MAP 标量函数cardinality()它返回一个 MAP 值中包含的元素个数自 v3.0 起可用且是map_size()的别名。读完本文你将掌握cardinality()的语法、参数与返回值规则含 NULL 语义、在 StarRocks 原生表与数据湖Hive 外部表上的完整实操方法以及该函数在 BE 执行引擎中的向量化实现原理——从列式存储的 offsets 差值计算到常量列展开与空 map 返回 0 的边界行为。一、功能定位MAP 的元素个数函数StarRocks 中的 MAP 是键值对key-value pair组成的无序集合例如{a:1, b:2}。其中一个键值对构成一个元素因此{a:1, b:2}包含 2 个元素。cardinality()的作用就是返回这个元素个数INT cardinality(any_map)核心要点参数any_map要统计元素个数的 MAP 值类型可以是任意键值类型组合的 MAP函数签名中的ANY_MAP返回值INT 类型即该 MAP 中键值对的总数NULL 语义若输入本身为 NULL则返回 NULL若 MAP 内部某个 key 或 value 为 NULLNULL 会被当作普通值正常参与计数不影响结果版本与别名该函数自 v3.0 起支持并且是map_size()的别名——二者语义、行为完全一致。二、函数注册机制cardinality 与 map_size 同源在 StarRocks 中函数的名称、返回类型与 BE 实现类是通过元数据注册表统一声明的。查看 gensrc/script/functions.py可以看到两条关键注册项[170000, map_size, True, False, INT, [ANY_MAP], MapFunctions::map_size], [170100, cardinality, True, False, INT, [ANY_MAP], MapFunctions::map_size],从注册表可以确认三点事实cardinality与map_size的返回类型同为INT入参同为ANY_MAP两者的 BE 实现都指向同一个 C 函数MapFunctions::map_size——这正是文档中cardinality 是 map_size 别名说法的底层依据SQL 层解析出不同函数名执行时走同一份代码注册表中还并列存在cardinality的数组重载[ANY_ARRAY] - ArrayFunctions::array_length说明cardinality是一个多态函数名用于 MAP 时走 map 实现用于 ARRAY 时走数组长度实现。FE 侧同样有对应的函数名常量声明见 fe/fe-core/src/main/java/com/starrocks/catalog/FunctionSet.javapublic static final String CARDINALITY cardinality;三、实操一查询 StarRocks 原生表中的 MAP 数据自 v3.1 起StarRocks 支持在建表时直接定义 MAP 列。下面沿用官方文档中的test_map表完整示例从建表、写入到统计元素个数CREATE TABLE test_map( col_int INT, col_map MAPVARCHAR(50),INT ) DUPLICATE KEY(col_int); INSERT INTO test_map VALUES (1, map{a:1,b:2}), (2, map{c:3}), (3, map{d:4,e:5}); SELECT * FROM test_map ORDER BY col_int; ------------------------ | col_int | col_map | ------------------------ | 1 | {a:1,b:2} | | 2 | {c:3} | | 3 | {d:4,e:5} | ------------------------对col_map列逐行调用cardinality()得到每行 Map 的元素个数SELECT cardinality(col_map) FROM test_map ORDER BY col_int; ---------------------- | cardinality(col_map) | ---------------------- | 2 | | 1 | | 2 | ---------------------- 3 rows in set (0.05 sec)结果与数据逐行对应{a:1,b:2}有 2 个元素{c:3}有 1 个{d:4,e:5}有 2 个。四、实操二查询数据湖中的 MAP 数据cardinality()不仅可用于原生表也可作用于数据湖外表中的 MAP 列。以包含如下数据的 Hive 表hive_map为例SELECT * FROM hive_map ORDER BY col_int; ------------------------ | col_int | col_map | ------------------------ | 1 | {a:1,b:2} | | 2 | {c:3} | | 3 | {d:4,e:5} | ------------------------只要在集群中创建了 Hive Catalog原文档中该链接指向docs/en/data_source/catalog/hive_catalog.md#create-a-hive-catalog就可以直接使用该 catalog 下的表调用cardinality()SELECT cardinality(col_map) FROM hive_map ORDER BY col_int; ---------------------- | cardinality(col_map) | ---------------------- | 2 | | 1 | | 2 | ---------------------- 3 rows in set (0.05 sec)这意味着在湖仓一体场景下无需把 Hive/外部表数据导入 StarRocks 内部表即可直接对外部表的 MAP 列做元素个数统计配合 Hive catalog 的联邦查询能力完成湖上分析。五、底层实现BE 向量化执行中的 offsets 差值算法cardinality()/map_size()的 BE 实现位于 be/src/exprs/map_functions.cpp函数声明在 be/src/exprs/map_functions.hStatusOrColumnPtr MapFunctions::map_size(FunctionContext* context, const Columns columns) { DCHECK_EQ(1, columns.size()); RETURN_IF_COLUMNS_ONLY_NULL(columns); auto arg0 ColumnHelper::unpack_and_duplicate_const_column(columns[0]-size(), columns[0]); const size_t num_rows arg0-size(); const auto* col_map down_castconst MapColumn*(ColumnHelper::get_data_column(arg0.get())); auto col_result Int32Column::create(); raw::make_room(col_result-get_data(), num_rows); const uint32_t* offsets col_map-offsets().immutable_data().data(); int32_t* p col_result-get_data().data(); for (size_t i 0; i num_rows; i) { p[i] offsets[i 1] - offsets[i]; } if (arg0-has_null()) { auto null_column NullColumn::static_pointer_cast( Column::mutate(down_castconst NullableColumn*(arg0.get())-null_column())); return NullableColumn::create(std::move(col_result), std::move(null_column)); } else { return col_result; } }从这段源码可以读出cardinality()的四个实现要点O(1) 逐行计算MAP 列在 StarRocks 列式存储中由 keys 列、values 列和 offsets 数组构成第 i 行的 Map 元素个数恰为offsets[i1] - offsets[i]——一次减法即可得出无需遍历键值对因此该函数是典型的向量化轻量标量函数常量列展开unpack_and_duplicate_const_column表明若参数是常量 MAP例如SELECT cardinality(map{a:1,b:2})会先展开为与行数一致的非常量列再计算NULL 直通若输入列带 null 位结果列直接复用输入的 null 位图输入为 NULL 的行输出为 NULL与文档输入为 NULL 返回 NULL的描述一致空 map 返回 0当某行 map 为空时offsets[i1] - offsets[i]为 0返回 0 而非 NULL——这一点可结合 BE 单元测试 be/test/exprs/map_functions_test.cpp 确认测试用例明确构造了空 map[NULL]内容与 NULL 两种输入并断言输出分别为0和NULL// Inputs: // c0 // -------- // [1-11, 2-22, 3-33] // [1-44, 2-55, 4-66] // [2-77, 3-88] // [2-99] // [NULL] // 空 map // NULL // // Query: map_size(c0) // // Outputs: // 3 // 3 // 2 // 1 // 0 // 空 map - 0 // NULL // NULL 输入 - NULL六、进阶cardinality 与低基数优化Low Cardinality Optimize从源码结构看cardinality还被 FE 优化器的低基数改写链路所识别。在 fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/tree/lowcardinality/DecodeCollector.java 中FunctionSet.CARDINALITY被列入支持集合——这意味着在启用低基数优化的场景下优化器在处理带字典编码列的表达式时会将cardinality纳入改写考量范围。对于 MAP 类型列由于 MAP 存储本身是 keys/values/offsets 三元组cardinality()直接在 offsets 上取差值即可完成不需要解引用 key/value 内容这也是该函数在大数据量下仍然高效的原因。七、总结cardinality(any_map)返回 MAP 值的元素个数自 v3.0 起支持是map_size()的别名两者在 BE 层共用MapFunctions::map_size实现返回值类型为 INT输入 NULL 返回 NULLmap 内部的 NULL key/value 按普通值计数空 map 返回 0既可查询 StarRocks 原生表v3.1 起支持建表定义 MAP 列也可配合 Hive catalog 直接查询数据湖外表中的 MAP 列底层实现基于 MapColumn 的 offsets 数组做逐行差值计算天然向量化、无需遍历键值对是湖仓分析中轻量且常用的统计函数。如需进一步了解 MAP 类型其他操作如map_keys、map_values、map_concat等可参考 be/src/exprs/map_functions.h 中的完整函数列表及 MAP 函数文档目录。【免费下载链接】starrocksThe worlds 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),仅供参考
网站建设高端定制企业官网