This is an automated email from the ASF dual-hosted git repository. starocean999 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 1d984e0ebb1 return residual expr of join (#28760) 1d984e0ebb1 is described below commit 1d984e0ebb1010f58b860c3089254053566d5b13 Author: 谢健 <jianx...@gmail.com> AuthorDate: Mon Dec 25 12:53:14 2023 +0800 return residual expr of join (#28760) --- .../jobs/joinorder/hypergraph/HyperGraph.java | 158 +++++++++++++-------- .../jobs/joinorder/hypergraph/edge/Edge.java | 22 +++ .../jobs/joinorder/hypergraph/edge/FilterEdge.java | 15 -- .../mv/AbstractMaterializedViewRule.java | 6 +- .../rules/exploration/mv/ComparisonResult.java | 94 ++++++++++++ .../nereids/rules/exploration/mv/StructInfo.java | 2 +- .../joinorder/hypergraph/CompareOuterJoinTest.java | 13 +- ...uterJoinTest.java => PullupExpressionTest.java} | 108 ++++---------- .../rules/exploration/mv/BuildStructInfoTest.java | 4 +- 9 files changed, 257 insertions(+), 165 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java index e534fc1fa84..7bd33c64b3c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java @@ -27,6 +27,7 @@ import org.apache.doris.nereids.jobs.joinorder.hypergraph.node.DPhyperNode; import org.apache.doris.nereids.jobs.joinorder.hypergraph.node.StructInfoNode; import org.apache.doris.nereids.memo.Group; import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.rules.exploration.mv.ComparisonResult; import org.apache.doris.nereids.rules.exploration.mv.LogicalCompatibilityContext; import org.apache.doris.nereids.rules.rewrite.PushDownFilterThroughJoin; import org.apache.doris.nereids.trees.expressions.Alias; @@ -44,18 +45,21 @@ import org.apache.doris.nereids.util.PlanUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import javax.annotation.Nullable; /** * The graph is a join graph, whose node is the leaf plan and edge is a join operator. @@ -268,11 +272,11 @@ public class HyperGraph { filterEdges.forEach(e -> { if (LongBitmap.isSubset(e.getReferenceNodes(), leftSubNodes) && !PushDownFilterThroughJoin.COULD_PUSH_THROUGH_LEFT.contains(joinEdge.getJoinType())) { - e.addRejectJoin(joinEdge); + e.addRejectEdge(joinEdge); } if (LongBitmap.isSubset(e.getReferenceNodes(), rightSubNodes) && !PushDownFilterThroughJoin.COULD_PUSH_THROUGH_RIGHT.contains(joinEdge.getJoinType())) { - e.addRejectJoin(joinEdge); + e.addRejectEdge(joinEdge); } }); } @@ -289,9 +293,11 @@ public class HyperGraph { JoinEdge childA = joinEdges.get(i); if (!JoinType.isAssoc(childA.getJoinType(), edgeB.getJoinType())) { leftRequired = LongBitmap.newBitmapUnion(leftRequired, childA.getLeftSubNodes(joinEdges)); + childA.addRejectEdge(edgeB); } if (!JoinType.isLAssoc(childA.getJoinType(), edgeB.getJoinType())) { leftRequired = LongBitmap.newBitmapUnion(leftRequired, childA.getRightSubNodes(joinEdges)); + childA.addRejectEdge(edgeB); } } @@ -299,9 +305,11 @@ public class HyperGraph { JoinEdge childA = joinEdges.get(i); if (!JoinType.isAssoc(edgeB.getJoinType(), childA.getJoinType())) { rightRequired = LongBitmap.newBitmapUnion(rightRequired, childA.getRightSubNodes(joinEdges)); + childA.addRejectEdge(edgeB); } if (!JoinType.isRAssoc(edgeB.getJoinType(), childA.getJoinType())) { rightRequired = LongBitmap.newBitmapUnion(rightRequired, childA.getLeftSubNodes(joinEdges)); + childA.addRejectEdge(edgeB); } } edgeB.setLeftExtendedNodes(leftRequired); @@ -593,57 +601,75 @@ public class HyperGraph { * compare hypergraph * * @param viewHG the compared hyper graph - * @return null represents not compatible, or return some expression which can - * be pull up from this hyper graph + * @return Comparison result */ - public @Nullable List<Expression> isLogicCompatible(HyperGraph viewHG, LogicalCompatibilityContext ctx) { - Map<Edge, Edge> queryToView = constructEdgeMap(viewHG, ctx.getQueryToViewEdgeExpressionMapping()); + public ComparisonResult isLogicCompatible(HyperGraph viewHG, LogicalCompatibilityContext ctx) { + // 1 try to construct a map which can be mapped from edge to edge + Map<Edge, Edge> queryToView = constructMapWithNode(viewHG, ctx.getQueryToViewNodeIDMapping()); - // All edge in view must have a mapped edge in query - if (queryToView.size() != viewHG.edgeSize()) { - return null; + // 2. compare them by expression and extract residual expr + ComparisonResult.Builder builder = new ComparisonResult.Builder(); + ComparisonResult edgeCompareRes = compareEdgesWithExpr(queryToView, ctx.getQueryToViewEdgeExpressionMapping()); + if (edgeCompareRes.isInvalid()) { + return ComparisonResult.INVALID; } + builder.addComparisonResult(edgeCompareRes); - boolean allMatch = queryToView.entrySet().stream() - .allMatch(entry -> - compareEdgeWithNode(entry.getKey(), entry.getValue(), ctx.getQueryToViewNodeIDMapping())); - if (!allMatch) { - return null; + // 3. pull join edge of view is no sense, so reject them + if (!queryToView.values().containsAll(viewHG.joinEdges)) { + return ComparisonResult.INVALID; } - // join edges must be identical - boolean isJoinIdentical = joinEdges.stream() - .allMatch(queryToView::containsKey); - if (!isJoinIdentical) { - return null; + // 4. process residual edges + List<Expression> residualQueryJoin = + processOrphanEdges(Sets.difference(Sets.newHashSet(joinEdges), queryToView.keySet())); + if (residualQueryJoin == null) { + return ComparisonResult.INVALID; } + builder.addQueryExpressions(residualQueryJoin); - // extract all top filters - List<FilterEdge> residualFilterEdges = filterEdges.stream() - .filter(e -> !queryToView.containsKey(e)) - .collect(ImmutableList.toImmutableList()); - if (residualFilterEdges.stream().anyMatch(e -> !e.isTopFilter())) { - return null; + List<Expression> residualQueryFilter = + processOrphanEdges(Sets.difference(Sets.newHashSet(filterEdges), queryToView.keySet())); + if (residualQueryFilter == null) { + return ComparisonResult.INVALID; } - return residualFilterEdges.stream() - .flatMap(e -> e.getExpressions().stream()) - .collect(ImmutableList.toImmutableList()); + builder.addQueryExpressions(residualQueryFilter); + + List<Expression> residualViewFilter = + processOrphanEdges( + Sets.difference(Sets.newHashSet(viewHG.filterEdges), Sets.newHashSet(queryToView.values()))); + if (residualViewFilter == null) { + return ComparisonResult.INVALID; + } + builder.addViewExpressions(residualViewFilter); + + return builder.build(); } - private Map<Edge, Edge> constructEdgeMap(HyperGraph viewHG, Map<Expression, Expression> exprMap) { - Map<Expression, Edge> exprToEdge = constructExprMap(viewHG); - Map<Edge, Edge> queryToView = new HashMap<>(); - joinEdges.stream() - .filter(e -> !e.getExpressions().isEmpty() - && exprMap.containsKey(e.getExpression(0)) - && compareEdgeWithExpr(e, exprToEdge.get(exprMap.get(e.getExpression(0))), exprMap)) - .forEach(e -> queryToView.put(e, exprToEdge.get(exprMap.get(e.getExpression(0))))); - filterEdges.stream() - .filter(e -> !e.getExpressions().isEmpty() - && exprMap.containsKey(e.getExpression(0)) - && compareEdgeWithExpr(e, exprToEdge.get(exprMap.get(e.getExpression(0))), exprMap)) - .forEach(e -> queryToView.put(e, exprToEdge.get(exprMap.get(e.getExpression(0))))); - return queryToView; + private List<Expression> processOrphanEdges(Set<Edge> edges) { + List<Expression> expressions = new ArrayList<>(); + for (Edge edge : edges) { + if (!edge.canPullUp()) { + return null; + } + expressions.addAll(edge.getExpressions()); + } + return expressions; + } + + private Map<Edge, Edge> constructMapWithNode(HyperGraph viewHG, Map<Integer, Integer> nodeMap) { + // TODO use hash map to reduce loop + Map<Edge, Edge> joinEdgeMap = joinEdges.stream().map(qe -> { + Optional<JoinEdge> viewEdge = viewHG.joinEdges.stream() + .filter(ve -> compareEdgeWithNode(qe, ve, nodeMap)).findFirst(); + return Pair.of(qe, viewEdge); + }).filter(e -> e.second.isPresent()).collect(ImmutableMap.toImmutableMap(p -> p.first, p -> p.second.get())); + Map<Edge, Edge> filterEdgeMap = filterEdges.stream().map(qe -> { + Optional<FilterEdge> viewEdge = viewHG.filterEdges.stream() + .filter(ve -> compareEdgeWithNode(qe, ve, nodeMap)).findFirst(); + return Pair.of(qe, viewEdge); + }).filter(e -> e.second.isPresent()).collect(ImmutableMap.toImmutableMap(p -> p.first, p -> p.second.get())); + return ImmutableMap.<Edge, Edge>builder().putAll(joinEdgeMap).putAll(filterEdgeMap).build(); } private boolean compareEdgeWithNode(Edge t, Edge o, Map<Integer, Integer> nodeMap) { @@ -686,24 +712,40 @@ public class HyperGraph { return bitmap2 == newBitmap1; } - private boolean compareEdgeWithExpr(Edge t, Edge o, Map<Expression, Expression> expressionMap) { - if (t.getExpressions().size() != o.getExpressions().size()) { - return false; - } - int size = t.getExpressions().size(); - for (int i = 0; i < size; i++) { - if (!Objects.equals(expressionMap.get(t.getExpression(i)), o.getExpression(i))) { - return false; + private ComparisonResult compareEdgesWithExpr(Map<Edge, Edge> queryToViewedgeMap, + Map<Expression, Expression> queryToView) { + ComparisonResult.Builder builder = new ComparisonResult.Builder(); + for (Entry<Edge, Edge> e : queryToViewedgeMap.entrySet()) { + ComparisonResult res = compareEdgeWithExpr(e.getKey(), e.getValue(), queryToView); + if (res.isInvalid()) { + return ComparisonResult.INVALID; } + builder.addComparisonResult(res); } - return true; + return builder.build(); } - private Map<Expression, Edge> constructExprMap(HyperGraph hyperGraph) { - Map<Expression, Edge> exprToEdge = new HashMap<>(); - hyperGraph.joinEdges.forEach(edge -> edge.getExpressions().forEach(expr -> exprToEdge.put(expr, edge))); - hyperGraph.filterEdges.forEach(edge -> edge.getExpressions().forEach(expr -> exprToEdge.put(expr, edge))); - return exprToEdge; + private ComparisonResult compareEdgeWithExpr(Edge query, Edge view, Map<Expression, Expression> queryToView) { + Set<? extends Expression> queryExprSet = query.getExpressionSet(); + Set<? extends Expression> viewExprSet = view.getExpressionSet(); + + Set<Expression> equalViewExpr = new HashSet<>(); + List<Expression> residualQueryExpr = new ArrayList<>(); + for (Expression queryExpr : queryExprSet) { + if (queryToView.containsKey(queryExpr) && viewExprSet.contains(queryToView.get(queryExpr))) { + equalViewExpr.add(queryToView.get(queryExpr)); + } else { + residualQueryExpr.add(queryExpr); + } + } + List<Expression> residualViewExpr = ImmutableList.copyOf(Sets.difference(viewExprSet, equalViewExpr)); + if (!residualViewExpr.isEmpty() && !view.canPullUp()) { + return ComparisonResult.INVALID; + } + if (!residualQueryExpr.isEmpty() && !query.canPullUp()) { + return ComparisonResult.INVALID; + } + return new ComparisonResult(residualQueryExpr, residualViewExpr); } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/Edge.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/Edge.java index 4b88ce9f60d..c47300922b5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/Edge.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/Edge.java @@ -22,6 +22,8 @@ import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; +import com.google.common.collect.ImmutableSet; + import java.util.BitSet; import java.util.List; import java.util.Set; @@ -51,6 +53,8 @@ public abstract class Edge { // record all sub nodes behind in this operator. It's T function in paper private final long subTreeNodes; + private long rejectNodes = 0; + /** * Create simple edge. */ @@ -71,6 +75,10 @@ public abstract class Edge { return LongBitmap.getCardinality(leftExtendedNodes) == 1 && LongBitmap.getCardinality(rightExtendedNodes) == 1; } + public void addRejectEdge(Edge edge) { + rejectNodes = LongBitmap.newBitmapUnion(edge.getReferenceNodes(), rejectNodes); + } + public void addLeftExtendNode(long left) { this.leftExtendedNodes = LongBitmap.or(this.leftExtendedNodes, left); } @@ -171,6 +179,20 @@ public abstract class Edge { public abstract List<? extends Expression> getExpressions(); + public Set<? extends Expression> getExpressionSet() { + return ImmutableSet.copyOf(getExpressions()); + } + + public boolean canPullUp() { + // Only inner join and filter with none rejectNodes can be pull up + return rejectNodes == 0 + && !(this instanceof JoinEdge && !((JoinEdge) this).getJoinType().isInnerJoin()); + } + + public long getRejectNodes() { + return rejectNodes; + } + public Expression getExpression(int i) { return getExpressions().get(i); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/FilterEdge.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/FilterEdge.java index ec037871025..57c6d9660d0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/FilterEdge.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/edge/FilterEdge.java @@ -22,7 +22,6 @@ import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; -import java.util.ArrayList; import java.util.BitSet; import java.util.List; import java.util.Set; @@ -32,25 +31,11 @@ import java.util.Set; */ public class FilterEdge extends Edge { private final LogicalFilter<? extends Plan> filter; - private final List<Integer> rejectEdges; public FilterEdge(LogicalFilter<? extends Plan> filter, int index, BitSet childEdges, long subTreeNodes, long childRequireNodes) { super(index, childEdges, new BitSet(), subTreeNodes, childRequireNodes, 0L); this.filter = filter; - rejectEdges = new ArrayList<>(); - } - - public void addRejectJoin(JoinEdge joinEdge) { - rejectEdges.add(joinEdge.getIndex()); - } - - public List<Integer> getRejectEdges() { - return rejectEdges; - } - - public boolean isTopFilter() { - return rejectEdges.isEmpty(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java index 90ebe567c46..c63e2d85af3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java @@ -136,12 +136,14 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac LogicalCompatibilityContext compatibilityContext = LogicalCompatibilityContext.from(queryToViewTableMapping, queryToViewSlotMapping, queryStructInfo, viewStructInfo); - List<Expression> pulledUpExpressions = StructInfo.isGraphLogicalEquals(queryStructInfo, viewStructInfo, + ComparisonResult comparisonResult = StructInfo.isGraphLogicalEquals(queryStructInfo, viewStructInfo, compatibilityContext); - if (pulledUpExpressions == null) { + if (comparisonResult.isInvalid()) { logger.debug(currentClassName + " graph logical is not equals so continue"); continue; } + // TODO: Use set of list? And consider view expr + List<Expression> pulledUpExpressions = ImmutableList.copyOf(comparisonResult.getQueryExpressions()); // set pulled up expression to queryStructInfo predicates and update related predicates if (!pulledUpExpressions.isEmpty()) { queryStructInfo.addPredicates(pulledUpExpressions); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/ComparisonResult.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/ComparisonResult.java new file mode 100644 index 00000000000..cc8284f33e6 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/ComparisonResult.java @@ -0,0 +1,94 @@ +// 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.trees.expressions.Expression; + +import com.google.common.collect.ImmutableList; + +import java.util.Collection; +import java.util.List; + +/** + * comparison result of view and query + */ +public class ComparisonResult { + public static final ComparisonResult INVALID = new ComparisonResult(ImmutableList.of(), ImmutableList.of(), false); + public static final ComparisonResult EMPTY = new ComparisonResult(ImmutableList.of(), ImmutableList.of(), true); + private final boolean valid; + private final List<Expression> viewExpressions; + private final List<Expression> queryExpressions; + + public ComparisonResult(List<Expression> queryExpressions, List<Expression> viewExpressions) { + this(queryExpressions, viewExpressions, true); + } + + ComparisonResult(List<Expression> queryExpressions, List<Expression> viewExpressions, boolean valid) { + this.viewExpressions = ImmutableList.copyOf(viewExpressions); + this.queryExpressions = ImmutableList.copyOf(queryExpressions); + this.valid = valid; + } + + public List<Expression> getViewExpressions() { + return viewExpressions; + } + + public List<Expression> getQueryExpressions() { + return queryExpressions; + } + + public boolean isInvalid() { + return !valid; + } + + /** + * Builder + */ + public static class Builder { + ImmutableList.Builder<Expression> queryBuilder = new ImmutableList.Builder<>(); + ImmutableList.Builder<Expression> viewBuilder = new ImmutableList.Builder<>(); + boolean valid = true; + + /** + * add comparisonResult + */ + public Builder addComparisonResult(ComparisonResult comparisonResult) { + if (comparisonResult.isInvalid()) { + valid = false; + return this; + } + queryBuilder.addAll(comparisonResult.getQueryExpressions()); + viewBuilder.addAll(comparisonResult.getViewExpressions()); + return this; + } + + public Builder addQueryExpressions(Collection<Expression> expressions) { + queryBuilder.addAll(expressions); + return this; + } + + public Builder addViewExpressions(Collection<Expression> expressions) { + viewBuilder.addAll(expressions); + return this; + } + + public ComparisonResult build() { + return new ComparisonResult(queryBuilder.build(), viewBuilder.build(), valid); + } + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java index 3c9814cdce3..20da9ee12fd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java @@ -263,7 +263,7 @@ public class StructInfo { * For inner join should judge only the join tables, * for other join type should also judge the join direction, it's input filter that can not be pulled up etc. */ - public static @Nullable List<Expression> isGraphLogicalEquals(StructInfo queryStructInfo, StructInfo viewStructInfo, + public static ComparisonResult isGraphLogicalEquals(StructInfo queryStructInfo, StructInfo viewStructInfo, LogicalCompatibilityContext compatibilityContext) { return queryStructInfo.hyperGraph.isLogicCompatible(viewStructInfo.hyperGraph, compatibilityContext); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java index d0e5084a1c1..cfc88b2aa3c 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java @@ -62,7 +62,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - Assertions.assertTrue(h1.isLogicCompatible(h2, constructContext(p1, p2)) != null); + Assertions.assertFalse(h1.isLogicCompatible(h2, constructContext(p1, p2)).isInvalid()); } @Test @@ -79,7 +79,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - Assertions.assertTrue(h1.isLogicCompatible(h2, constructContext(p1, p2)) != null); + Assertions.assertFalse(h1.isLogicCompatible(h2, constructContext(p1, p2)).isInvalid()); } @Test @@ -104,7 +104,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); + List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)).getQueryExpressions(); Assertions.assertEquals(1, exprList.size()); Assertions.assertEquals("(id = 0)", exprList.get(0).toSql()); } @@ -132,7 +132,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); + List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)).getQueryExpressions(); Assertions.assertEquals(0, exprList.size()); } @@ -159,7 +159,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); + List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)).getQueryExpressions(); Assertions.assertEquals(1, exprList.size()); Assertions.assertEquals("(id = 0)", exprList.get(0).toSql()); } @@ -187,8 +187,7 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); - Assertions.assertEquals(null, exprList); + Assertions.assertTrue(h1.isLogicCompatible(h2, constructContext(p1, p2)).isInvalid()); } LogicalCompatibilityContext constructContext(Plan p1, Plan p2) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java similarity index 54% copy from fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java copy to fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java index d0e5084a1c1..d4818a844e8 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CompareOuterJoinTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java @@ -20,73 +20,23 @@ package org.apache.doris.nereids.jobs.joinorder.hypergraph; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.rules.RuleSet; import org.apache.doris.nereids.rules.exploration.mv.AbstractMaterializedViewRule; +import org.apache.doris.nereids.rules.exploration.mv.ComparisonResult; import org.apache.doris.nereids.rules.exploration.mv.LogicalCompatibilityContext; import org.apache.doris.nereids.rules.exploration.mv.StructInfo; 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.expressions.Expression; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.util.HyperGraphBuilder; 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.List; - -class CompareOuterJoinTest extends SqlTestBase { - @Test - void testStarGraphWithInnerJoin() { - // t2 - // | - //t3-- t1 -- t4 - // | - // t5 - CascadesContext c1 = createCascadesContext( - "select * from T1, T2, T3, T4 where " - + "T1.id = T2.id " - + "and T1.id = T3.id " - + "and T1.id = T4.id ", - connectContext - ); - Plan p1 = PlanChecker.from(c1) - .analyze() - .rewrite() - .getPlan().child(0); - Plan p2 = PlanChecker.from(c1) - .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); - Assertions.assertTrue(h1.isLogicCompatible(h2, constructContext(p1, p2)) != null); - } - - @Test - void testRandomQuery() { - Plan p1 = new HyperGraphBuilder().randomBuildPlanWith(3, 3); - p1 = PlanChecker.from(connectContext, p1) - .analyze() - .rewrite() - .getPlan(); - Plan p2 = PlanChecker.from(connectContext, p1) - .analyze() - .rewrite() - .applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER) - .getAllPlan().get(0); - HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); - HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - Assertions.assertTrue(h1.isLogicCompatible(h2, constructContext(p1, p2)) != null); - } - +class PullupExpressionTest extends SqlTestBase { @Test - void testInnerJoinWithFilter() { - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); + void testPullUpQueryFilter() { CascadesContext c1 = createCascadesContext( - "select * from T1 inner join T2 on T1.id = T2.id where T1.id = 0", + "select * from T1 join T2 on T1.id = T2.id where T1.id = 1", connectContext ); Plan p1 = PlanChecker.from(c1) @@ -94,7 +44,7 @@ class CompareOuterJoinTest extends SqlTestBase { .rewrite() .getPlan().child(0); CascadesContext c2 = createCascadesContext( - "select * from T1 inner join T2 on T1.id = T2.id", + "select * from T1 join T2 on T1.id = T2.id", connectContext ); Plan p2 = PlanChecker.from(c2) @@ -104,17 +54,16 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); - Assertions.assertEquals(1, exprList.size()); - Assertions.assertEquals("(id = 0)", exprList.get(0).toSql()); + ComparisonResult res = h1.isLogicCompatible(h2, constructContext(p1, p2)); + Assertions.assertEquals(2, res.getQueryExpressions().size()); + Assertions.assertEquals("(id = 1)", res.getQueryExpressions().get(0).toSql()); + Assertions.assertEquals("(id = 1)", res.getQueryExpressions().get(1).toSql()); } - @Disabled @Test - void testInnerJoinWithFilter2() { - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); + void testPullUpQueryJoinCondition() { CascadesContext c1 = createCascadesContext( - "select * from T1 inner join T2 on T1.id = T2.id where T1.id = 0", + "select * from T1 join T2 on T1.id = T2.id and T1.score = T2.score", connectContext ); Plan p1 = PlanChecker.from(c1) @@ -122,7 +71,7 @@ class CompareOuterJoinTest extends SqlTestBase { .rewrite() .getPlan().child(0); CascadesContext c2 = createCascadesContext( - "select * from T1 inner join T2 on T1.id = T2.id where T1.id = 0", + "select * from T1 join T2 on T1.id = T2.id", connectContext ); Plan p2 = PlanChecker.from(c2) @@ -132,24 +81,23 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); - Assertions.assertEquals(0, exprList.size()); + ComparisonResult res = h1.isLogicCompatible(h2, constructContext(p1, p2)); + Assertions.assertEquals(1, res.getQueryExpressions().size()); + Assertions.assertEquals("(score = score)", res.getQueryExpressions().get(0).toSql()); } @Test - void testLeftOuterJoinWithLeftFilter() { - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); + void testPullUpViewFilter() { CascadesContext c1 = createCascadesContext( - "select * from ( select * from T1 where T1.id = 0) T1 left outer join T2 on T1.id = T2.id", + "select * from T1 join T2 on T1.id = T2.id", connectContext ); - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); Plan p1 = PlanChecker.from(c1) .analyze() .rewrite() .getPlan().child(0); CascadesContext c2 = createCascadesContext( - "select * from T1 left outer join T2 on T1.id = T2.id", + "select * from T1 join T2 on T1.id = T2.id where T1.id = 1 and T2.id = 1", connectContext ); Plan p2 = PlanChecker.from(c2) @@ -159,25 +107,24 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); - Assertions.assertEquals(1, exprList.size()); - Assertions.assertEquals("(id = 0)", exprList.get(0).toSql()); + ComparisonResult res = h1.isLogicCompatible(h2, constructContext(p1, p2)); + Assertions.assertEquals(2, res.getViewExpressions().size()); + Assertions.assertEquals("(id = 1)", res.getViewExpressions().get(0).toSql()); + Assertions.assertEquals("(id = 1)", res.getViewExpressions().get(1).toSql()); } @Test - void testLeftOuterJoinWithRightFilter() { - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); + void testPullUpViewJoinCondition() { CascadesContext c1 = createCascadesContext( - "select * from T1 left outer join ( select * from T2 where T2.id = 0) T2 on T1.id = T2.id", + "select * from T1 join T2 on T1.id = T2.id ", connectContext ); - connectContext.getSessionVariable().setDisableNereidsRules("INFER_PREDICATES"); Plan p1 = PlanChecker.from(c1) .analyze() .rewrite() .getPlan().child(0); CascadesContext c2 = createCascadesContext( - "select * from T1 left outer join T2 on T1.id = T2.id", + "select * from T1 join T2 on T1.id = T2.id and T1.score = T2.score", connectContext ); Plan p2 = PlanChecker.from(c2) @@ -187,8 +134,9 @@ class CompareOuterJoinTest extends SqlTestBase { .getAllPlan().get(0).child(0); HyperGraph h1 = HyperGraph.toStructInfo(p1).get(0); HyperGraph h2 = HyperGraph.toStructInfo(p2).get(0); - List<Expression> exprList = h1.isLogicCompatible(h2, constructContext(p1, p2)); - Assertions.assertEquals(null, exprList); + ComparisonResult res = h1.isLogicCompatible(h2, constructContext(p1, p2)); + Assertions.assertEquals(1, res.getViewExpressions().size()); + Assertions.assertEquals("(score = score)", res.getViewExpressions().get(0).toSql()); } LogicalCompatibilityContext constructContext(Plan p1, Plan p2) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/BuildStructInfoTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/BuildStructInfoTest.java index 6ac41a49812..f68365f6708 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/BuildStructInfoTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/BuildStructInfoTest.java @@ -79,7 +79,7 @@ class BuildStructInfoTest extends SqlTestBase { .when(j -> { HyperGraph structInfo = HyperGraph.toStructInfo(j).get(0); Assertions.assertTrue(structInfo.getJoinEdge(0).getJoinType().isLeftOuterJoin()); - Assertions.assertEquals(0, (int) structInfo.getFilterEdge(0).getRejectEdges().get(0)); + Assertions.assertEquals(3L, structInfo.getFilterEdge(0).getRejectNodes()); return true; })); @@ -92,7 +92,7 @@ class BuildStructInfoTest extends SqlTestBase { .when(j -> { HyperGraph structInfo = HyperGraph.toStructInfo(j).get(0); Assertions.assertTrue(structInfo.getJoinEdge(0).getJoinType().isLeftOuterJoin()); - Assertions.assertTrue(structInfo.getFilterEdge(0).getRejectEdges().isEmpty()); + Assertions.assertEquals(0, structInfo.getFilterEdge(0).getRejectNodes()); return true; })); } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org