ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

StarRocks regexp_replace 函数详解:语法、示例与 BE 向量化实现路径剖析

StarRocks regexp_replace 函数详解:语法、示例与 BE 向量化实现路径剖析 StarRocks regexp_replace 函数详解语法、示例与 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/starrocks本文基于 StarRocks 官方函数参考文档regexp_replace展开介绍该正则替换函数的语法、参数语义与典型用法示例并结合后端BE源码剖析其执行路径从 RE2 逐行匹配到基于 Hyperscan 的向量化加速帮助读者在数据清洗、日志脱敏等场景中既会用函数又理解其底层性能机制。函数功能与返回值regexp_replace用于将字符串str中匹配正则表达式pattern的子串替换为替换串repl。该函数属于 StarRocks 字符串函数族在 SQL 层面注册于前端函数表见 FunctionSet.java 中的常量定义public static final String REGEXP_REPLACE regexp_replace;函数签名为VARCHAR regexp_replace(VARCHAR str, VARCHAR pattern, VARCHAR repl)入参str、pattern、repl均为VARCHAR类型返回值为VARCHAR类型即替换后的完整字符串在优化器常量折叠一侧该函数被标注为可求值的常量函数参数类型{VARCHAR, VARCHAR, VARCHAR}、返回VARCHAR见 ScalarOperatorFunctions.java。官方示例原文档完整继承以下两个示例来自官方文档覆盖了“普通子串替换”和“带反向引用back-reference的替换”两种核心用法MySQL SELECT regexp_replace(a b c, , -); ----------------------------------- | regexp_replace(a b c, , -) | ----------------------------------- | a-b-c | ----------------------------------- MySQL SELECT regexp_replace(a b c,(b),\\1); ---------------------------------------- | regexp_replace(a b c, (b), \1) | ---------------------------------------- | a b c | ----------------------------------------两个示例说明的关键行为全局替换 在a b c中出现两次结果中两处空格全部被替换为-说明默认行为是对所有匹配项逐一替换而非仅替换首个匹配替换串支持反向引用\\1中的\1引用 pattern 中第 1 个捕获组(b)的匹配内容结果a b c表明捕获组内容被原样嵌入替换位置。这是用正则做 HTML 标签化、字段脱敏如regexp_replace(phone, (\\d{3})\\d{4}(\\d{4}), $1****$2)这类脱敏写法的基础能力。语义细节全局替换的边界条件“是否全局替换”并非无条件成立。从 BE 源码结构看StarRocks 根据 pattern 是否锚定来决定替换范围。在函数状态初始化逻辑中见 string_functions.cppstate-global_mode pattern_str.empty() || (!pattern_str.starts_with(^) !pattern_str.ends_with($));可以推断出其判定规则当 pattern既不以^开头、也不以$结尾时进入全局替换模式GlobalReplace替换所有匹配项——这与官方示例一的行为一致当 pattern 以^开头或以$结尾即带有位置锚定语义时走单次替换路径Replace只替换第一个匹配项这一逻辑体现在常量 pattern 的执行分支中全局模式与单次模式由模板参数global_mode区分编译见 string_functions.cppif constexpr (global_mode) { re2::RE2::GlobalReplace(result_str, *const_re, rpl_str); } else { re2::RE2::Replace(result_str, *const_re, rpl_str); }因此在实践中regexp_replace(str, abc$, )去除行尾标记与regexp_replace(str, abc, )去除全部标记的语义是不同类别的操作使用时需留意 pattern 的锚定写法。另外pattern 以^开头或$结尾时的锚定判断是基于 pattern 首尾字符的启发式判断并非完整的正则锚点解析例如.*$不以$开头但含$阅读源码可知这是一种面向常见写法的性能/语义折中。空值与非法 pattern 的处理BE 侧对每行输入做了显式的 NULL 与错误处理实现位于通用执行路径见 string_functions.cppif (str_viewer.is_null(row) || ptn_viewer.is_null(row) || rpl_viewer.is_null(row)) { result.append_null(); continue; } // ... re2::RE2 local_re(ptn_value, *options); if (!local_re.ok()) { context-set_error(strings::Substitute(Invalid regex: $0, ptn_value).c_str()); result.append_null(); continue; }由此可以确认两个实现事实三个参数任意一个为 NULL结果即为 NULL不会报错非法正则的报错时机取决于 pattern 是否常量若 pattern 是常量列会在 fragment 初始化阶段regexp_replace_prepare见 string_functions.cpp就编译校验非法时直接返回Invalid regex expression错误查询提前失败若 pattern 是逐行变化的列则逐行编译非法行输出 NULL 并通过set_error上报错误信息。执行路径剖析从常量优化到 Hyperscan 向量化regexp_replace的 BE 入口是 string_functions.cpp 中的分发函数它按“pattern 是否常量 pattern 是否简单字面量”两个维度选择了最多四条执行路径StatusOrColumnPtr StringFunctions::regexp_replace(FunctionContext* context, const Columns columns) { // pattern 为常量且匹配简单子串模式时走 Hyperscan 加速路径 if (state-use_hyperscan) { if (state-use_hyperscan_vec) { return regexp_replace_use_hyperscan_vec(state, columns); } else { return regexp_replace_use_hyperscan(state, columns); } } // pattern 为常量的 RE2 编译结果 if (state-const_pattern) { if (state-opt_const_rpl.has_value()) { // repl 也是常量最优化路径 return regexp_replace_const_pattern_and_rpl...(const_re, columns, ...); } return regexp_replace_const...(const_re, columns); } // 兜底pattern 逐行变化的通用路径 return regexp_replace_general(context, options, columns); }各路径的适用条件与含义1. Hyperscan 加速路径在regexp_replace_prepare中见 string_functions.cppStarRocks 用两个内部正则判断 pattern 是否“足够简单”static const RE2 SUBSTRING_RE(R((?:\.\*)*([^\.\^\{\[\(\|\)\]\}\\*\?\$\\])(?:\.\*)*), ...); static const RE2 FIXED_LITERAL_RE(R(^[^\.\^\{\[\(\|\)\]\}\\*\?\$\\]$), ...);若 pattern 完整匹配SUBSTRING_RE形如a.*b这类以字面量为主、仅含.*的模式则启用 Hyperscan 编译hs_compile_and_alloc_scratch走regexp_replace_use_hyperscan若 pattern 进一步完整匹配FIXED_LITERAL_RE纯字面量不含任何正则元字符则启用向量化版本regexp_replace_use_hyperscan_vec该路径直接对整个 BinaryColumn 的字节缓冲做一次性扫描替换见 string_functions.cpp逐行解引用与字符串拷贝的开销被摊薄到批处理层面。对应的专项测试 string_fn_regexp_replace_test.cpp 中testHyperscanVec用 5%~95% 不同命中率的随机数据验证了向量化路径与逐行 Hyperscan 路径结果逐行一致ASSERT_EQ(vec-debug_item(i), ori-debug_item(i))保证了加速路径的正确性。该文件中的testMultipleRowsWithPackagePattern还针对_package_.*这类多行匹配场景做了正确性回归。2. 常量 pattern 的 RE2 路径pattern 是常量但不是简单子串模式时RE2 只在 prepare 阶段编译一次state-const_pattern true执行阶段对每行数据复用同一编译结果避免逐行重复编译正则。repl是否常量进一步区分了regexp_replace_const与regexp_replace_const_pattern_and_rpl两个模板实例常量 repl 路径避免逐行拷贝替换串。3. 通用路径pattern 逐行变化非常量列时走regexp_replace_general每行现场构造re2::RE2并调用RE2::GlobalReplace。这是兜底路径也是唯一支持逐行不同 pattern 的路径。RE2 选项配置无论哪条路径RE2 均使用统一的选项见 string_functions.cppstate-options std::make_uniquere2::RE2::Options(); state-options-set_log_errors(false); state-options-set_longest_match(true); state-options-set_dot_nl(true);longest_match(true)匹配采用最左最长策略与常见正则习惯一致dot_nl(true).可以匹配换行符即 pattern 中的.跨行生效log_errors(false)错误不走 RE2 默认日志通道改由 StarRocks 自己的set_error机制上报。Hyperscan 编译则使用HS_FLAG_ALLOWEMPTY | HS_FLAG_DOTALL | HS_FLAG_UTF8 | HS_FLAG_SOM_LEFTMOST标志见 string_fn_regexp_replace_test.cpp 中的等价编译参数其中DOTALL与 RE2 的dot_nl语义对齐SOM_LEFTMOST保证最左匹配顺序。性能建议与使用要点结合上述源码结构可以给出以下实践建议尽量把 pattern 写成常量字面量。pattern 为常量列是启用所有加速路径常量 RE2 复用、Hyperscan、向量化的前提同一列对不同行使用不同 pattern 会退化为通用路径每行都要重新编译正则。纯字面量替换优先考虑更轻的写法。形如regexp_replace(col, 2024-, )的纯字面量 pattern 会命中最快的hyperscan_vec路径但如果只是精确子串替换、不涉及正则语义使用replace函数同样可得到常量快速路径语义更直观。锚定 pattern 的语义差异。带^前缀或$后缀的 pattern 会走单次替换而非全局替换编写“去前缀/去后缀”类转换时需按第 3 节的规则理解其行为。正则方言是 RE2 语法。StarRocks 的 pattern 遵循 RE2 语法规则不支持回溯等 PCRE 特性替换串中可用\1形式的反向引用引用捕获组。Trino 连接器中的两参形式除标准三参形式外仓库中还存在一个值得注意的适配点Trino 兼容层会把 Trino 方言的两参regexp_replace(expr, pattern)调用转换为 StarRocks 的三参形式补默认空串替换见 Trino2SRFunctionCallTransformer.java// support regexp_replace with 2 param registerFunctionTransformer(regexp_replace, 2, new FunctionCallExpr(regexp_replace, ...));也就是说两参“按正则删除匹配内容”的写法是在 Trino 连接器语法翻译场景下获得的在原生 StarRocks SQL 中应按三参签名显式传入替换串。总结regexp_replace是 StarRocks 中做正则级数据清洗的核心函数语法上遵循regexp_replace(str, pattern, repl)三参形式默认全局替换、支持捕获组反向引用任一参数为 NULL 时返回 NULL实现上StarRocks 从源码结构看按“pattern 是否常量、是否简单字面量”分流到 Hyperscan 向量化、常量 RE2 复用、逐行通用共四条路径使得简单 pattern 的大批量清洗能获得接近内存扫描的速度而复杂 pattern 的逐行语义仍由 RE2 保证。相关参考函数文档 regexp_replace.md、BE 实现 string_functions.cpp、BE 函数声明 string_functions.h、前端注册 FunctionSet.java、专项测试 string_fn_regexp_replace_test.cpp。【免费下载链接】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),仅供参考
返回列表