This is an automated email from the ASF dual-hosted git repository.
morrysnow 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 b51f6ae050 [feature](Nereids)add rule: PruneOlapScanTablet (#14378)
b51f6ae050 is described below
commit b51f6ae0500f4bab7971c8557d3ac039ef8b3e9a
Author: mch_ucchi <[email protected]>
AuthorDate: Tue Nov 29 01:06:14 2022 +0800
[feature](Nereids)add rule: PruneOlapScanTablet (#14378)
---
.../glue/translator/PhysicalPlanTranslator.java | 1 +
.../jobs/batch/NereidsRewriteJobExecutor.java | 2 +
.../org/apache/doris/nereids/rules/RuleType.java | 1 +
.../rewrite/logical/PruneOlapScanPartition.java | 2 +-
.../rules/rewrite/logical/PruneOlapScanTablet.java | 84 +++++++++++
.../visitor/ExpressionColumnFilterConverter.java | 134 +++++++++++++++++
.../trees/plans/logical/LogicalOlapScan.java | 50 +++++--
.../apache/doris/nereids/util/ExpressionUtils.java | 30 ++++
.../doris/planner/HashDistributionPruner.java | 2 +-
.../rewrite/logical/PruneOlapScanTabletTest.java | 164 +++++++++++++++++++++
10 files changed, 452 insertions(+), 18 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
index 3faf6b2598..ea368bfedf 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
@@ -393,6 +393,7 @@ public class PhysicalPlanTranslator extends
DefaultPlanVisitor<PlanFragment, Pla
BaseTableRef tableRef = new BaseTableRef(ref, olapTable, tableName);
tupleDescriptor.setRef(tableRef);
olapScanNode.setSelectedPartitionIds(olapScan.getSelectedPartitionIds());
+ olapScanNode.setSampleTabletIds(olapScan.getSelectedTabletIds());
switch (olapScan.getTable().getKeysType()) {
case AGG_KEYS:
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
index 0ebe87f22e..cfd777ad2a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
@@ -38,6 +38,7 @@ import
org.apache.doris.nereids.rules.rewrite.logical.LimitPushDown;
import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects;
import org.apache.doris.nereids.rules.rewrite.logical.NormalizeAggregate;
import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanPartition;
+import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanTablet;
import org.apache.doris.nereids.rules.rewrite.logical.PushFilterInsideJoin;
import org.apache.doris.nereids.rules.rewrite.logical.ReorderJoin;
@@ -88,6 +89,7 @@ public class NereidsRewriteJobExecutor extends BatchRulesJob {
.add(topDownBatch(ImmutableList.of(new
PruneOlapScanPartition())))
.add(topDownBatch(ImmutableList.of(new
SelectMaterializedIndexWithAggregate())))
.add(topDownBatch(ImmutableList.of(new
SelectMaterializedIndexWithoutAggregate())))
+ .add(topDownBatch(ImmutableList.of(new PruneOlapScanTablet())))
// we need to execute this rule at the end of rewrite
// to avoid two consecutive same project appear when we do
optimization.
.add(topDownBatch(ImmutableList.of(new
EliminateGroupByConstant())))
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index 5160fc2b4d..32bb60b8b3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -136,6 +136,7 @@ public enum RuleType {
MATERIALIZED_INDEX_PROJECT_FILTER_SCAN(RuleTypeClass.REWRITE),
MATERIALIZED_INDEX_FILTER_PROJECT_SCAN(RuleTypeClass.REWRITE),
OLAP_SCAN_PARTITION_PRUNE(RuleTypeClass.REWRITE),
+ OLAP_SCAN_TABLET_PRUNE(RuleTypeClass.REWRITE),
EXTRACT_SINGLE_TABLE_EXPRESSION_FROM_DISJUNCTION(RuleTypeClass.REWRITE),
REWRITE_SENTINEL(RuleTypeClass.REWRITE),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
index 018074dcfd..b6e8887f83 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
@@ -89,7 +89,7 @@ public class PruneOlapScanPartition extends
OneRewriteRuleFactory {
partitionInfo.getPartitionColumns(), columnNameToRange);
Collection<Long> selectedPartitionId =
Utils.execWithReturnVal(partitionPruner::prune);
LogicalOlapScan rewrittenScan =
- scan.withSelectedPartitionId(new
ArrayList<>(selectedPartitionId));
+ scan.withSelectedPartitionIds(new
ArrayList<>(selectedPartitionId));
return new LogicalFilter<>(filter.getPredicates(), rewrittenScan);
}).toRule(RuleType.OLAP_SCAN_PARTITION_PRUNE);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTablet.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTablet.java
new file mode 100644
index 0000000000..0251a8ccf5
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTablet.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.rewrite.logical;
+
+import org.apache.doris.catalog.DistributionInfo;
+import org.apache.doris.catalog.DistributionInfo.DistributionInfoType;
+import org.apache.doris.catalog.HashDistributionInfo;
+import org.apache.doris.catalog.MaterializedIndex;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.Partition;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionColumnFilterConverter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
+import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.planner.HashDistributionPruner;
+import org.apache.doris.planner.PartitionColumnFilter;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * prune bucket
+ */
+public class PruneOlapScanTablet extends OneRewriteRuleFactory {
+
+ @Override
+ public Rule build() {
+ return logicalFilter(logicalOlapScan())
+ .when(filter -> !filter.child().isTabletPruned())
+ .then(filter -> {
+ LogicalOlapScan olapScan = filter.child();
+ OlapTable table = olapScan.getTable();
+ List<Long> selectedTabletIds = Lists.newArrayList();
+ for (Long id : olapScan.getSelectedPartitionIds()) {
+ Partition partition = table.getPartition(id);
+ MaterializedIndex index =
partition.getIndex(olapScan.getSelectedIndexId());
+
selectedTabletIds.addAll(getSelectedTabletIds(filter.getConjuncts(),
+ index, partition.getDistributionInfo()));
+ }
+ return
filter.withChildren(olapScan.withSelectedTabletIds(ImmutableList.copyOf(selectedTabletIds)));
+ }).toRule(RuleType.OLAP_SCAN_TABLET_PRUNE);
+ }
+
+ private Collection<Long> getSelectedTabletIds(List<Expression> expressions,
+ MaterializedIndex index, DistributionInfo info) {
+ if (info.getType() != DistributionInfoType.HASH) {
+ return index.getTabletIdsInOrder();
+ }
+ HashDistributionInfo hashInfo = (HashDistributionInfo) info;
+ Map<String, PartitionColumnFilter> filterMap = Maps.newHashMap();
+
expressions.stream().map(ExpressionUtils::checkAndMaybeCommute).filter(Optional::isPresent)
+ .forEach(expr -> new
ExpressionColumnFilterConverter(filterMap).convert(expr.get()));
+ return new HashDistributionPruner(index.getTabletIdsInOrder(),
+ hashInfo.getDistributionColumns(),
+ filterMap,
+ hashInfo.getBucketNum()
+ ).prune();
+ }
+}
+
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionColumnFilterConverter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionColumnFilterConverter.java
new file mode 100644
index 0000000000..be575f73c9
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionColumnFilterConverter.java
@@ -0,0 +1,134 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.visitor;
+
+import org.apache.doris.analysis.Expr;
+import org.apache.doris.analysis.LiteralExpr;
+import org.apache.doris.analysis.NullLiteral;
+import org.apache.doris.analysis.SlotRef;
+import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+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.InPredicate;
+import org.apache.doris.nereids.trees.expressions.IsNull;
+import org.apache.doris.nereids.trees.expressions.LessThan;
+import org.apache.doris.nereids.trees.expressions.LessThanEqual;
+import org.apache.doris.nereids.trees.expressions.NullSafeEqual;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
+import org.apache.doris.planner.PartitionColumnFilter;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * expression column filter converter
+ */
+public class ExpressionColumnFilterConverter
+ extends DefaultExpressionVisitor<Expression, Void> {
+ private final Map<String, PartitionColumnFilter> columnFilterMap;
+
+ private class FilterParam {
+ public LiteralExpr lowerBound = null;
+ public boolean lowerBoundInclusive = false;
+ public LiteralExpr upperBound = null;
+ public boolean upperBoundInclusive = false;
+ public org.apache.doris.analysis.InPredicate inPredicate = null;
+
+ public void setValues(LiteralExpr lowerBound, boolean lowerInclusive,
+ LiteralExpr upperBound, boolean upperInclusive) {
+ this.lowerBound = lowerBound;
+ this.lowerBoundInclusive = lowerInclusive;
+ this.upperBound = upperBound;
+ this.upperBoundInclusive = upperInclusive;
+ }
+
+ public void setInPredicate(org.apache.doris.analysis.InPredicate
inPredicate) {
+ this.inPredicate = inPredicate;
+ }
+ }
+
+ private final FilterParam param = new FilterParam();
+
+ public ExpressionColumnFilterConverter(Map<String, PartitionColumnFilter>
filterMap) {
+ this.columnFilterMap = filterMap;
+ }
+
+ public void convert(Expression expr) {
+ expr.accept(this, null);
+ }
+
+ @Override
+ public Expression visitComparisonPredicate(ComparisonPredicate predicate,
Void unused) {
+ if (predicate instanceof NullSafeEqual) {
+ return null;
+ }
+ LiteralExpr literal = ((Literal) predicate.right()).toLegacyLiteral();
+ if (predicate instanceof EqualTo) {
+ param.setValues(literal, true, literal, true);
+ } else if (predicate instanceof GreaterThan) {
+ param.setValues(literal, false, null, false);
+ } else if (predicate instanceof GreaterThanEqual) {
+ param.setValues(literal, true, null, false);
+ } else if (predicate instanceof LessThan) {
+ param.setValues(null, false, literal, false);
+ } else if (predicate instanceof LessThanEqual) {
+ param.setValues(null, false, literal, true);
+ }
+ setOrUpdateFilter(((Slot) predicate.left()).getName());
+ return null;
+ }
+
+ @Override
+ public Expression visitInPredicate(InPredicate predicate, Void unused) {
+ List<Expr> literals = predicate.getOptions().stream()
+ .map(expr -> ((Expr) ((Literal) expr).toLegacyLiteral()))
+ .collect(Collectors.toList());
+ param.setInPredicate(new org.apache.doris.analysis.InPredicate(new
SlotRef(null, ""), literals, false));
+ setOrUpdateFilter(((Slot) predicate.getCompareExpr()).getName());
+ return null;
+ }
+
+ @Override
+ public Expression visitIsNull(IsNull predicate, Void unused) {
+ param.setValues(new NullLiteral(), true, new NullLiteral(), true);
+ setOrUpdateFilter(((Slot) predicate.child()).getName());
+ return null;
+ }
+
+ private void setOrUpdateFilter(String columnName) {
+ PartitionColumnFilter filter =
columnFilterMap.computeIfAbsent(columnName,
+ k -> new PartitionColumnFilter());
+ if (param.lowerBound != null) {
+ filter.setLowerBound(param.lowerBound, param.lowerBoundInclusive);
+ }
+ if (param.upperBound != null) {
+ filter.setUpperBound(param.upperBound, param.upperBoundInclusive);
+ }
+ if (param.inPredicate != null) {
+ if (filter.getInPredicate() == null) {
+ filter.setInPredicate(param.inPredicate);
+ } else {
+
filter.getInPredicate().getChildren().addAll(param.inPredicate.getListChildren());
+ }
+ }
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
index 79f0b6e02e..dcf4aeeb93 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
@@ -49,6 +49,7 @@ public class LogicalOlapScan extends LogicalRelation
implements CatalogRelation
private final long selectedIndexId;
private final ImmutableList<Long> selectedTabletId;
private final boolean partitionPruned;
+ private final boolean tabletPruned;
private final ImmutableList<Long> candidateIndexIds;
private final boolean indexSelected;
@@ -61,12 +62,14 @@ public class LogicalOlapScan extends LogicalRelation
implements CatalogRelation
public LogicalOlapScan(RelationId id, OlapTable table, List<String>
qualifier) {
this(id, table, qualifier, Optional.empty(), Optional.empty(),
- table.getPartitionIds(), false, ImmutableList.of(), false,
PreAggStatus.on());
+ table.getPartitionIds(), false, ImmutableList.of(), false,
+ ImmutableList.of(), false, PreAggStatus.on());
}
public LogicalOlapScan(RelationId id, Table table, List<String> qualifier)
{
this(id, table, qualifier, Optional.empty(), Optional.empty(),
- ((OlapTable) table).getPartitionIds(), false,
ImmutableList.of(), false, PreAggStatus.on());
+ ((OlapTable) table).getPartitionIds(), false,
ImmutableList.of(), false,
+ ImmutableList.of(), false, PreAggStatus.on());
}
/**
@@ -74,18 +77,18 @@ public class LogicalOlapScan extends LogicalRelation
implements CatalogRelation
*/
public LogicalOlapScan(RelationId id, Table table, List<String> qualifier,
Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties,
- List<Long> selectedPartitionIdList, boolean partitionPruned,
List<Long> candidateIndexIds,
- boolean indexSelected, PreAggStatus preAggStatus) {
+ List<Long> selectedPartitionIds, boolean partitionPruned,
+ ImmutableList<Long> selectedTabletIds, boolean tabletPruned,
+ List<Long> candidateIndexIds, boolean indexSelected, PreAggStatus
preAggStatus) {
super(id, PlanType.LOGICAL_OLAP_SCAN, table, qualifier,
- groupExpression, logicalProperties, selectedPartitionIdList);
+ groupExpression, logicalProperties, selectedPartitionIds);
// TODO: use CBO manner to select best index id, according to index's
statistics info,
// revisit this after rollup and materialized view selection are
fully supported.
this.selectedIndexId = CollectionUtils.isEmpty(candidateIndexIds)
? getTable().getBaseIndexId() : candidateIndexIds.get(0);
- this.selectedTabletId = getTable().getAllPartitions().stream()
- .flatMap(partition ->
partition.getBaseIndex().getTabletIdsInOrder().stream())
- .collect(ImmutableList.toImmutableList());
+ this.selectedTabletId = selectedTabletIds;
this.partitionPruned = partitionPruned;
+ this.tabletPruned = tabletPruned;
this.candidateIndexIds = ImmutableList.copyOf(candidateIndexIds);
this.indexSelected = indexSelected;
this.preAggStatus = preAggStatus;
@@ -124,34 +127,45 @@ public class LogicalOlapScan extends LogicalRelation
implements CatalogRelation
return false;
}
return Objects.equals(selectedPartitionIds, ((LogicalOlapScan)
o).selectedPartitionIds)
- && Objects.equals(candidateIndexIds, ((LogicalOlapScan)
o).candidateIndexIds);
+ && Objects.equals(candidateIndexIds, ((LogicalOlapScan)
o).candidateIndexIds)
+ && Objects.equals(selectedTabletId, ((LogicalOlapScan)
o).selectedTabletId);
}
@Override
public int hashCode() {
- return Objects.hash(id, selectedPartitionIds, candidateIndexIds);
+ return Objects.hash(id, selectedPartitionIds, candidateIndexIds,
selectedTabletId);
}
@Override
public Plan withGroupExpression(Optional<GroupExpression> groupExpression)
{
return new LogicalOlapScan(id, table, qualifier, groupExpression,
Optional.of(getLogicalProperties()),
- selectedPartitionIds, partitionPruned, candidateIndexIds,
indexSelected, preAggStatus);
+ selectedPartitionIds, partitionPruned, selectedTabletId,
tabletPruned,
+ candidateIndexIds, indexSelected, preAggStatus);
}
@Override
public LogicalOlapScan withLogicalProperties(Optional<LogicalProperties>
logicalProperties) {
- return new LogicalOlapScan(id, table, qualifier, Optional.empty(),
logicalProperties, selectedPartitionIds,
- partitionPruned, candidateIndexIds, indexSelected,
preAggStatus);
+ return new LogicalOlapScan(id, table, qualifier, Optional.empty(),
logicalProperties,
+ selectedPartitionIds, partitionPruned, selectedTabletId,
tabletPruned,
+ candidateIndexIds, indexSelected, preAggStatus);
}
- public LogicalOlapScan withSelectedPartitionId(List<Long>
selectedPartitionId) {
+ public LogicalOlapScan withSelectedPartitionIds(List<Long>
selectedPartitionIds) {
return new LogicalOlapScan(id, table, qualifier, Optional.empty(),
Optional.of(getLogicalProperties()),
- selectedPartitionId, true, candidateIndexIds, indexSelected,
preAggStatus);
+ selectedPartitionIds, true, selectedTabletId, tabletPruned,
+ candidateIndexIds, indexSelected, preAggStatus);
}
public LogicalOlapScan withMaterializedIndexSelected(PreAggStatus preAgg,
List<Long> candidateIndexIds) {
return new LogicalOlapScan(id, table, qualifier, Optional.empty(),
Optional.of(getLogicalProperties()),
- selectedPartitionIds, partitionPruned, candidateIndexIds,
true, preAgg);
+ selectedPartitionIds, partitionPruned, selectedTabletId,
tabletPruned,
+ candidateIndexIds, true, preAgg);
+ }
+
+ public LogicalOlapScan withSelectedTabletIds(ImmutableList<Long>
selectedTabletIds) {
+ return new LogicalOlapScan(id, table, qualifier, Optional.empty(),
Optional.of(getLogicalProperties()),
+ selectedPartitionIds, partitionPruned, selectedTabletIds, true,
+ candidateIndexIds, indexSelected, preAggStatus);
}
@Override
@@ -163,6 +177,10 @@ public class LogicalOlapScan extends LogicalRelation
implements CatalogRelation
return partitionPruned;
}
+ public boolean isTabletPruned() {
+ return tabletPruned;
+ }
+
public List<Long> getSelectedTabletId() {
return selectedTabletId;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
index baa91b25a8..6d85eec105 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
@@ -20,9 +20,13 @@ package org.apache.doris.nereids.util;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.expressions.And;
import org.apache.doris.nereids.trees.expressions.Cast;
+import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
import org.apache.doris.nereids.trees.expressions.CompoundPredicate;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.InPredicate;
+import org.apache.doris.nereids.trees.expressions.IsNull;
+import org.apache.doris.nereids.trees.expressions.Not;
import org.apache.doris.nereids.trees.expressions.Or;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
@@ -355,6 +359,32 @@ public class ExpressionUtils {
return groupingSets;
}
+ /**
+ * check and maybe commute for predications except not pred.
+ */
+ public static Optional<Expression> checkAndMaybeCommute(Expression
expression) {
+ if (expression instanceof Not) {
+ return Optional.empty();
+ }
+ if (expression instanceof InPredicate) {
+ InPredicate predicate = ((InPredicate) expression);
+ if (!predicate.getCompareExpr().isSlot()) {
+ return Optional.empty();
+ }
+ return Optional.ofNullable(predicate.getOptions().stream()
+ .allMatch(Expression::isLiteral) ? expression : null);
+ } else if (expression instanceof ComparisonPredicate) {
+ ComparisonPredicate predicate = ((ComparisonPredicate) expression);
+ if (predicate.left() instanceof Literal) {
+ predicate = predicate.commute();
+ }
+ return Optional.ofNullable(predicate.left().isSlot() &&
predicate.right().isLiteral() ? predicate : null);
+ } else if (expression instanceof IsNull) {
+ return Optional.ofNullable(((IsNull) expression).child().isSlot()
? expression : null);
+ }
+ return Optional.empty();
+ }
+
public static List<List<Expression>> cubeToGroupingSets(List<Expression>
cubeExpressions) {
List<List<Expression>> groupingSets = Lists.newArrayList();
cubeToGroupingSets(cubeExpressions, 0, Lists.newArrayList(),
groupingSets);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/planner/HashDistributionPruner.java
b/fe/fe-core/src/main/java/org/apache/doris/planner/HashDistributionPruner.java
index 7ec05c002f..7314fe0564 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/planner/HashDistributionPruner.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/planner/HashDistributionPruner.java
@@ -58,7 +58,7 @@ public class HashDistributionPruner implements
DistributionPruner {
private Map<String, PartitionColumnFilter> distributionColumnFilters;
private int hashMod;
- HashDistributionPruner(List<Long> bucketsList, List<Column> columns,
+ public HashDistributionPruner(List<Long> bucketsList, List<Column> columns,
Map<String, PartitionColumnFilter> filters, int
hashMod) {
this.bucketsList = bucketsList;
this.distributionColumns = columns;
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTabletTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTabletTest.java
new file mode 100644
index 0000000000..e5745658be
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanTabletTest.java
@@ -0,0 +1,164 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.rewrite.logical;
+
+import org.apache.doris.analysis.Expr;
+import org.apache.doris.analysis.IntLiteral;
+import org.apache.doris.analysis.SlotRef;
+import org.apache.doris.analysis.StringLiteral;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.DistributionInfo;
+import org.apache.doris.catalog.HashDistributionInfo;
+import org.apache.doris.catalog.MaterializedIndex;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.Partition;
+import org.apache.doris.catalog.PrimitiveType;
+import org.apache.doris.catalog.Type;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.GreaterThanEqual;
+import org.apache.doris.nereids.trees.expressions.InPredicate;
+import org.apache.doris.nereids.trees.expressions.LessThanEqual;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
+import org.apache.doris.nereids.trees.plans.RelationId;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.MemoTestUtils;
+import org.apache.doris.planner.PartitionColumnFilter;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import mockit.Expectations;
+import mockit.Mocked;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+public class PruneOlapScanTabletTest {
+
+ @Test
+ public void testPruneOlapScanTablet(@Mocked OlapTable olapTable,
+ @Mocked Partition partition, @Mocked MaterializedIndex index,
+ @Mocked HashDistributionInfo distributionInfo) {
+ List<Long> tabletIds = Lists.newArrayListWithExpectedSize(300);
+ for (long i = 0; i < 300; i++) {
+ tabletIds.add(i);
+ }
+
+ List<Column> columns = Lists.newArrayList(
+ new Column("k0", PrimitiveType.DATE, false),
+ new Column("k1", PrimitiveType.INT, false),
+ new Column("k2", PrimitiveType.INT, false),
+ new Column("k3", PrimitiveType.INT, false),
+ new Column("k4", PrimitiveType.INT, false)
+ );
+
+ PartitionColumnFilter k0Filter = new PartitionColumnFilter();
+ k0Filter.setLowerBound(new StringLiteral("2019-08-22"), true);
+ k0Filter.setUpperBound(new StringLiteral("2019-08-22"), true);
+
+ PartitionColumnFilter k1Filter = new PartitionColumnFilter();
+ List<Expr> inList = Lists.newArrayList();
+ inList.add(new IntLiteral(100));
+ inList.add(new IntLiteral(200));
+ inList.add(new IntLiteral(300));
+ inList.add(new IntLiteral(400));
+ inList.add(new IntLiteral(500));
+ k1Filter.setInPredicate(new org.apache.doris.analysis.InPredicate(new
SlotRef(null, "k1"), inList, false));
+
+ PartitionColumnFilter k2Filter = new PartitionColumnFilter();
+ List<Expr> inList2 = Lists.newArrayList();
+ inList2.add(new IntLiteral(900));
+ inList2.add(new IntLiteral(1100));
+ k2Filter.setInPredicate(new org.apache.doris.analysis.InPredicate(new
SlotRef(null, "k2"), inList2, false));
+
+ PartitionColumnFilter k3Filter = new PartitionColumnFilter();
+ List<Expr> inList3 = Lists.newArrayList();
+ inList3.add(new IntLiteral(1));
+ inList3.add(new IntLiteral(3));
+ k3Filter.setInPredicate(new org.apache.doris.analysis.InPredicate(new
SlotRef(null, "k3"), inList3, false));
+
+ PartitionColumnFilter k4Filter = new PartitionColumnFilter();
+ List<Expr> inList4 = Lists.newArrayList();
+ inList4.add(new IntLiteral(2));
+ k4Filter.setInPredicate(new org.apache.doris.analysis.InPredicate(new
SlotRef(null, "k4"), inList4, false));
+
+ SlotReference k0 = new SlotReference("k0",
DataType.convertFromCatalogDataType(Type.INT), false, ImmutableList.of());
+ SlotReference k1 = new SlotReference("k1",
DataType.convertFromCatalogDataType(Type.INT), false, ImmutableList.of());
+ SlotReference k2 = new SlotReference("k2",
DataType.convertFromCatalogDataType(Type.INT), false, ImmutableList.of());
+ SlotReference k3 = new SlotReference("k3",
DataType.convertFromCatalogDataType(Type.INT), false, ImmutableList.of());
+ SlotReference k4 = new SlotReference("k4",
DataType.convertFromCatalogDataType(Type.INT), false, ImmutableList.of());
+
+ GreaterThanEqual greaterThanEqual = new GreaterThanEqual(k0, new
DateLiteral("2019-08-22"));
+ LessThanEqual lessThanEqual = new LessThanEqual(k0, new
DateLiteral("2019-08-22"));
+
+ InPredicate inPredicate1 = new InPredicate(k1, ImmutableList.of(new
IntegerLiteral(101),
+ new IntegerLiteral(201),
+ new IntegerLiteral(301),
+ new IntegerLiteral(401),
+ new IntegerLiteral(500)));
+ InPredicate inPredicate2 = new InPredicate(k2, ImmutableList.of(new
IntegerLiteral(901),
+ new IntegerLiteral(1101)));
+ InPredicate inPredicate3 = new InPredicate(k3, ImmutableList.of(new
IntegerLiteral(1),
+ new IntegerLiteral(3)));
+ EqualTo equalTo = new EqualTo(k4, new IntegerLiteral(10));
+
+ new Expectations() {
+ {
+ olapTable.getPartitionIds();
+ result = ImmutableList.of(1L);
+
+ olapTable.getName();
+ result = "t1";
+ olapTable.getPartition(anyLong);
+ result = partition;
+ partition.getIndex(anyLong);
+ result = index;
+ partition.getDistributionInfo();
+ result = distributionInfo;
+ index.getTabletIdsInOrder();
+ result = tabletIds;
+ distributionInfo.getDistributionColumns();
+ result = columns;
+ distributionInfo.getType();
+ result = DistributionInfo.DistributionInfoType.HASH;
+ distributionInfo.getBucketNum();
+ result = tabletIds.size();
+ }
+ };
+
+ Expression expr = ExpressionUtils.and(greaterThanEqual, lessThanEqual,
inPredicate1, inPredicate2, inPredicate3, equalTo);
+ LogicalFilter<LogicalOlapScan> filter = new LogicalFilter<>(expr,
+ new LogicalOlapScan(RelationId.createGenerator().getNextId(),
olapTable));
+
+ Assertions.assertEquals(0,
filter.child().getSelectedTabletId().size());
+
+ CascadesContext context = MemoTestUtils.createCascadesContext(filter);
+ context.topDownRewrite(ImmutableList.of(new
PruneOlapScanTablet().build()));
+
+ LogicalFilter<LogicalOlapScan> filter1 =
((LogicalFilter<LogicalOlapScan>) context.getMemo().copyOut());
+ LogicalOlapScan olapScan = filter1.child();
+ Assertions.assertEquals(19, olapScan.getSelectedTabletId().size());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]