This is an automated email from the ASF dual-hosted git repository. kxiao pushed a commit to branch branch-2.0-beta in repository https://gitbox.apache.org/repos/asf/doris.git
commit a630d520de59753998d825076f9b97e94333e73c Author: jakevin <jakevin...@gmail.com> AuthorDate: Fri Jun 9 11:53:44 2023 +0800 [feature](Nereids): push down alias into union outputs. (#20543) --- .../org/apache/doris/nereids/rules/RuleSet.java | 6 +- .../org/apache/doris/nereids/rules/RuleType.java | 1 + .../rewrite/logical/PushdownAliasIntoUnionAll.java | 86 ++++++++++++++++++++++ .../rewrite/logical/PushdownAliasThroughJoin.java | 35 +++------ .../nereids_tpcds_shape_sf100_p0/shape/query2.out | 11 ++- 5 files changed, 105 insertions(+), 34 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java index 84f7479fa6..fb8dce6576 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java @@ -72,6 +72,7 @@ import org.apache.doris.nereids.rules.rewrite.logical.MergeFilters; import org.apache.doris.nereids.rules.rewrite.logical.MergeGenerates; import org.apache.doris.nereids.rules.rewrite.logical.MergeLimits; import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects; +import org.apache.doris.nereids.rules.rewrite.logical.PushdownAliasIntoUnionAll; import org.apache.doris.nereids.rules.rewrite.logical.PushdownAliasThroughJoin; import org.apache.doris.nereids.rules.rewrite.logical.PushdownExpressionsInHashCondition; import org.apache.doris.nereids.rules.rewrite.logical.PushdownFilterThroughAggregation; @@ -126,7 +127,6 @@ public class RuleSet { new PushdownFilterThroughSetOperation(), new PushdownFilterThroughWindow(), new PushdownProjectThroughLimit(), - new PushdownAliasThroughJoin(), new EliminateOuterJoin(), new MergeProjects(), new MergeFilters(), @@ -135,7 +135,9 @@ public class RuleSet { new PushdownFilterThroughCTE(), new PushdownProjectThroughCTE(), new PushdownFilterThroughCTEAnchor(), - new PushdownProjectThroughCTEAnchor()); + new PushdownProjectThroughCTEAnchor(), + new PushdownAliasThroughJoin(), + new PushdownAliasIntoUnionAll()); public static final List<Rule> IMPLEMENTATION_RULES = planRuleFactories() .add(new LogicalCTEProduceToPhysicalCTEProduce()) 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 2c0e6479c7..7dd712d1e5 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 @@ -138,6 +138,7 @@ public enum RuleType { PUSHDOWN_FILTER_THROUGH_WINDOW(RuleTypeClass.REWRITE), PUSHDOWN_PROJECT_THROUGH_LIMIT(RuleTypeClass.REWRITE), PUSHDOWN_ALIAS_THROUGH_JOIN(RuleTypeClass.REWRITE), + PUSHDOWN_ALIAS_INTO_UNION_ALL(RuleTypeClass.REWRITE), PUSHDOWN_FILTER_THROUGH_SET_OPERATION(RuleTypeClass.REWRITE), PUSHDOWN_FILTER_THROUGH_SORT(RuleTypeClass.REWRITE), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasIntoUnionAll.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasIntoUnionAll.java new file mode 100644 index 0000000000..65ca513b7b --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasIntoUnionAll.java @@ -0,0 +1,86 @@ +// 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.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.Alias; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; +import org.apache.doris.nereids.trees.plans.logical.LogicalUnion; +import org.apache.doris.nereids.util.PlanUtils; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Pushdown Alias (inside must be Slot) into UnionAll outputs. + * <pre> + * Project(c1, c2 as c2t) + * | + * UnionAll output(c1, c2, c3) + * -> + * Project(c1, c2t) + * | + * UnionAll output(c1, c2 as c2t, c3) + * </pre> + */ +public class PushdownAliasIntoUnionAll extends OneRewriteRuleFactory { + @Override + public Rule build() { + return logicalProject(logicalUnion()) + .when(project -> project.child().getQualifier() == Qualifier.ALL) + .when(project -> project.getProjects().stream().allMatch(expr -> + (expr instanceof Slot) || (expr instanceof Alias && ((Alias) expr).child() instanceof Slot))) + .when(project -> project.getProjects().stream().anyMatch(expr -> expr instanceof Alias)) + .then(project -> { + LogicalUnion union = project.child(); + // aliasMap { Slot -> Alias } + Map<Slot, Alias> aliasMap = project.getProjects().stream() + .filter(namedExpression -> namedExpression instanceof Alias) + .map(namedExpression -> (Alias) namedExpression) + .collect(Collectors.toMap( + alias -> (Slot) (alias.child()), + alias -> alias)); + Preconditions.checkState(!aliasMap.isEmpty(), "aliasMap should not be empty"); + List<NamedExpression> newOutput = union.getOutputs().stream() + .map(ne -> { + Slot outSlot = ne.toSlot(); + Alias alias = aliasMap.get(outSlot); + if (alias == null) { + return outSlot; + } + if (ne instanceof Alias) { + return alias.withChildren(ImmutableList.of(((Alias) ne).child())); + } else { + return alias; + } + }) + .collect(Collectors.toList()); + List<NamedExpression> newProjects = project.getProjects().stream().map(NamedExpression::toSlot) + .collect(Collectors.toList()); + return PlanUtils.projectOrSelf(newProjects, union.withNewOutputs(newOutput)); + }).toRule(RuleType.PUSHDOWN_ALIAS_INTO_UNION_ALL); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasThroughJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasThroughJoin.java index 04811beeca..6496b13b9b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasThroughJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownAliasThroughJoin.java @@ -27,12 +27,13 @@ import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; -import org.apache.doris.nereids.trees.plans.logical.LogicalProject; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -41,22 +42,12 @@ import java.util.stream.Collectors; * Pushdown Alias (inside must be Slot) through Join. */ public class PushdownAliasThroughJoin extends OneRewriteRuleFactory { - private boolean isAllSlotOrAliasSlot(LogicalProject<? extends Plan> project) { - return project.getProjects().stream().allMatch(expr -> { - if (expr instanceof Slot) { - return true; - } - if (expr instanceof Alias) { - return ((Alias) expr).child() instanceof Slot; - } - return false; - }); - } - @Override public Rule build() { return logicalProject(logicalJoin()) - .when(this::isAllSlotOrAliasSlot) + .when(project -> project.getProjects().stream().allMatch(expr -> + (expr instanceof Slot) || (expr instanceof Alias && ((Alias) expr).child() instanceof Slot))) + .when(project -> project.getProjects().stream().anyMatch(expr -> expr instanceof Alias)) .then(project -> { LogicalJoin<? extends Plan, ? extends Plan> join = project.child(); // aliasMap { Slot -> List<Alias<Slot>> } @@ -71,9 +62,7 @@ public class PushdownAliasThroughJoin extends OneRewriteRuleFactory { } aliases.add(expr); }); - if (aliasMap.isEmpty()) { - return null; - } + Preconditions.checkState(!aliasMap.isEmpty(), "aliasMap should not be empty"); List<NamedExpression> newProjects = project.getProjects().stream().map(NamedExpression::toSlot) .collect(Collectors.toList()); @@ -122,15 +111,9 @@ public class PushdownAliasThroughJoin extends OneRewriteRuleFactory { private List<NamedExpression> createNewOutput(List<Slot> oldOutput, Map<Expression, List<NamedExpression>> aliasMap) { - List<NamedExpression> output = Lists.newArrayList(); - oldOutput.stream().forEach(slot -> { - List<NamedExpression> alias = aliasMap.get(slot); - if (alias != null) { - output.addAll(alias); - } else { - output.add(slot); - } - }); + List<NamedExpression> output = oldOutput.stream() + .flatMap(slot -> aliasMap.getOrDefault(slot, Collections.singletonList(slot)).stream()) + .collect(Collectors.toList()); return output; } } diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query2.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query2.out index cb297a1129..5b2d1c11c3 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query2.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query2.out @@ -7,12 +7,11 @@ CteAnchor[cteId= ( CTEId#4=] ) --------hashAgg[LOCAL] ----------PhysicalProject ------------hashJoin[INNER_JOIN](date_dim.d_date_sk = wscs.sold_date_sk) ---------------PhysicalProject -----------------PhysicalUnion -------------------PhysicalProject ---------------------PhysicalOlapScan[web_sales] -------------------PhysicalProject ---------------------PhysicalOlapScan[catalog_sales] +--------------PhysicalUnion +----------------PhysicalProject +------------------PhysicalOlapScan[web_sales] +----------------PhysicalProject +------------------PhysicalOlapScan[catalog_sales] --------------PhysicalDistribute ----------------PhysicalProject ------------------PhysicalOlapScan[date_dim] --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org