This is an automated email from the ASF dual-hosted git repository.

jakevin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new d6ff9744c9 [feature](Nereids) covert predicate to SARGABLE (#25180)
d6ff9744c9 is described below

commit d6ff9744c96d37e00088b2e2a4eeed4bee8feebd
Author: 谢健 <jianx...@gmail.com>
AuthorDate: Thu Oct 12 14:46:56 2023 +0800

    [feature](Nereids) covert predicate to SARGABLE (#25180)
    
    covert predicate to SARGABLE
    1. support format like `1 - a`
    2. support rearrange `year/month/week/day/minutes/seconds_sub/add` function
---
 .../rules/SimplifyArithmeticComparisonRule.java    | 154 +++++++++++++--------
 .../expression/SimplifyArithmeticRuleTest.java     |  34 ++++-
 2 files changed, 128 insertions(+), 60 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyArithmeticComparisonRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyArithmeticComparisonRule.java
index 28c66a3ac5..eda95ba32b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyArithmeticComparisonRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyArithmeticComparisonRule.java
@@ -21,16 +21,34 @@ import 
org.apache.doris.nereids.rules.expression.AbstractExpressionRewriteRule;
 import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
 import org.apache.doris.nereids.trees.expressions.Add;
 import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
-import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Divide;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.GreaterThan;
-import org.apache.doris.nereids.trees.expressions.GreaterThanEqual;
-import org.apache.doris.nereids.trees.expressions.LessThan;
-import org.apache.doris.nereids.trees.expressions.LessThanEqual;
 import org.apache.doris.nereids.trees.expressions.Multiply;
 import org.apache.doris.nereids.trees.expressions.Subtract;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
-import org.apache.doris.nereids.util.TypeUtils;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
 
 /**
  * Simplify arithmetic comparison rule.
@@ -40,68 +58,90 @@ import org.apache.doris.nereids.util.TypeUtils;
 public class SimplifyArithmeticComparisonRule extends 
AbstractExpressionRewriteRule {
     public static final SimplifyArithmeticComparisonRule INSTANCE = new 
SimplifyArithmeticComparisonRule();
 
-    @Override
-    public Expression visit(Expression expr, ExpressionRewriteContext context) 
{
-        return expr;
-    }
+    // don't rearrange multiplication because divide may loss precision
+    final Map<Class<? extends Expression>, Class<? extends Expression>> 
rearrangementMap = ImmutableMap
+            .<Class<? extends Expression>, Class<? extends 
Expression>>builder()
+            .put(Add.class, Subtract.class)
+            .put(Subtract.class, Add.class)
+            .put(Divide.class, Multiply.class)
+            .put(YearsSub.class, YearsAdd.class)
+            .put(YearsAdd.class, YearsSub.class)
+            .put(MonthsSub.class, MonthsAdd.class)
+            .put(MonthsAdd.class, MonthsSub.class)
+            .put(WeeksSub.class, WeeksAdd.class)
+            .put(WeeksAdd.class, WeeksSub.class)
+            .put(DaysSub.class, DaysAdd.class)
+            .put(DaysAdd.class, DaysSub.class)
+            .put(HoursSub.class, HoursAdd.class)
+            .put(HoursAdd.class, HoursSub.class)
+            .put(MinutesSub.class, MinutesAdd.class)
+            .put(MinutesAdd.class, MinutesSub.class)
+            .put(SecondsSub.class, SecondsAdd.class)
+            .put(SecondsAdd.class, SecondsSub.class)
+            .build();
 
-    private Expression process(ComparisonPredicate predicate) {
-        Expression left = predicate.left();
-        Expression right = predicate.right();
-        if (TypeUtils.isAddOrSubtract(left)) {
-            Expression p = left.child(1);
-            if (p.isConstant()) {
-                if (TypeUtils.isAdd(left)) {
-                    right = new Subtract(right, p);
-                }
-                if (TypeUtils.isSubtract(left)) {
-                    right = new Add(right, p);
-                }
-                left = left.child(0);
+    @Override
+    public Expression visitComparisonPredicate(ComparisonPredicate comparison, 
ExpressionRewriteContext context) {
+        ComparisonPredicate newComparison = comparison;
+        if (couldRearrange(comparison)) {
+            newComparison = normalize(comparison);
+            if (newComparison == null) {
+                return comparison;
             }
-        }
-        if (TypeUtils.isDivide(left)) {
-            Expression p = left.child(1);
-            if (p.isLiteral()) {
-                right = new Multiply(right, p);
-                left = left.child(0);
-                if (p.toString().startsWith("-")) {
-                    Expression tmp = right;
-                    right = left;
-                    left = tmp;
-                }
+            try {
+                List<Expression> children = 
tryRearrangeChildren(newComparison.left(), newComparison.right());
+                newComparison = (ComparisonPredicate) 
newComparison.withChildren(children);
+            } catch (Exception e) {
+                return comparison;
             }
         }
-        if (left != predicate.left() || right != predicate.right()) {
-            predicate = (ComparisonPredicate) predicate.withChildren(left, 
right);
-            return TypeCoercionUtils.processComparisonPredicate(predicate);
-        } else {
-            return predicate;
-        }
+        return TypeCoercionUtils.processComparisonPredicate(newComparison);
     }
 
-    @Override
-    public Expression visitGreaterThan(GreaterThan greaterThan, 
ExpressionRewriteContext context) {
-        return process(greaterThan);
+    private boolean couldRearrange(ComparisonPredicate cmp) {
+        return rearrangementMap.containsKey(cmp.left().getClass())
+                && !cmp.left().isConstant()
+                && 
cmp.left().children().stream().anyMatch(Expression::isConstant);
     }
 
-    @Override
-    public Expression visitGreaterThanEqual(GreaterThanEqual greaterThanEqual, 
ExpressionRewriteContext context) {
-        return process(greaterThanEqual);
-    }
+    private List<Expression> tryRearrangeChildren(Expression left, Expression 
right) throws Exception {
+        if (!left.child(1).isLiteral()) {
+            throw new RuntimeException(String.format("Expected literal when 
arranging children for Expr %s", left));
+        }
+        Literal leftLiteral = (Literal) left.child(1);
+        Expression leftExpr = left.child(0);
 
-    @Override
-    public Expression visitEqualTo(EqualTo equalTo, ExpressionRewriteContext 
context) {
-        return process(equalTo);
-    }
+        Class<? extends Expression> oppositeOperator = 
rearrangementMap.get(left.getClass());
+        Expression newChild = 
oppositeOperator.getConstructor(Expression.class, Expression.class)
+                .newInstance(right, leftLiteral);
 
-    @Override
-    public Expression visitLessThan(LessThan lessThan, 
ExpressionRewriteContext context) {
-        return process(lessThan);
+        if (left instanceof Divide && leftLiteral.compareTo(new 
IntegerLiteral(0)) < 0) {
+            // Multiplying by a negative number will change the operator.
+            return Arrays.asList(newChild, leftExpr);
+        }
+        return Arrays.asList(leftExpr, newChild);
     }
 
-    @Override
-    public Expression visitLessThanEqual(LessThanEqual lessThanEqual, 
ExpressionRewriteContext context) {
-        return process(lessThanEqual);
+    // Ensure that the second child must be Literal, such as
+    private @Nullable ComparisonPredicate normalize(ComparisonPredicate 
comparison) {
+        if (!(comparison.left().child(1) instanceof Literal)) {
+            Expression left = comparison.left();
+            if (comparison.left() instanceof Add) {
+                // 1 + a > 1 => a + 1 > 1
+                Expression newLeft = left.withChildren(left.child(1), 
left.child(0));
+                comparison = (ComparisonPredicate) 
comparison.withChildren(newLeft, comparison.right());
+            } else if (comparison.left() instanceof Subtract) {
+                // 1 - a > 1 => a + 1 < 1
+                Expression newLeft = left.child(0);
+                Expression newRight = new Add(left.child(1), 
comparison.right());
+                comparison = (ComparisonPredicate) 
comparison.withChildren(newLeft, newRight);
+                comparison = comparison.commute();
+            } else {
+                // Don't normalize division/multiplication because the slot 
sign is undecided.
+                return null;
+            }
+        }
+        return comparison;
     }
+
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyArithmeticRuleTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyArithmeticRuleTest.java
index 567073254a..dd8df29c5b 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyArithmeticRuleTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyArithmeticRuleTest.java
@@ -25,9 +25,9 @@ import 
org.apache.doris.nereids.rules.expression.rules.SimplifyArithmeticRule;
 import com.google.common.collect.ImmutableList;
 import org.junit.jupiter.api.Test;
 
-public class SimplifyArithmeticRuleTest extends ExpressionRewriteTestHelper {
+class SimplifyArithmeticRuleTest extends ExpressionRewriteTestHelper {
     @Test
-    public void testSimplifyArithmetic() {
+    void testSimplifyArithmetic() {
         executor = new ExpressionRuleExecutor(ImmutableList.of(
                 SimplifyArithmeticRule.INSTANCE,
                 FunctionBinder.INSTANCE,
@@ -53,7 +53,7 @@ public class SimplifyArithmeticRuleTest extends 
ExpressionRewriteTestHelper {
     }
 
     @Test
-    public void testSimplifyArithmeticComparison() {
+    void testSimplifyArithmeticComparison() {
         executor = new ExpressionRuleExecutor(ImmutableList.of(
                 SimplifyArithmeticRule.INSTANCE,
                 FoldConstantRule.INSTANCE,
@@ -88,7 +88,35 @@ public class SimplifyArithmeticRuleTest extends 
ExpressionRewriteTestHelper {
         assertRewriteAfterTypeCoercion("IA * ID > IB * IC", "IA * ID > IB * 
IC");
         assertRewriteAfterTypeCoercion("IA * ID / 2 > IB * IC", "cast((IA * 
ID) as DOUBLE) > cast((IB * IC) as DOUBLE) * 2");
         assertRewriteAfterTypeCoercion("IA * ID / -2 > IB * IC", "cast((IB * 
IC) as DOUBLE) * -2 > cast((IA * ID) as DOUBLE)");
+        assertRewriteAfterTypeCoercion("1 - IA > 1", "(cast(IA as BIGINT) < 
0)");
+        assertRewriteAfterTypeCoercion("1 - IA + 1 * 3 - 5 > 1", "(cast(IA as 
BIGINT) < -2)");
     }
 
+    @Test
+    void testSimplifyDateTimeComparison() {
+        executor = new ExpressionRuleExecutor(ImmutableList.of(
+                SimplifyArithmeticRule.INSTANCE,
+                FoldConstantRule.INSTANCE,
+                SimplifyArithmeticComparisonRule.INSTANCE,
+                SimplifyArithmeticRule.INSTANCE,
+                FunctionBinder.INSTANCE,
+                FoldConstantRule.INSTANCE
+        ));
+        assertRewriteAfterTypeCoercion("years_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-01-01 00:00:00')");
+        assertRewriteAfterTypeCoercion("years_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2022-01-01 00:00:00')");
+        assertRewriteAfterTypeCoercion("months_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-01 00:00:00')");
+        assertRewriteAfterTypeCoercion("months_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-02-01 00:00:00')");
+        assertRewriteAfterTypeCoercion("weeks_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-25 00:00:00')");
+        assertRewriteAfterTypeCoercion("weeks_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-01-08 00:00:00')");
+        assertRewriteAfterTypeCoercion("days_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-31 00:00:00')");
+        assertRewriteAfterTypeCoercion("days_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-01-02 00:00:00')");
+        assertRewriteAfterTypeCoercion("hours_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-31 23:00:00')");
+        assertRewriteAfterTypeCoercion("hours_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-01-01 01:00:00')");
+        assertRewriteAfterTypeCoercion("minutes_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-31 23:59:00')");
+        assertRewriteAfterTypeCoercion("minutes_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-01-01 00:01:00')");
+        assertRewriteAfterTypeCoercion("seconds_add(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2020-12-31 23:59:59')");
+        assertRewriteAfterTypeCoercion("seconds_sub(IA, 1) > '2021-01-01 
00:00:00'", "(cast(IA as DATETIMEV2(0)) > '2021-01-01 00:00:01')");
+
+    }
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to