David Mollitor created SPARK-59185:
--------------------------------------

             Summary: Derive a StartsWith prefix filter from leading-literal 
LIKE patterns
                 Key: SPARK-59185
                 URL: https://issues.apache.org/jira/browse/SPARK-59185
             Project: Spark
          Issue Type: Improvement
          Components: SQL
    Affects Versions: 1.4.0
            Reporter: David Mollitor


h3. What

{{LikeSimplification}} rewrites simple {{LIKE}} patterns into cheaper 
predicates:
{{'A%'}} -> {{{}StartsWith{}}}, {{'%B'}} -> {{{}EndsWith{}}}, {{'A%B'}} -> 
length guard +
{{StartsWith}} + {{{}EndsWith{}}}, {{'%B%'}} -> {{{}Contains{}}}, and an exact 
string -> {{{}EqualTo{}}}.

Multi-wildcard patterns that have a leading literal but do not match any of 
those shapes –
e.g. {{{}'A%B%'{}}}, {{{}'AB%CD%EF'{}}}, {{'A_B%'}} – fall through unchanged 
and remain a full regex
{{{}Like{}}}. Nothing is derived from the leading literal, so the data source 
receives no
predicate and the per-row regex runs on every row.

This improvement makes {{LikeSimplification}} additionally derive the leading 
literal {{A}}
as the necessary condition {{{}StartsWith(col, A){}}}, keeping the original 
{{LIKE}} as the exact
residual:
{code:java}
col LIKE 'A%B%'  ==>  StartsWith(col, A) && (col LIKE 'A%B%')
{code}
{{StartsWith}} is placed first so the cheap check short-circuits the regex, and 
it is a
predicate the existing pushdown path already understands.
h3. Why
 * {{StartsWith}} on a UTF8_BINARY column translates to 
{{sources.StringStartsWith}} and lets Parquet prune row groups via min/max 
statistics (readers cannot prune on the raw {{{}Like{}}}).
 * On rows that fail the prefix, the cheap {{StartsWith}} short-circuits the 
more expensive
regex match.
 * Results are unchanged: {{StartsWith(A)}} is implied by {{{}LIKE 'A%...'{}}}, 
and the exact
{{LIKE}} is retained as the residual, so the conjunction accepts exactly the 
same rows.

h3. Restricted to binary-equality collations

The derivation only fires when the input collation has binary equality
({{{}StringType.supportsBinaryEquality{}}}, i.e. UTF8_BINARY). Two reasons:
 * *Correctness.* {{Like}} matches via a Java regex with collation-aware case 
flags, whereas {{StartsWith}} matches via {{{}CollationSupport{}}}. Under a 
non-binary collation (e.g. UTF8_LCASE) these two case-folding engines can 
disagree on edge cases, so {{StartsWith(A)}} would not be a guaranteed 
necessary condition and could wrongly drop a matching row. Under binary equality
both are exact byte matching, so the implication holds.
 * *Benefit.* {{StringStartsWith}} is pushed down (and prunes in Parquet) only 
for UTF8_BINARY; for non-binary collations it is wrapped as 
{{{}CollatedStringStartsWith{}}}, which readers ignore.

h3. Example
{code:java}
-- before: full regex, no pushdown
Filter (col LIKE 'ab%cd%')

-- after: prefix pushes down and prunes; LIKE re-checks exactly
Filter (StartsWith(col, 'ab') AND (col LIKE 'ab%cd%'))
{code}



--
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