[enhancement](nereids)add eliminate filter on one row relation rule (#24980)

1.simplify PushdownFilterThroughSetOperation rule
2.add eliminate filter on one row relation rule
This commit is contained in:
starocean999
2023-10-11 16:12:24 +08:00
committed by GitHub
parent 48b04752a5
commit 6d999f5b95
5 changed files with 98 additions and 39 deletions

View File

@ -198,6 +198,7 @@ public enum RuleType {
ELIMINATE_LIMIT_ON_ONE_ROW_RELATION(RuleTypeClass.REWRITE),
ELIMINATE_LIMIT_ON_EMPTY_RELATION(RuleTypeClass.REWRITE),
ELIMINATE_FILTER(RuleTypeClass.REWRITE),
ELIMINATE_FILTER_ON_ONE_RELATION(RuleTypeClass.REWRITE),
ELIMINATE_NOT_NULL(RuleTypeClass.REWRITE),
ELIMINATE_UNNECESSARY_PROJECT(RuleTypeClass.REWRITE),
ELIMINATE_OUTER_JOIN(RuleTypeClass.REWRITE),

View File

@ -19,27 +19,36 @@ package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.Sets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Eliminate filter which is FALSE or TRUE.
*/
public class EliminateFilter extends OneRewriteRuleFactory {
public class EliminateFilter implements RewriteRuleFactory {
@Override
public Rule build() {
return logicalFilter()
.when(filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance))
public List<Rule> buildRules() {
return ImmutableList.of(logicalFilter().when(
filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance))
.thenApply(ctx -> {
LogicalFilter<Plan> filter = ctx.root;
Set<Expression> newConjuncts = Sets.newHashSetWithExpectedSize(filter.getConjuncts().size());
ImmutableSet.Builder newConjuncts = ImmutableSet.builder();
for (Expression expression : filter.getConjuncts()) {
if (expression == BooleanLiteral.FALSE) {
return new LogicalEmptyRelation(ctx.statementContext.getNextRelationId(),
@ -48,12 +57,44 @@ public class EliminateFilter extends OneRewriteRuleFactory {
newConjuncts.add(expression);
}
}
if (newConjuncts.isEmpty()) {
ImmutableSet<Expression> conjuncts = newConjuncts.build();
if (conjuncts.isEmpty()) {
return filter.child();
} else {
return new LogicalFilter<>(newConjuncts, filter.child());
return new LogicalFilter<>(conjuncts, filter.child());
}
})
.toRule(RuleType.ELIMINATE_FILTER);
.toRule(RuleType.ELIMINATE_FILTER),
logicalFilter(logicalOneRowRelation()).thenApply(ctx -> {
LogicalFilter<LogicalOneRowRelation> filter = ctx.root;
Map<Expression, Expression> replaceMap =
filter.child().getOutputs().stream().filter(e -> e instanceof Alias)
.collect(Collectors.toMap(NamedExpression::toSlot, e -> ((Alias) e).child()));
ImmutableSet.Builder newConjuncts = ImmutableSet.builder();
ExpressionRewriteContext context =
new ExpressionRewriteContext(ctx.cascadesContext);
for (Expression expression : filter.getConjuncts()) {
Expression newExpr = ExpressionUtils.replace(expression, replaceMap);
Expression foldExpression =
FoldConstantRule.INSTANCE.rewrite(newExpr, context);
if (foldExpression == BooleanLiteral.FALSE) {
return new LogicalEmptyRelation(
ctx.statementContext.getNextRelationId(), filter.getOutput());
} else if (foldExpression != BooleanLiteral.TRUE) {
newConjuncts.add(expression);
}
}
ImmutableSet<Expression> conjuncts = newConjuncts.build();
if (conjuncts.isEmpty()) {
return filter.child();
} else {
return new LogicalFilter<>(conjuncts, filter.child());
}
})
.toRule(RuleType.ELIMINATE_FILTER_ON_ONE_RELATION));
}
}

View File

@ -22,11 +22,8 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation;
import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalSetOperation;
import org.apache.doris.nereids.trees.plans.logical.LogicalUnion;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableSet;
@ -44,25 +41,10 @@ public class PushdownFilterThroughSetOperation extends OneRewriteRuleFactory {
@Override
public Rule build() {
return logicalFilter(logicalSetOperation()).when(f -> f.child().getQualifier() == Qualifier.ALL).then(f -> {
return logicalFilter(logicalSetOperation()).then(f -> {
LogicalSetOperation setOperation = f.child();
if (setOperation instanceof LogicalUnion && ((LogicalUnion) setOperation).hasPushedFilter()) {
return f;
}
List<Plan> newChildren = new ArrayList<>();
boolean allOneRowRelation = true;
boolean hasOneRowRelation = false;
for (Plan child : setOperation.children()) {
if (child instanceof OneRowRelation) {
// We shouldn't push down the 'filter' to 'oneRowRelation'.
hasOneRowRelation = true;
newChildren.add(child);
continue;
} else {
allOneRowRelation = false;
}
Map<Expression, Expression> replaceMap = new HashMap<>();
for (int i = 0; i < setOperation.getOutputs().size(); ++i) {
NamedExpression output = setOperation.getOutputs().get(i);
@ -73,14 +55,7 @@ public class PushdownFilterThroughSetOperation extends OneRewriteRuleFactory {
ExpressionUtils.replace(conjunct, replaceMap)).collect(ImmutableSet.toImmutableSet());
newChildren.add(new LogicalFilter<>(newFilterPredicates, child));
}
if (allOneRowRelation) {
return f;
}
if (hasOneRowRelation) {
// If there are some `OneRowRelation` exists, we need to keep the `filter`.
return f.withChildren(((LogicalUnion) setOperation).withHasPushedFilter().withChildren(newChildren));
}
return setOperation.withChildren(newChildren);
}).toRule(RuleType.PUSHDOWN_FILTER_THROUGH_SET_OPERATION);
}