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 245efbe4786 extract agg in struct info node (#29853) 245efbe4786 is described below commit 245efbe4786f0f4409d0c4398ffc533b675e898c Author: 谢健 <jianx...@gmail.com> AuthorDate: Mon Jan 15 13:32:21 2024 +0800 extract agg in struct info node (#29853) --- .../joinorder/hypergraph/node/StructInfoNode.java | 62 ++++++++++++++ .../rules/exploration/mv/HyperGraphComparator.java | 35 +++++++- .../rules/exploration/mv/HyperGraphAggTest.java | 98 ++++++++++++++++++++++ 3 files changed, 191 insertions(+), 4 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java index 424ca6a5f10..9e3886bfdca 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java @@ -19,14 +19,26 @@ package org.apache.doris.nereids.jobs.joinorder.hypergraph.node; import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph; import org.apache.doris.nereids.jobs.joinorder.hypergraph.edge.Edge; +import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.LeafPlan; import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; +import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; +import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.util.Utils; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nullable; /** * HyperGraph Node. @@ -34,9 +46,13 @@ import java.util.List; public class StructInfoNode extends AbstractNode { private List<HyperGraph> graphs = new ArrayList<>(); + private final List<Set<Expression>> expressions; + private final Set<CatalogRelation> relationSet; public StructInfoNode(int index, Plan plan, List<Edge> edges) { super(extractPlan(plan), index, edges); + relationSet = plan.collect(CatalogRelation.class::isInstance); + expressions = collectExpressions(plan); } public StructInfoNode(int index, Plan plan) { @@ -48,6 +64,52 @@ public class StructInfoNode extends AbstractNode { this.graphs = graphs; } + private @Nullable List<Set<Expression>> collectExpressions(Plan plan) { + if (plan instanceof LeafPlan) { + return ImmutableList.of(); + } + List<Set<Expression>> childExpressions = collectExpressions(plan.child(0)); + if (!isValidNodePlan(plan) || childExpressions == null) { + return null; + } + if (plan instanceof LogicalAggregate) { + return ImmutableList.<Set<Expression>>builder() + .add(ImmutableSet.copyOf(plan.getExpressions())) + .add(ImmutableSet.copyOf(((LogicalAggregate<?>) plan).getGroupByExpressions())) + .addAll(childExpressions) + .build(); + } + return ImmutableList.<Set<Expression>>builder() + .add(ImmutableSet.copyOf(plan.getExpressions())) + .addAll(childExpressions) + .build(); + } + + private boolean isValidNodePlan(Plan plan) { + return plan instanceof LogicalProject || plan instanceof LogicalAggregate + || plan instanceof LogicalFilter || plan instanceof LogicalCatalogRelation; + } + + /** + * get all expressions of nodes + */ + public @Nullable List<Expression> getExpressions() { + return expressions.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + public @Nullable List<Set<Expression>> getExprSetList() { + return expressions; + } + + /** + * return catalog relation + */ + public Set<CatalogRelation> getCatalogRelation() { + return relationSet; + } + private static Plan extractPlan(Plan plan) { if (plan instanceof GroupPlan) { //TODO: Note mv can be in logicalExpression, how can we choose it diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java index 7817475c7b8..bf48926348f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap; import org.apache.doris.nereids.jobs.joinorder.hypergraph.edge.Edge; import org.apache.doris.nereids.jobs.joinorder.hypergraph.edge.FilterEdge; import org.apache.doris.nereids.jobs.joinorder.hypergraph.edge.JoinEdge; +import org.apache.doris.nereids.jobs.joinorder.hypergraph.node.StructInfoNode; import org.apache.doris.nereids.rules.rewrite.PushDownFilterThroughJoin; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; @@ -90,14 +91,21 @@ public class HyperGraphComparator { } private ComparisonResult isLogicCompatible() { - // 1 try to construct a map which can be mapped from edge to edge + // 1 compare nodes + boolean nodeMatches = logicalCompatibilityContext.getQueryToViewNodeMapping().entrySet() + .stream().allMatch(e -> compareNodeWithExpr(e.getKey(), e.getValue())); + if (!nodeMatches) { + return ComparisonResult.newInvalidResWithErrorMessage("StructInfoNode are not compatible\n"); + } + + // 2 try to construct a map which can be mapped from edge to edge Map<Edge, Edge> queryToView = constructQueryToViewMapWithExpr(); if (!makeViewJoinCompatible(queryToView)) { return ComparisonResult.newInvalidResWithErrorMessage("Join types are not compatible\n"); } refreshViewEdges(); - // 2. compare them by expression and nodes. Note compare edges after inferring for nodes + // 3. compare them by expression and nodes. Note compare edges after inferring for nodes boolean matchNodes = queryToView.entrySet().stream() .allMatch(e -> compareEdgeWithNode(e.getKey(), e.getValue())); if (!matchNodes) { @@ -105,7 +113,7 @@ public class HyperGraphComparator { } queryToView.forEach(this::compareEdgeWithExpr); - // 3. process residual edges + // 1. process residual edges Sets.difference(getQueryJoinEdgeSet(), queryToView.keySet()) .forEach(e -> pullUpQueryExprWithEdge.put(e, e.getExpressions())); Sets.difference(getQueryFilterEdgeSet(), queryToView.keySet()) @@ -118,6 +126,25 @@ public class HyperGraphComparator { return buildComparisonRes(); } + private boolean compareNodeWithExpr(StructInfoNode query, StructInfoNode view) { + List<Set<Expression>> queryExprSetList = query.getExprSetList(); + List<Set<Expression>> viewExprSetList = view.getExprSetList(); + if (queryExprSetList == null || viewExprSetList == null + || queryExprSetList.size() != viewExprSetList.size()) { + return false; + } + int size = queryExprSetList.size(); + for (int i = 0; i < size; i++) { + Set<Expression> mappingQueryExprSet = queryExprSetList.get(i).stream() + .map(e -> logicalCompatibilityContext.getQueryToViewEdgeExpressionMapping().get(e)) + .collect(Collectors.toSet()); + if (!mappingQueryExprSet.equals(viewExprSetList.get(i))) { + return false; + } + } + return true; + } + private ComparisonResult buildComparisonRes() { ComparisonResult.Builder builder = new ComparisonResult.Builder(); for (Entry<Edge, List<? extends Expression>> e : pullUpQueryExprWithEdge.entrySet()) { @@ -134,7 +161,7 @@ public class HyperGraphComparator { .filter(expr -> !ExpressionUtils.isInferred(expr)) .collect(Collectors.toList()); if (!rawFilter.isEmpty() && !canPullUp(getViewEdgeAfterInferring(e.getKey()))) { - return ComparisonResult.newInvalidResWithErrorMessage(getErrorMessage() + "with error edge\n" + e); + return ComparisonResult.newInvalidResWithErrorMessage(getErrorMessage() + "\nwith error edge\n" + e); } builder.addViewExpressions(rawFilter); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphAggTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphAggTest.java new file mode 100644 index 00000000000..29d3e0edc36 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphAggTest.java @@ -0,0 +1,98 @@ +// 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.exploration.mv; + +import org.apache.doris.nereids.CascadesContext; +import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph; +import org.apache.doris.nereids.jobs.joinorder.hypergraph.node.StructInfoNode; +import org.apache.doris.nereids.rules.RuleSet; +import org.apache.doris.nereids.rules.exploration.mv.mapping.RelationMapping; +import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping; +import org.apache.doris.nereids.sqltest.SqlTestBase; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.util.PlanChecker; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.Objects; + +class HyperGraphAggTest extends SqlTestBase { + @Test + void testJoinWithAgg() { + CascadesContext c2 = createCascadesContext( + "select * from T1 inner join" + + "(" + + "select id from T2 group by id" + + ") T2 " + + "on T1.id = T2.id ", + connectContext + ); + Plan p2 = PlanChecker.from(c2) + .analyze() + .rewrite() + .applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER) + .getAllPlan().get(0).child(0); + HyperGraph h1 = HyperGraph.toStructInfo(p2).get(0); + Assertions.assertEquals("id", Objects.requireNonNull(((StructInfoNode) h1.getNode(1)).getExpressions()).get(0).toSql()); + } + + @Disabled + @Test + void testIJWithAgg() { + connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); + CascadesContext c1 = createCascadesContext( + "select * from T1 inner join T2 " + + "on T1.id = T2.id", + connectContext + ); + Plan p1 = PlanChecker.from(c1) + .analyze() + .rewrite() + .getPlan().child(0); + CascadesContext c2 = createCascadesContext( + "select * from T1 inner join" + + "(" + + "select id from T2 group by id" + + ") T2 " + + "on T1.id = T2.id ", + connectContext + ); + Plan p2 = PlanChecker.from(c2) + .analyze() + .rewrite() + .applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER) + .getAllPlan().get(0).child(0); + HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); + HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); + ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2, constructContext(p1, p2)); + Assertions.assertTrue(!res.isInvalid()); + Assertions.assertEquals(2, res.getViewNoNullableSlot().size()); + } + + LogicalCompatibilityContext constructContext(Plan p1, Plan p2) { + StructInfo st1 = AbstractMaterializedViewRule.extractStructInfo(p1, + null).get(0); + StructInfo st2 = AbstractMaterializedViewRule.extractStructInfo(p2, + null).get(0); + RelationMapping rm = RelationMapping.generate(st1.getRelations(), st2.getRelations()).get(0); + SlotMapping sm = SlotMapping.generate(rm); + return LogicalCompatibilityContext.from(rm, sm, st1, st2); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org