ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

StarRocks any_match 数组高阶函数详解:语法、Lambda 用法与三值逻辑

StarRocks any_match 数组高阶函数详解:语法、Lambda 用法与三值逻辑 StarRocks any_match 数组高阶函数详解语法、Lambda 用法与三值逻辑【免费下载链接】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关联文档中基于 Lambda 高阶函数的any_match()展开介绍其语法、参数、返回值与 NULL 语义并结合 array_map()、Lambda 表达式 的通用规则以及 BE 端ArrayMatch模板实现帮助读者理解any_match的执行原理并掌握在数组/多数组比对、MAP 重写等真实场景中的用法。读完本文你将能正确写出可复用的any_match查询并准确预判其在空数组、NULL 元素、NULL 输入下的三种返回结果。功能概述any_match()是一个高阶数组函数它接收一个 Lambda 函数谓词和一个或多个数组作为参数逐元素逐下标对齐地执行谓词判断并返回数组中是否存在至少一个元素满足该谓词的布尔结果。只要有一个或多个元素匹配谓词返回true即1没有任何元素匹配时返回false即0空数组是false的特例若部分元素上谓词返回 NULL、其余元素全部返回false则整体返回 NULL这是三值逻辑下与全不匹配的区分。该函数自 StarRocksv3.0.6起支持与同族函数 all_match() 互为对偶any_match关注是否存在满足all_match关注是否全部满足。二者在 BE 端共用同一套模板实现只是模板参数isAny不同。语法与参数any_match(lambda_function, arr1, arr2...)参数说明arr1待匹配的主数组即逐个元素施加谓词的对象arrN可选的附加数组供 Lambda 函数体引用如按位与arr1配对比较lambda_function用于匹配值的 Lambda 函数谓词返回布尔值函数返回BOOLEAN类型值。Lambda 函数的使用规则Lambda 函数遵循 array_map() 的使用说明核心约束如下Lambda 只能作为高阶函数的第一个或最后一个参数放在哪个位置不影响计算结果any_match(x - x 0, arr)与any_match(arr, x - x 0)等价传入的数组数量必须与 Lambda 的入参个数一致否则报错例如select any_match(x - x, [1], [2,4])会抛出ERROR 1064 (HY000): Lambda arguments should equal to lambda input arrays.所有数组的元素个数必须相同逐下标对齐参与运算否则报错。Lambda 函数体遵循 Lambda 表达式 的通用约束几乎所有标量函数都可在 Lambda 体内使用但子查询、聚合函数、窗口函数、表函数不支持且 Lambda 内不允许出现相关列correlated columns。返回值与 NULL 语义any_match()的返回值遵循 SQL 三值逻辑可归结为以下判定表输入情况返回至少一个元素使谓词为truetrue1所有元素使谓词为falsefalse0数组为空false0存在元素使谓词为 NULL且其余元素均为falseNULL输入数组本身为 NULL 或谓词结果为 NULLNULL也就是说一旦扫描到true便立即短路返回true只有当存在 NULL 且没有 true时才返回 NULL这使any_match的 NULL 传播语义与普通布尔 OR 的三值逻辑保持一致。实现原理源码级any_match的 BE 端实现位于 array_functions.cpp仅一行委托调用StatusOrColumnPtr ArrayFunctions::any_match(FunctionContext* context, const Columns columns) { return ArrayMatchtrue::process(context, columns); }核心逻辑在模板类ArrayMatchisAny中array_functions.tpp。其注释清晰地描述了等价改写关系all/any_match(lambda_func, array1, array2...)→all/any_match(array_map(lambda_func, array1, array2...))→all/any_match(bool_array)即any_match在逻辑上等价于先用array_map把 Lambda 作用于各数组得到布尔数组再对该布尔数组求是否存在 true。ArrayMatchtrue的求值过程可以概括为逐行取出布尔数组遍历元素遇true立即置结果true并跳出短路遇null标记has_null若遍历结束仍非true且存在has_null则结果为 NULL否则为false数组本身为 NULL 时结果直接为 NULL。从实现可见一个容易被忽略的细节any_match的谓词结果是基于array_map之后产生的布尔数组判定的因此arr1空数组经array_map后得到空布尔数组遍历不到任何元素res保持初始值!isAny即false从而返回false——这与文档中空数组返回 false一致。该实现还以is_const、ConstColumn等方式处理常量列与 NULL 列RETURN_IF_COLUMNS_ONLY_NULL并有对应的单元测试覆盖见 array_functions_test.cpparray_match_nullable、array_match_not_null、array_match_only_null三个测试用例分别验证了可空列、非空列、全 NULL/常量列下ArrayMatchtrue与ArrayMatchfalse的输出例如[1,1,0]返回true、[0]返回false、[1,NULL]返回true、[0,NULL]返回 NULL、空数组返回false。在 FE 端any_match与all_match被注册为内置函数名常量FunctionSet.java支持常量折叠优化可在优化器阶段对常量数组参数直接求值。示例详解以下示例均来自关联文档用于检查x中是否存在小于y对应位置的元素。示例 1存在匹配返回 1select any_match((x,y) - x y, [1,2,8], [4,5,6]); -------------------------------------------------- | any_match((x, y) - x y, [1, 2, 8], [4, 5, 6]) | -------------------------------------------------- | 1 | --------------------------------------------------逐位比较14、25均成立任一满足即返回1短路无需比较到86。示例 2全部不匹配返回 0select any_match((x,y) - x y, [11,12,8], [4,5,6]); ---------------------------------------------------- | any_match((x, y) - x y, [11, 12, 8], [4, 5, 6]) | ---------------------------------------------------- | 0 | ----------------------------------------------------逐位比较114、125、86均不成立返回0。示例 3存在 NULL 且无 true返回 NULLselect any_match((x,y) - x y, [11,12,null], [4,5,6]); ------------------------------------------------------- | any_match((x, y) - x y, [11, 12, NULL], [4, 5, 6]) | ------------------------------------------------------- | NULL | -------------------------------------------------------114、125为 falseNULL6的结果为 NULL且不存在任何 true因此整体返回 NULL。示例 4空数组返回 0select any_match((x,y) - x y, [], []); ------------------------------------ | any_match((x, y) - x y, [], []) | ------------------------------------ | 0 | ------------------------------------空数组没有任何元素不存在匹配元素返回false。示例 5数组本身为 NULL 返回 NULLselect any_match((x,y) - x y, null, [4,5,6]); --------------------------------------------- | any_match((x, y) - x y, NULL, [4, 5, 6]) | --------------------------------------------- | NULL | ---------------------------------------------当arr1本身为 NULL 时结果直接为 NULL对应源码中array_null_map置位分支。在 MAP 上使用 any_matchany_match本身不支持直接作用于 MAP 类型。若要对 MAP 的键值对施加谓词例如判断是否存在k v的键值对需要按如下方式改写借助 transform_values 与 map_valuesany_match((k,v)-kv, map) -- 改写为 any_match(map_values(transform_values((k,v)-kv, map)))示例判断 MAP 中是否存在键大于值的键值对。select any_match(map_values(transform_values((k,v)-kv, map{2:1})));该查询返回1因为键2大于值1。改写思路是先用transform_values将每个键值对映射为布尔结果再用map_values取出布尔值数组最后交给any_match判断是否存在true。与其他高阶函数的配合any_match与all_match是成对存在的高阶函数建议结合以下文档一起阅读all_match()判断数组所有元素是否都满足谓词与any_match使用相同的ArrayMatch模板isAnyfalse空数组返回true存在 NULL 且无 false 时返回 NULLarray_map()any_match内部等价于array_map加布尔数组判定Lambda 参数数量与数组数量一致等约束均继承自它array_filter()、array_sum()、array_sortby()同为支持 Lambda 的高阶数组函数适用场景可互为参考。常见问题与注意事项返回值类型是 BOOLEAN在select结果中以1/0显示可配合where条件直接使用数组数量与 Lambda 入参必须一致、元素个数必须相同否则返回ERROR 1064 (HY000): Lambda arguments should equal to lambda input arrays.之类的错误NULL 与空数组不要混淆空数组返回false而数组为 NULL 或元素为 NULL 且无 true 时返回 NULL三值语义与 SQL 惯例一致版本要求该函数自 v3.0.6 起支持使用时请确认集群版本不低于此版本MAP 需改写不能直接传 MAP需通过map_values(transform_values(...))转换为布尔数组后再调用。【免费下载链接】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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进