Skip to content

Commit 955f720

Browse files
foxtail463yangtao555
andauthored
[opt](partition prunning) Infer bare-column predicates from monotonic functions for partition pruning (#66288)
Problem Summary: Partition pruning can binary-search sorted partitions only for bare-column comparisons. Predicates such as date_trunc(dt, 'day'), year(dt), and substring(col, 1, n) hide the partition column and may fall back to slower per-partition evaluation. Solution: Derive safe necessary bounds on the bare partition column and use them only during partition pruning, while preserving the original predicate and AND/OR structure. A dedicated rounding trait models FLOOR/CEIL semantics and validates unsafe arguments and casts. Compound interval syntax is bound through DATE_ADD/DATE_SUB, but is not inverse-rewritten because overflow and clamping could change query semantics. Follow-up work: This PR keeps the safety-checked inference local to partition pruning. A follow-up PR will reuse it in global expression optimization so OLAP zone maps and ORC/Parquet min/max pruning can also benefit, with broader pushdown semantics validated separately. Co-authored-by: yangtao555 <yangtao555@jd.com>
1 parent 2bc391a commit 955f720

33 files changed

Lines changed: 1105 additions & 36 deletions

fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/InferPredicateFromMonotonicFunction.java

Lines changed: 338 additions & 0 deletions
Large diffs are not rendered by default.

fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/PartitionPruner.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ private static <K extends Comparable<K>> PartitionPruneResult<K> pruneInternal(
185185
partitionPredicate = PartitionPruneExpressionExtractor.extract(
186186
partitionPredicate, ImmutableSet.copyOf(partitionSlots), cascadesContext);
187187
Expression originalPartitionPredicate = partitionPredicate;
188+
// Keep inferred ranges local to pruning. They can unlock sorted-partition binary search,
189+
// but must not be written back as extra runtime filter conjuncts.
190+
partitionPredicate = InferPredicateFromMonotonicFunction.inferForPartitionPrune(partitionPredicate);
188191
partitionPredicate = PredicateRewriteForPartitionPrune.rewrite(partitionPredicate, cascadesContext);
189192
int expandThreshold = cascadesContext.getAndCacheSessionVariable(
190193
"partitionPruningExpandThreshold",
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.nereids.trees.expressions.functions;
19+
20+
import org.apache.doris.nereids.trees.expressions.Expression;
21+
import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
22+
import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
23+
import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
24+
25+
/**
26+
* Monotonicity of year, quarter, and month ceil functions. Calendar arithmetic can clamp the
27+
* origin's day at month end, so custom origins do not universally guarantee ceil(x) >= x. For
28+
* partition pruning, only the canonical first-day origin is accepted.
29+
*/
30+
public interface CalendarCeilMonotonic extends DateCeilFloorMonotonic {
31+
@Override
32+
default boolean isRoundingRelationGuaranteed() {
33+
if (!DateCeilFloorMonotonic.super.isRoundingRelationGuaranteed()) {
34+
return false;
35+
}
36+
if (arity() == 1 || (arity() == 2 && getArgument(1) instanceof IntegerLikeLiteral)) {
37+
return true;
38+
}
39+
Expression origin = getArgument(arity() - 1);
40+
return origin instanceof DateLiteral
41+
&& ((DateLiteral) origin).compareTo(DateTimeV2Literal.USE_IN_FLOOR_CEIL) == 0;
42+
}
43+
}

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateCeilFloorMonotonic.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
package org.apache.doris.nereids.trees.expressions.functions;
1919

20+
import org.apache.doris.nereids.trees.expressions.Expression;
21+
import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
2022
import org.apache.doris.nereids.trees.expressions.literal.Literal;
2123

22-
/** monotonicity of XX_CEIL and XX_FLOOR */
23-
public interface DateCeilFloorMonotonic extends Monotonic {
24+
/** Monotonicity and rounding relation of date/time ceil and floor functions. */
25+
public interface DateCeilFloorMonotonic extends RoundingMonotonic {
2426
@Override
2527
default boolean isMonotonic(Literal lower, Literal upper) {
2628
switch (arity()) {
@@ -44,4 +46,20 @@ default boolean isPositive() {
4446
default int getMonotonicFunctionChildIndex() {
4547
return 0;
4648
}
49+
50+
@Override
51+
default boolean isRoundingRelationGuaranteed() {
52+
if (arity() == 1) {
53+
return true;
54+
}
55+
if (arity() == 2 && getArgument(1).getDataType().isDateLikeType()) {
56+
return true;
57+
}
58+
return (arity() == 2 || arity() == 3) && isPositiveIntegerLiteral(getArgument(1));
59+
}
60+
61+
private boolean isPositiveIntegerLiteral(Expression expression) {
62+
return expression instanceof IntegerLikeLiteral
63+
&& ((IntegerLikeLiteral) expression).getBigDecimalValue().signum() > 0;
64+
}
4765
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.nereids.trees.expressions.functions;
19+
20+
/** A monotonic function whose result is guaranteed to be on one side of its input. */
21+
public interface RoundingMonotonic extends Monotonic {
22+
/** Direction in which the function rounds its input. */
23+
enum RoundingType {
24+
FLOOR,
25+
CEIL
26+
}
27+
28+
RoundingType getRoundingType();
29+
30+
/** Whether the current arguments preserve the declared relation between the result and input. */
31+
default boolean isRoundingRelationGuaranteed() {
32+
return true;
33+
}
34+
}

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Date.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
import org.apache.doris.catalog.FunctionSignature;
2121
import org.apache.doris.nereids.trees.expressions.Expression;
2222
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
23-
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
2423
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
2524
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
25+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic;
26+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic.RoundingType;
2627
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
2728
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
2829
import org.apache.doris.nereids.types.DateTimeV2Type;
@@ -37,7 +38,8 @@
3738
* ScalarFunction 'date'. This class is generated by GenerateFunction.
3839
*/
3940
public class Date extends ScalarFunction
40-
implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable, PropagateNullLiteral, Monotonic {
41+
implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable, PropagateNullLiteral,
42+
RoundingMonotonic {
4143

4244
//TODO: eliminate this function for Date input
4345
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
@@ -80,6 +82,11 @@ public boolean isPositive() {
8082
return true;
8183
}
8284

85+
@Override
86+
public RoundingType getRoundingType() {
87+
return RoundingType.FLOOR;
88+
}
89+
8390
@Override
8491
public int getMonotonicFunctionChildIndex() {
8592
return 0;

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateTrunc.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
import org.apache.doris.nereids.exceptions.AnalysisException;
2222
import org.apache.doris.nereids.trees.expressions.Expression;
2323
import org.apache.doris.nereids.trees.expressions.functions.CustomSignature;
24-
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
2524
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
2625
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
26+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic;
27+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic.RoundingType;
2728
import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
2829
import org.apache.doris.nereids.trees.expressions.literal.format.DateTimeChecker;
2930
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
@@ -42,7 +43,7 @@
4243
* ScalarFunction 'date_trunc'. This class is generated by GenerateFunction.
4344
*/
4445
public class DateTrunc extends ScalarFunction
45-
implements BinaryExpression, PropagateNullLiteral, PropagateNullable, Monotonic, CustomSignature {
46+
implements BinaryExpression, PropagateNullLiteral, PropagateNullable, RoundingMonotonic, CustomSignature {
4647
private static final List<String> LEGAL_TIME_UNIT =
4748
ImmutableList.of("year", "quarter", "month", "week", "day", "hour", "minute", "second");
4849

@@ -168,6 +169,19 @@ public boolean isPositive() {
168169
return true;
169170
}
170171

172+
@Override
173+
public RoundingType getRoundingType() {
174+
return RoundingType.FLOOR;
175+
}
176+
177+
@Override
178+
public boolean isRoundingRelationGuaranteed() {
179+
int dateArgumentIndex = getMonotonicFunctionChildIndex();
180+
Expression unit = child(dateArgumentIndex == 0 ? 1 : 0);
181+
return unit instanceof StringLikeLiteral
182+
&& LEGAL_TIME_UNIT.contains(((StringLikeLiteral) unit).getStringValue().toLowerCase());
183+
}
184+
171185
@Override
172186
public int getMonotonicFunctionChildIndex() {
173187
return getArgument(0).getDataType().isDateLikeType() ? 0 : 1;

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayCeil.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
2424
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
2525
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
26+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic.RoundingType;
2627
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
2728
import org.apache.doris.nereids.types.DateTimeV2Type;
2829
import org.apache.doris.nereids.types.DateV2Type;
@@ -102,6 +103,11 @@ public List<FunctionSignature> getSignatures() {
102103
return SIGNATURES;
103104
}
104105

106+
@Override
107+
public RoundingType getRoundingType() {
108+
return RoundingType.CEIL;
109+
}
110+
105111
@Override
106112
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
107113
return visitor.visitDayCeil(this, context);

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayFloor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
2424
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
2525
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
26+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic.RoundingType;
2627
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
2728
import org.apache.doris.nereids.types.DateTimeV2Type;
2829
import org.apache.doris.nereids.types.DateV2Type;
@@ -102,6 +103,11 @@ public List<FunctionSignature> getSignatures() {
102103
return SIGNATURES;
103104
}
104105

106+
@Override
107+
public RoundingType getRoundingType() {
108+
return RoundingType.FLOOR;
109+
}
110+
105111
@Override
106112
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
107113
return visitor.visitDayFloor(this, context);

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HourCeil.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
2424
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
2525
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
26+
import org.apache.doris.nereids.trees.expressions.functions.RoundingMonotonic.RoundingType;
2627
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
2728
import org.apache.doris.nereids.types.DateTimeV2Type;
2829
import org.apache.doris.nereids.types.IntegerType;
@@ -99,6 +100,11 @@ public List<FunctionSignature> getSignatures() {
99100
return SIGNATURES;
100101
}
101102

103+
@Override
104+
public RoundingType getRoundingType() {
105+
return RoundingType.CEIL;
106+
}
107+
102108
@Override
103109
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
104110
return visitor.visitHourCeil(this, context);

0 commit comments

Comments
 (0)