Repository navigation
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Is your feature request related to a problem or challenge?
- related to Should
PruningPredicatecoerce? #14944
The usecase is a predicate like this, where month_id is an integer:
month_id = '202502'In DataFusion this results in casting the month_id column to a Utf8 and then is compared to the string '202502'
This is non ideal for at least 3 reasons:
- Converting many rows to strings is expensive
- Comparing strings is much slower than comparing integers
- many data sources (like parquet) only handle predicates in the form of
<col> <op> <const>and notcast(<col>) <op> <const>so these predicates can be pushed down
Here is an example (note the predicate in the plan below is CAST(foo.month_id AS Utf8) = Utf8("2024") rather than foo.month_id = Int32("2024")):
DataFusion CLI v46.0.0
> create table foo(month_id int) as values (1), (2), (3);
0 row(s) fetched.
Elapsed 0.003 seconds.
> explain select * from foo where month_id = '2024';
+---------------+-------------------------------------------------------+
| plan_type | plan |
+---------------+-------------------------------------------------------+
| logical_plan | Filter: CAST(foo.month_id AS Utf8) = Utf8("2024") |
| | TableScan: foo projection=[month_id] |
| physical_plan | CoalesceBatchesExec: target_batch_size=8192 |
| | FilterExec: CAST(month_id@0 AS Utf8) = 2024 |
| | DataSourceExec: partitions=1, partition_sizes=[1] |
| | |
+---------------+-------------------------------------------------------+
2 row(s) fetched.
Elapsed 0.008 seconds.Describe the solution you'd like
I would like the filter in the plan above to be FilterExec: month_id = 2024 (no cast on month_id)
Other notes:
- I think this applies to
=and!= - I don't think it can be done for
<,<=,>=and>as the semantics for comparing ints and strings is different than equality.
Describe alternatives you've considered
We already have something called unwrap_in_cast that does this transformation
@jayzhan211 has moved this code in this PR
I think once that PR merged, that would be the natural place to add this optimization
Additional context
No response
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
alan910127 commentedon Mar 6, 2025
take
alamb commentedon Mar 6, 2025
We have now merged
UnwrapCastInComparisonintoSimplifier#15012@alan910127 thank you for working on this issue. My suggestion on how to start is to write some tests first
I would personally suggest following the model of this test:
datafusion/datafusion/optimizer/src/simplify_expressions/unwrap_cast.rs
Lines 502 to 507 in da42933
And add an expression like
c1 = 'foo'(c1 is defined here)And the expected expression should be that the column is compared to a int32 literal (not a cast on the column):
alan910127 commentedon Mar 6, 2025
Got it, thanks for the suggestion!
jayzhan211 commentedon Mar 15, 2025
month_id is integer and "2024" is utf8.
In
type_coercion, we cast month_id to utf8 based on the coercion rule.CAST(foo.month_id AS Utf8) = Utf8("2024")Instead of unwrapping the cast after cast. How about we fix the type coercion to avoid the cast at the first place. Given the rhs is literal, we can try to parse the string to i32 and check if it is valid. I expect we end up
foo.month_id = 2024intype_coercion. Although this only works for literal case, if both are columns, then we can only convert it to string since we don't know the value at this point.We can fix the logic in unwrap cast #15110 first, after that we can try on this one
alamb commentedon Mar 15, 2025
I was thinking that this optimization would be good to do in case someone explicitly built the expression
But I agree once #15110 is fixed, this situation might be unlikely