David Mollitor created SPARK-59354:
--------------------------------------

             Summary: Derive a length guard from LIKE patterns with '_' 
wildcards
                 Key: SPARK-59354
                 URL: https://issues.apache.org/jira/browse/SPARK-59354
             Project: Spark
          Issue Type: Improvement
          Components: SQL
    Affects Versions: 4.1.0
            Reporter: David Mollitor


h3. What

A {{LIKE}} pattern containing the {{_}} wildcard (which matches exactly one 
code point) is not
simplified today – {{LikeSimplification}} leaves it as a full per-row regex. 
Since {{_}}
constrains length, this derives a code-point {*}length guard{*}:
 * no {{%}} -> exact length: {{col LIKE 'a_c'}} implies {{{}Length(col) = 3{}}};
 * with {{%}} -> lower bound: {{col LIKE 'a_b%'}} implies {{{}Length(col) >= 
3{}}};

where N is the number of non-{{{}%{}}} code points in the pattern.

When the pattern has no literals (only {{{}_{}}}/{{{}%{}}}) the guard is 
exactly equivalent, so it
*replaces* the {{{}LIKE{}}}:
{code:java}
col LIKE '___'   ==>   Length(col) = 3
col LIKE '_%'    ==>   Length(col) >= 1
{code}
When the pattern also has literals, the guard is only a necessary condition, so 
the exact
{{LIKE}} is kept as the residual:
{code:java}
col LIKE 'a_c'   ==>   Length(col) = 3  && (col LIKE 'a_c')
col LIKE 'a_b%'  ==>   Length(col) >= 3 && (col LIKE 'a_b%')
{code}
h3. Why are the changes needed?

{{Length(col)}} is an O(n) check that fails fast before the regex, so short 
strings are
rejected (and, for the literal-free cases, the regex is eliminated entirely). 
This is a
CPU/short-circuit improvement.
h3. Correctness
 * {{Length}} is a *code-point* count – the right measure for {{{}_{}}}, which 
matches one code
point regardless of its UTF-8 byte width (so a byte length would be wrong here).
 * The rewrite is valid in every context (not just predicates) and needs no 
collation gate:
{{Length(col) = N}} agrees with {{col LIKE '...'}} even on {{null}} (both are 
null-intolerant),
and for the literal case {{And(guard, LIKE)}} is just the {{LIKE}} conjoined 
with one of its necessary conditions, so it is equivalent to the original 
{{LIKE}} in all cases.
 * Assumes each pattern token consumes exactly one input code point, which 
holds for Spark's {{LIKE}} (Java-regex simple, 1:1 case folding). Idempotency 
under the fixed-point optimizer batch is maintained via a {{TreeNodeTag}} on 
the residual {{{}Like{}}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to