Repository navigation
[Show & Tell] Native Regex Unicode Escape Support in Gluten (Velox & Bolt) #13321
Replies: 2 comments 2 replies
|
@KushShriv, thanks for bringing up this discussion. The proposed translation helps preserve Spark’s regex semantics during native execution. This raises a broader question: should we also let users explicitly choose native-engine semantics where they are willing to accept differences from Spark? For example, we could consider per-feature settings, or a broader “native semantics mode,” that allows RE2 semantics and skips the corresponding compatibility translation and fallback checks. This could extend beyond regex to other areas whose behavior depends on underlying libraries, such as JSON parsing. Some users may prefer a documented native behavior contract over strict Spark compatibility, particularly where compatibility adds substantial complexity or limits native execution. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
[Show & Tell] Native Regex Unicode Escape Support in Gluten (Velox & Bolt)
Hey everyone!
I just opened a pull request to solve a long-standing pain point with regular expressions in Gluten: handling Java-style Unicode escapes (\uXXXX and surrogate pairs) on RE2-backed execution engines like Velox and Bolt.
Check out the PR here: #13278
1. The Problem
Previously, when a Spark query included regex patterns containing Java-style Unicode escapes (such as
\u4e00-\u9fa5for CJK characters or supplementary characters written as surrogate pairs like\uD83D\uDE00), RE2 couldn't parse them. This caused compilation failures on the native side, forcing the entire operator to fall back to Spark (tracked inFallbackSuite).2. The Solution: Two-Layer Defense
To fix this cleanly without breaking ClickHouse or introducing runtime crashes, we implemented a two-pronged approach:
Scala-Side Translation (
ExpressionConverter):We added an escape-aware scanner (
Re2PatternUtils.translateJavaPatternToRe2) that rewrites literal patterns into RE2-compatible syntax right before they are written into the Substrait plan. It coversRLike,RegExpReplace,RegExpExtract,RegExpExtractAll,RegExpInstr, andStringSplit.\1–\9), and unpaired surrogates safely fall back to Spark (GlutenNotSupportException).needsRe2PatternTranslation = true(overridden for Velox and Bolt; ClickHouse is untouched, and Bolt relies purely on the Scala rewrite).C++ Validator as a Strict Safeguard (Velox):
validatePattern()compiles patterns with RE2 exactly as given. If a raw\uever slips past (e.g., from a plan not built by Gluten's converter or a new expression added without Scala wiring), it is rejected at validation time rather than failing mid-execution with a crypticVeloxUserError. The operator simply falls back to Spark gracefully.3. Test Results & Validation
We ran an end-to-end comparison on a 6,000-row table against vanilla Spark and an independent Java regex oracle across 10 different query shapes (
rlike,regexp_replace,split, surrogate pairs, etc.):common_test(C++)Re2PatternUtilsSuiteVeloxStringFunctionsSuiteFallbackSuiteStyle checks (
scalastyle,checkstyle, andspotless) are fully passing for bothbackends-veloxandgluten-substrait.4. What do you think?
Would love to hear your thoughts or feedback on this architecture, especially if you've run into similar regex hurdles with RE2 translation in other connectors! Feel free to drop comments or questions below.
All reactions