
StarRocks map_from_arrays 函数详解从双数组构建 MAP 值的语义、示例与 BE 源码实现【免费下载链接】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/starrocksmap_from_arrays是 StarRocks 中用于将键数组 值数组配对构造为 MAP 类型的 SQL 函数自 v3.1 版本起支持。本篇基于官方函数文档与 BE/FE 源码完整梳理该函数的语法、参数约束、返回规则与全部官方示例并深入剖析其在列式执行引擎中的向量化实现——包括等长校验、NULL 传播、重复键去重保留最后一个相同键等底层行为帮助你在编写 MAP 相关查询时准确预判结果、排查长度不匹配报错并理解 StarRocks MAP 类型的内部数据结构。函数定位与适用版本map_from_arrays的官方定义是Creates a MAP value from the given pair of key item array and value item array由给定的键元素数组和值元素数组构造一个 MAP 值。该函数自v3.1 版本起支持适用于需要在查询中把两组并列的数组动态组装成映射关系的场景例如将拆列后的键值对重新聚合为 MAP、或构造维度标签映射等。在函数集合层面FE 侧于 FunctionSet.java 中注册了函数名常量MAP_FROM_ARRAYS map_from_arrays用于分析器识别与函数解析。语法与参数MAP map_from_arrays(ARRAY keys, ARRAY values)参数说明继承自官方文档参数说明keys用于构造结果 MAP 的键。要求 keys 中的元素唯一见下文去重规则的详细说明。values用于构造结果 MAP 的值。两个参数均为 ARRAY 类型按数组下标一一配对keys[i]与values[i]构成 MAP 中的第 i 个键值对。返回值与三条核心规则返回由输入 keys 与 values 构造出的 MAP文档明确给出三条行为规则长度必须一致keys和values必须具有相同长度否则返回错误。NULL 传播如果 key 或 value即数组参数本身为 NULL函数返回 NULL。返回的 MAP 具有互异的键distinct keys输入中若出现重复键结果 MAP 只保留一份。其中第 3 条规则的精确语义需要特别注意——源码注释写明去重策略为 keep the last identical key保留最后一个相同键而非保留第一个。这一点对含重复键的输入至关重要下面结合源码与示例展开。官方示例逐条解析示例一基础构造select map_from_arrays([1, 2], [Star, Rocks]); -------------------------------------------- || map_from_arrays([1, 2], [Star, Rocks]) | -------------------------------------------- | {1:Star,2:Rocks} | --------------------------------------------两个元素一一对应1 → Star2 → Rocks直接得到 MAP 字面量等价的结果。示例二参数为 NULL 时整体返回 NULLselect map_from_arrays([1, 2], NULL); ------------------------------- || map_from_arrays([1, 2], NULL) | ------------------------------- | NULL | -------------------------------values参数本身是 NULL 数组结果直接为 NULL符合NULL 传播规则。示例三数组内含 NULL 元素而非数组为 NULLselect map_from_arrays([1,3,null,2,null],[ab,cdd,null,null,abc]); -------------------------------------------------------------------------- || map_from_arrays([1, 3, NULL, 2, NULL], [ab, cdd, NULL, NULL, abc]) | -------------------------------------------------------------------------- | {1:ab,3:cdd,2:null,null:abc} | --------------------------------------------------------------------------这条示例信息量最大逐对拆解输入5 个下标0 起下标键值结果中的条目01ab1:ab13cdd3:cdd2NULLNULL被去重移除32NULL2:NULL4NULLabcNULL:abc注意两点数组内含 NULL 元素并不导致整体返回 NULL。NULL 元素会被保留为合法的键值对如2:NULL、NULL:abc这与参数数组本身为 NULL 才返回 NULL的规则形成对照。重复的 NULL 键按保留最后一个去重下标 2 与下标 4 的键都是 NULL最终 MAP 中只保留后出现的NULL:abc前一个条目被丢弃。这正是源码中 keep the last identical key 策略的直接体现。BE 源码实现剖析向量化函数入口该函数在 BE 端以向量化函数形式实现声明于 map_functions.hMapFunctions类中通过DEFINE_VECTORIZED_FN(map_from_arrays)定义完整实现位于 map_functions.cpp 的MapFunctions::map_from_arrays。实现整体分为四个阶段阶段一常量展开与 NULL 结构拆解。对两列输入分别调用ColumnHelper::unpack_and_duplicate_const_column展开常量列再按是否 nullable 拆出NullColumn空值位图与底层ArrayColumn数组数据列。数组列采用 offsets elements 的平铺结构offsets[i]到offsets[i1]即第 i 行数组在 elements 中的区间因此数组长度就是相邻 offset 之差。阶段二等长校验对应规则 1。当两列均无 NULL 时走快速路径只需逐行比较 keys 与 values 的累计 offsets 是否一致只要有一行不一致就返回Status::InvalidArgument(Key and value arrays must be the same length)——这正是文档所说长度不一致返回错误的实现来源// NOTE: only need to check the accumulated offset of each element for (int i 1; i num_rows; i) { num_equals (keys_offsets[i] values_offsets[i]); } if (num_equals ! num_rows) { return Status::InvalidArgument(Key and value arrays must be the same length); }含 NULL 的慢速路径中则只对非 NULL 行逐行调用get_element_size比较元素个数NULL 行的 offset 不推进校验不通过后同样抛出长度错误。阶段三NULL 位图合并与元素拷贝对应规则 2。含 NULL 时函数将 keys 与 values 的空值位图做按位或ColumnHelper::or_two_filters——即只要任意一侧为 NULL该行结果 MAP 整体即为 NULL。随后用跳连续 NULL 段、按段批量拷贝的方式仅把非 NULL 行的键值元素追加进新的 MapColumn 底层存储NULL 行在 offsets 中零宽度占位。这就是输入含 NULL 行时结果 MAP 也为 NULL 行的向量化落地。阶段四构造 MapColumn 并去重对应规则 3。无论哪条路径最后都会执行auto map_column MapColumn::create(...); map_column-remove_duplicated_keys();重复键去重保留最后一个去重逻辑在 map_column.cpp 的MapColumn::remove_duplicated_keys中源码注释直接写明// keep the last identical key。其工作方式对全部键元素计算 FNV 哈希_keys-fnv_hash对每一行 MAP从后往前for j offsets[i1]-1; j offsets[i]; --j扫描键借助unordered_multimapuint32_t, uint32_t记录已见键的哈希桶命中同哈希后再用_keys-equals做精确相等比较与已保留的键重复的条目在filter中标记为 0重建 offsets 并过滤_keys/_values最终 MAP 中相同键只保留最后出现的那个条目。这一反向扫描设计保证了后写覆盖先写在示例三中键为 NULL 的两个条目里下标 4 的NULL:abc先于下标 2 的NULL:NULL进入保留集合因此前者胜出、后者被过滤。此外该函数还支持need_recursive参数递归处理 value 本身也是 MAP 的嵌套场景map_from_arrays的调用路径则只对顶层 MAP 去重。测试覆盖BE 单测 map_functions_test.cpp 覆盖了map_from_arrays的正常构造、NULL 处理等场景FE 侧亦在多个计划/分析测试如 AnalyzeExprTest.java、ConstArrayFunctionFoldingTest.java中验证了该函数的表达式解析与常量折叠行为。使用建议与相关函数先保证长度一致再调用若键值来自split、窗口结果等动态数组建议先用array_length之类的长度函数做一致性过滤避免运行期报错 Key and value arrays must be the same length。不要依赖重复键虽然函数会自动去重且保留最后一个相同键但最后的语义依赖数组顺序官方参数说明明确要求 keys 元素唯一生产查询中应确保键的互异性使结果可预期。区分参数为 NULL与元素含 NULL前者整体返回 NULL后者元素级保留重复的 NULL 键同样参与保留最后一个去重。与配套函数组合同一 MapFunctions 类中还实现了map_size、map_keys、map_values、map_filter、map_entries、map_concat等函数可将map_from_arrays构造出的 MAP 与这些函数串联完成构建、取值、过滤、拼接的完整链路。小结map_from_arrays(ARRAY keys, ARRAY values)以按下标配对、等长约束、NULL 传播、保留最后一个重复键四条行为规则把两个数组转换为 MAP。官方文档给出了语法、参数与三条返回规则及三个可复现示例BE 端 map_functions.cpp 的向量化实现和 map_column.cpp 的哈希去重逻辑则完整印证了这些规则——尤其是重复键保留最后一个这一易被误解的细节。理解这套语义后你可以在 StarRocks v3.1 中放心地用它做动态 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),仅供参考