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 6d6f46e20f6 [nereids](mtmv) Support rewrite by mv nested materialized
view (#33362)
6d6f46e20f6 is described below
commit 6d6f46e20f6bc7d2a1a60281864ac283e18aa501
Author: seawinde <[email protected]>
AuthorDate: Sun Apr 21 00:09:22 2024 +0800
[nereids](mtmv) Support rewrite by mv nested materialized view (#33362)
Support query rewritting by nested materialized view.
Such as `inner_mv` def is as following
> select
> l_linenumber,
> o_custkey,
> o_orderkey,
> o_orderstatus,
> l_partkey,
> l_suppkey,
> l_orderkey
> from lineitem
> inner join orders on lineitem.l_orderkey = orders.o_orderkey;
the mv1_0 def is as following:
> select
> l_linenumber,
> o_custkey,
> o_orderkey,
> o_orderstatus,
> l_partkey,
> l_suppkey,
> l_orderkey,
> ps_availqty
> from inner_mv
> inner join partsupp on l_partkey = ps_partkey AND l_suppkey =
ps_suppkey;
for the following query, both inner_mv and mv1_0 can be successful when
query rewritting by materialized view,and cbo will chose `mv1_0` finally.
> select lineitem.l_linenumber
> from lineitem
> inner join orders on l_orderkey = o_orderkey
> inner join partsupp on l_partkey = ps_partkey AND l_suppkey
= ps_suppkey
> where o_orderstatus = 'o' AND l_linenumber in (1, 2, 3, 4, 5)
---
.../jobs/joinorder/hypergraph/HyperGraph.java | 4 -
.../java/org/apache/doris/nereids/memo/Group.java | 20 +--
.../apache/doris/nereids/memo/StructInfoMap.java | 34 ++--
.../mv/AbstractMaterializedViewAggregateRule.java | 63 ++++---
.../mv/AbstractMaterializedViewJoinRule.java | 5 +-
.../mv/AbstractMaterializedViewRule.java | 148 +++++++----------
.../mv/InitMaterializationContextHook.java | 27 +--
.../mv/LogicalCompatibilityContext.java | 2 +-
.../exploration/mv/MaterializationContext.java | 71 ++++++--
.../mv/MaterializedViewAggregateRule.java | 3 +-
.../mv/MaterializedViewFilterAggregateRule.java | 10 +-
.../mv/MaterializedViewFilterJoinRule.java | 5 +-
...MaterializedViewFilterProjectAggregateRule.java | 10 +-
.../mv/MaterializedViewFilterProjectJoinRule.java | 10 +-
.../mv/MaterializedViewOnlyJoinRule.java | 5 +-
.../mv/MaterializedViewProjectAggregateRule.java | 10 +-
...MaterializedViewProjectFilterAggregateRule.java | 5 +-
.../mv/MaterializedViewProjectFilterJoinRule.java | 10 +-
.../mv/MaterializedViewProjectJoinRule.java | 10 +-
.../exploration/mv/MaterializedViewUtils.java | 55 +++++--
.../nereids/rules/exploration/mv/StructInfo.java | 101 +++++++-----
.../plans/visitor/ExpressionLineageReplacer.java | 37 +++--
.../apache/doris/nereids/util/ExpressionUtils.java | 15 +-
.../joinorder/hypergraph/CompareOuterJoinTest.java | 29 ++--
.../jobs/joinorder/hypergraph/InferJoinTest.java | 21 +--
.../joinorder/hypergraph/InferPredicateTest.java | 10 +-
.../joinorder/hypergraph/PullupExpressionTest.java | 22 +--
.../doris/nereids/memo/StructInfoMapTest.java | 2 +-
.../rules/exploration/mv/BuildStructInfoTest.java | 10 +-
.../rules/exploration/mv/EliminateJoinTest.java | 30 ++--
.../rules/exploration/mv/HyperGraphAggTest.java | 11 +-
.../exploration/mv/HyperGraphComparatorTest.java | 22 +--
.../doris/nereids/util/ExpressionUtilsTest.java | 8 +-
.../mv/nested/nested_materialized_view.out | 20 +++
.../agg_with_roll_up/aggregate_with_roll_up.groovy | 56 ++++---
.../mv/join/inner/inner_join.groovy | 20 ++-
.../mv/nested/nested_materialized_view.groovy | 182 +++++++++++++++++++++
37 files changed, 718 insertions(+), 385 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 5e45fc0bdb8..19ff555469c 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
@@ -356,10 +356,6 @@ public class HyperGraph {
return new HyperGraph(finalOutputs, joinEdges, nodes, filterEdges,
complexProject);
}
- public List<HyperGraph> buildAll() {
- return ImmutableList.of(build());
- }
-
public void updateNode(int idx, Group group) {
Preconditions.checkArgument(nodes.get(idx) instanceof DPhyperNode);
nodes.set(idx, ((DPhyperNode) nodes.get(idx)).withGroup(group));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
index 01968a03bef..a9d3d881491 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
@@ -21,7 +21,6 @@ import org.apache.doris.common.Pair;
import org.apache.doris.nereids.cost.Cost;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.properties.PhysicalProperties;
-import org.apache.doris.nereids.rules.exploration.mv.StructInfo;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
@@ -76,8 +75,6 @@ public class Group {
private int chosenGroupExpressionId = -1;
- private List<StructInfo> structInfos = new ArrayList<>();
-
private StructInfoMap structInfoMap = new StructInfoMap();
/**
@@ -472,6 +469,7 @@ public class Group {
}
str.append(" stats").append("\n");
str.append(getStatistics() == null ? "" : getStatistics().detail("
"));
+
str.append(" lowest Plan(cost, properties, plan, childrenRequires)");
getAllProperties().forEach(
prop -> {
@@ -485,6 +483,10 @@ public class Group {
}
}
);
+
+ str.append("\n").append(" struct info map").append("\n");
+ str.append(structInfoMap);
+
return str.toString();
}
@@ -557,16 +559,4 @@ public class Group {
return TreeStringUtils.treeString(this, toString, getChildren,
getExtraPlans, displayExtraPlan);
}
-
- public List<StructInfo> getStructInfos() {
- return structInfos;
- }
-
- public void addStructInfo(StructInfo structInfo) {
- this.structInfos.add(structInfo);
- }
-
- public void addStructInfo(List<StructInfo> structInfos) {
- this.structInfos.addAll(structInfos);
- }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/StructInfoMap.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/StructInfoMap.java
index d065c5cd3e2..a14c2070a8f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/StructInfoMap.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/StructInfoMap.java
@@ -26,6 +26,7 @@ import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -49,7 +50,7 @@ public class StructInfoMap {
* @param group the group that the mv matched
* @return struct info or null if not found
*/
- public @Nullable StructInfo getStructInfo(BitSet mvTableMap, BitSet
foldTableMap, Group group) {
+ public @Nullable StructInfo getStructInfo(BitSet mvTableMap, BitSet
foldTableMap, Group group, Plan originPlan) {
if (!infoMap.containsKey(mvTableMap)) {
if ((groupExpressionMap.containsKey(foldTableMap) ||
groupExpressionMap.isEmpty())
&& !groupExpressionMap.containsKey(mvTableMap)) {
@@ -59,11 +60,10 @@ public class StructInfoMap {
Pair<GroupExpression, List<BitSet>> groupExpressionBitSetPair
= getGroupExpressionWithChildren(
mvTableMap);
StructInfo structInfo =
constructStructInfo(groupExpressionBitSetPair.first,
- groupExpressionBitSetPair.second, mvTableMap);
+ groupExpressionBitSetPair.second, mvTableMap,
originPlan);
infoMap.put(mvTableMap, structInfo);
}
}
-
return infoMap.get(mvTableMap);
}
@@ -71,13 +71,19 @@ public class StructInfoMap {
return groupExpressionMap.keySet();
}
+ public Collection<StructInfo> getStructInfos() {
+ return infoMap.values();
+ }
+
public Pair<GroupExpression, List<BitSet>>
getGroupExpressionWithChildren(BitSet tableMap) {
return groupExpressionMap.get(tableMap);
}
- private StructInfo constructStructInfo(GroupExpression groupExpression,
List<BitSet> children, BitSet tableMap) {
+ private StructInfo constructStructInfo(GroupExpression groupExpression,
List<BitSet> children,
+ BitSet tableMap, Plan originPlan) {
+ // this plan is not origin plan, should record origin plan in struct
info
Plan plan = constructPlan(groupExpression, children, tableMap);
- return StructInfo.of(plan).get(0);
+ return originPlan == null ? StructInfo.of(plan) : StructInfo.of(plan,
originPlan);
}
private Plan constructPlan(GroupExpression groupExpression, List<BitSet>
children, BitSet tableMap) {
@@ -120,12 +126,11 @@ public class StructInfoMap {
refreshedGroup.add(child);
childrenTableMap.add(child.getstructInfoMap().getTableMaps());
}
-
- if (needRefresh) {
- Set<Pair<BitSet, List<BitSet>>> bitSetWithChildren =
cartesianProduct(childrenTableMap);
- for (Pair<BitSet, List<BitSet>> bitSetWithChild :
bitSetWithChildren) {
- groupExpressionMap.put(bitSetWithChild.first,
Pair.of(groupExpression, bitSetWithChild.second));
- }
+ // if cumulative child table map is different from current
+ // or current group expression map is empty, should update the
groupExpressionMap currently
+ Set<Pair<BitSet, List<BitSet>>> bitSetWithChildren =
cartesianProduct(childrenTableMap);
+ for (Pair<BitSet, List<BitSet>> bitSetWithChild :
bitSetWithChildren) {
+ groupExpressionMap.putIfAbsent(bitSetWithChild.first,
Pair.of(groupExpression, bitSetWithChild.second));
}
}
return originSize != groupExpressionMap.size();
@@ -135,7 +140,7 @@ public class StructInfoMap {
Plan plan = groupExpression.getPlan();
BitSet tableMap = new BitSet();
if (plan instanceof LogicalCatalogRelation) {
- // TODO: Bitmap is not compatible with long, use tree map instead
+ // TODO: Bitset is not compatible with long, use tree map instead
tableMap.set((int) ((LogicalCatalogRelation)
plan).getTable().getId());
}
// one row relation / CTE consumer
@@ -154,4 +159,9 @@ public class StructInfoMap {
})
.collect(Collectors.toSet());
}
+
+ @Override
+ public String toString() {
+ return "StructInfoMap{ groupExpressionMap = " + groupExpressionMap +
", infoMap = " + infoMap + '}';
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
index 5cd2fb769b7..5c8c479986a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
@@ -56,6 +56,7 @@ import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -180,18 +181,27 @@ public abstract class
AbstractMaterializedViewAggregateRule extends AbstractMate
}
// Firstly,if group by expression between query and view is equals,
try to rewrite expression directly
Plan queryTopPlan = queryTopPlanAndAggPair.key();
- if (isGroupByEquals(queryTopPlanAndAggPair, viewTopPlanAndAggPair,
viewToQuerySlotMapping)) {
+ if (isGroupByEquals(queryTopPlanAndAggPair, viewTopPlanAndAggPair,
viewToQuerySlotMapping, queryStructInfo,
+ viewStructInfo)) {
List<Expression> rewrittenQueryExpressions =
rewriteExpression(queryTopPlan.getOutput(),
queryTopPlan,
materializationContext.getMvExprToMvScanExprMapping(),
viewToQuerySlotMapping,
- true);
+ true,
+ queryStructInfo.getTableBitSet());
if (!rewrittenQueryExpressions.isEmpty()) {
- return new LogicalProject<>(
-
rewrittenQueryExpressions.stream().map(NamedExpression.class::cast)
- .collect(Collectors.toList()),
- tempRewritedPlan);
-
+ List<NamedExpression> projects = new ArrayList<>();
+ for (Expression expression : rewrittenQueryExpressions) {
+ if (expression.containsType(AggregateFunction.class)) {
+
materializationContext.recordFailReason(queryStructInfo,
+ "rewritten expression contains aggregate
functions when group equals aggregate rewrite",
+ () -> String.format("aggregate functions =
%s\n", rewrittenQueryExpressions));
+ return null;
+ }
+ projects.add(expression instanceof NamedExpression
+ ? (NamedExpression) expression : new
Alias(expression));
+ }
+ return new LogicalProject<>(projects, tempRewritedPlan);
}
// if fails, record the reason and then try to roll up aggregate
function
materializationContext.recordFailReason(queryStructInfo,
@@ -219,7 +229,7 @@ public abstract class AbstractMaterializedViewAggregateRule
extends AbstractMate
// try to roll up.
// split the query top plan expressions to group expressions and
functions, if can not, bail out.
Pair<Set<? extends Expression>, Set<? extends Expression>>
queryGroupAndFunctionPair
- = topPlanSplitToGroupAndFunction(queryTopPlanAndAggPair);
+ = topPlanSplitToGroupAndFunction(queryTopPlanAndAggPair,
queryStructInfo);
Set<? extends Expression> queryTopPlanFunctionSet =
queryGroupAndFunctionPair.value();
// try to rewrite, contains both roll up aggregate functions and
aggregate group expression
List<NamedExpression> finalOutputExpressions = new ArrayList<>();
@@ -234,9 +244,10 @@ public abstract class
AbstractMaterializedViewAggregateRule extends AbstractMate
if (queryTopPlanFunctionSet.contains(topExpression)) {
Expression queryFunctionShuttled =
ExpressionUtils.shuttleExpressionWithLineage(
topExpression,
- queryTopPlan);
+ queryTopPlan,
+ queryStructInfo.getTableBitSet());
AggregateExpressionRewriteContext context = new
AggregateExpressionRewriteContext(
- false, mvExprToMvScanExprQueryBased, queryTopPlan);
+ false, mvExprToMvScanExprQueryBased, queryTopPlan,
queryStructInfo.getTableBitSet());
// queryFunctionShuttled maybe sum(column) + count(*), so need
to use expression rewriter
Expression rollupedExpression =
queryFunctionShuttled.accept(AGGREGATE_EXPRESSION_REWRITER,
context);
@@ -250,10 +261,10 @@ public abstract class
AbstractMaterializedViewAggregateRule extends AbstractMate
finalOutputExpressions.add(new Alias(rollupedExpression));
} else {
// if group by expression, try to rewrite group by expression
- Expression queryGroupShuttledExpr =
-
ExpressionUtils.shuttleExpressionWithLineage(topExpression, queryTopPlan);
- AggregateExpressionRewriteContext context = new
AggregateExpressionRewriteContext(
- true, mvExprToMvScanExprQueryBased, queryTopPlan);
+ Expression queryGroupShuttledExpr =
ExpressionUtils.shuttleExpressionWithLineage(
+ topExpression, queryTopPlan,
queryStructInfo.getTableBitSet());
+ AggregateExpressionRewriteContext context = new
AggregateExpressionRewriteContext(true,
+ mvExprToMvScanExprQueryBased, queryTopPlan,
queryStructInfo.getTableBitSet());
// group by expression maybe group by a + b, so we need
expression rewriter
Expression rewrittenGroupByExpression =
queryGroupShuttledExpr.accept(AGGREGATE_EXPRESSION_REWRITER,
context);
@@ -302,16 +313,18 @@ public abstract class
AbstractMaterializedViewAggregateRule extends AbstractMate
private boolean isGroupByEquals(Pair<Plan, LogicalAggregate<Plan>>
queryTopPlanAndAggPair,
Pair<Plan, LogicalAggregate<Plan>> viewTopPlanAndAggPair,
- SlotMapping viewToQuerySlotMapping) {
+ SlotMapping viewToQuerySlotMapping,
+ StructInfo queryStructInfo,
+ StructInfo viewStructInfo) {
Plan queryTopPlan = queryTopPlanAndAggPair.key();
Plan viewTopPlan = viewTopPlanAndAggPair.key();
LogicalAggregate<Plan> queryAggregate = queryTopPlanAndAggPair.value();
LogicalAggregate<Plan> viewAggregate = viewTopPlanAndAggPair.value();
Set<? extends Expression> queryGroupShuttledExpression = new HashSet<>(
ExpressionUtils.shuttleExpressionWithLineage(
- queryAggregate.getGroupByExpressions(), queryTopPlan));
+ queryAggregate.getGroupByExpressions(), queryTopPlan,
queryStructInfo.getTableBitSet()));
Set<? extends Expression> viewGroupShuttledExpressionQueryBased =
ExpressionUtils.shuttleExpressionWithLineage(
- viewAggregate.getGroupByExpressions(), viewTopPlan)
+ viewAggregate.getGroupByExpressions(), viewTopPlan,
viewStructInfo.getTableBitSet())
.stream()
.map(expr -> ExpressionUtils.replace(expr,
viewToQuerySlotMapping.toSlotReferenceMap()))
.collect(Collectors.toSet());
@@ -384,7 +397,7 @@ public abstract class AbstractMaterializedViewAggregateRule
extends AbstractMate
}
private Pair<Set<? extends Expression>, Set<? extends Expression>>
topPlanSplitToGroupAndFunction(
- Pair<Plan, LogicalAggregate<Plan>> topPlanAndAggPair) {
+ Pair<Plan, LogicalAggregate<Plan>> topPlanAndAggPair, StructInfo
queryStructInfo) {
LogicalAggregate<Plan> bottomQueryAggregate =
topPlanAndAggPair.value();
Set<Expression> groupByExpressionSet = new
HashSet<>(bottomQueryAggregate.getGroupByExpressions());
// when query is bitmap_count(bitmap_union), the plan is as following:
@@ -403,7 +416,7 @@ public abstract class AbstractMaterializedViewAggregateRule
extends AbstractMate
queryTopPlan.getOutput().forEach(expression -> {
ExpressionLineageReplacer.ExpressionReplaceContext replaceContext =
new
ExpressionLineageReplacer.ExpressionReplaceContext(ImmutableList.of(expression),
- ImmutableSet.of(), ImmutableSet.of());
+ ImmutableSet.of(), ImmutableSet.of(),
queryStructInfo.getTableBitSet());
queryTopPlan.accept(ExpressionLineageReplacer.INSTANCE,
replaceContext);
if (!Sets.intersection(bottomAggregateFunctionExprIdSet,
replaceContext.getExprIdExpressionMap().keySet()).isEmpty()) {
@@ -509,7 +522,8 @@ public abstract class AbstractMaterializedViewAggregateRule
extends AbstractMate
}
Expression queryFunctionShuttled =
ExpressionUtils.shuttleExpressionWithLineage(
aggregateFunction,
- rewriteContext.getQueryTopPlan());
+ rewriteContext.getQueryTopPlan(),
+ rewriteContext.getQueryTableBitSet());
Function rollupAggregateFunction = rollup(aggregateFunction,
queryFunctionShuttled,
rewriteContext.getMvExprToMvScanExprQueryBasedMapping());
if (rollupAggregateFunction == null) {
@@ -565,12 +579,15 @@ public abstract class
AbstractMaterializedViewAggregateRule extends AbstractMate
private final boolean onlyContainGroupByExpression;
private final Map<Expression, Expression>
mvExprToMvScanExprQueryBasedMapping;
private final Plan queryTopPlan;
+ private final BitSet queryTableBitSet;
public AggregateExpressionRewriteContext(boolean
onlyContainGroupByExpression,
- Map<Expression, Expression>
mvExprToMvScanExprQueryBasedMapping, Plan queryTopPlan) {
+ Map<Expression, Expression>
mvExprToMvScanExprQueryBasedMapping, Plan queryTopPlan,
+ BitSet queryTableBitSet) {
this.onlyContainGroupByExpression = onlyContainGroupByExpression;
this.mvExprToMvScanExprQueryBasedMapping =
mvExprToMvScanExprQueryBasedMapping;
this.queryTopPlan = queryTopPlan;
+ this.queryTableBitSet = queryTableBitSet;
}
public boolean isValid() {
@@ -592,5 +609,9 @@ public abstract class AbstractMaterializedViewAggregateRule
extends AbstractMate
public Plan getQueryTopPlan() {
return queryTopPlan;
}
+
+ public BitSet getQueryTableBitSet() {
+ return queryTableBitSet;
+ }
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
index df58345405a..2a05fecd33f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
@@ -44,10 +44,11 @@ public abstract class AbstractMaterializedViewJoinRule
extends AbstractMateriali
// Rewrite top projects, represent the query projects by view
List<Expression> expressionsRewritten = rewriteExpression(
queryStructInfo.getExpressions(),
- queryStructInfo.getOriginalPlan(),
+ queryStructInfo.getTopPlan(),
materializationContext.getMvExprToMvScanExprMapping(),
targetToSourceMapping,
- true
+ true,
+ queryStructInfo.getTableBitSet()
);
// Can not rewrite, bail out
if (expressionsRewritten.isEmpty()) {
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 90e0f8ed1db..b596408851f 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
@@ -38,6 +38,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Not;
import org.apache.doris.nereids.trees.expressions.Slot;
+import
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Nullable;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
@@ -57,6 +58,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -85,52 +87,62 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
*/
public List<Plan> rewrite(Plan queryPlan, CascadesContext cascadesContext)
{
List<Plan> rewrittenPlans = new ArrayList<>();
- // already rewrite or query is invalid, bail out
- List<StructInfo> queryStructInfos = checkQuery(queryPlan,
cascadesContext);
- if (queryStructInfos.isEmpty()) {
+ // if available materialization list is empty, bail out
+ if (cascadesContext.getMaterializationContexts().isEmpty()) {
return rewrittenPlans;
}
for (MaterializationContext context :
cascadesContext.getMaterializationContexts()) {
if (checkIfRewritten(queryPlan, context)) {
continue;
}
- // TODO Just support only one query struct info, support multi
later.
- StructInfo queryStructInfo = queryStructInfos.get(0);
- try {
- if (rewrittenPlans.size() < cascadesContext.getConnectContext()
-
.getSessionVariable().getMaterializedViewRewriteSuccessCandidateNum()) {
- rewrittenPlans.addAll(doRewrite(queryStructInfo,
cascadesContext, context));
+ context.tryReGenerateMvScanPlan(cascadesContext);
+ // check mv plan is valid or not
+ if (!checkPattern(context.getStructInfo())) {
+ context.recordFailReason(context.getStructInfo(),
+ "View struct info is invalid", () -> String.format(",
view plan is %s",
+
context.getStructInfo().getOriginalPlan().treeString()));
+ continue;
+ }
+ // get query struct infos according to the view strut info, if
valid query struct infos is empty, bail out
+ List<StructInfo> queryStructInfos =
getValidQueryStructInfos(queryPlan, cascadesContext,
+ context.getStructInfo().getTableBitSet());
+ if (queryStructInfos.isEmpty()) {
+ continue;
+ }
+ for (StructInfo queryStructInfo : queryStructInfos) {
+ try {
+ if (rewrittenPlans.size() <
cascadesContext.getConnectContext()
+
.getSessionVariable().getMaterializedViewRewriteSuccessCandidateNum()) {
+ rewrittenPlans.addAll(doRewrite(queryStructInfo,
cascadesContext, context));
+ }
+ } catch (Exception exception) {
+ context.recordFailReason(queryStructInfo,
+ "Materialized view rule exec fail",
exception::toString);
}
- } catch (Exception exception) {
- context.recordFailReason(queryStructInfo,
- "Materialized view rule exec fail",
exception::toString);
}
}
return rewrittenPlans;
}
/**
- * Check query is valid or not, if valid return the query struct infos, if
invalid return empty list.
+ * Get valid query struct infos, if invalid record the invalid reason
*/
- protected List<StructInfo> checkQuery(Plan queryPlan, CascadesContext
cascadesContext) {
- List<StructInfo> validQueryStructInfos = new ArrayList<>();
- List<MaterializationContext> materializationContexts =
cascadesContext.getMaterializationContexts();
- if (materializationContexts.isEmpty()) {
- return validQueryStructInfos;
- }
- List<StructInfo> queryStructInfos =
MaterializedViewUtils.extractStructInfo(queryPlan, cascadesContext);
- // TODO Just Check query queryPlan firstly, support multi later.
- StructInfo queryStructInfo = queryStructInfos.get(0);
- if (!checkPattern(queryStructInfo)) {
- for (MaterializationContext ctx :
cascadesContext.getMaterializationContexts()) {
- ctx.recordFailReason(queryStructInfo, "Query struct info is
invalid",
- () -> String.format("queryPlan is %s",
queryPlan.treeString())
- );
- }
- return validQueryStructInfos;
- }
- validQueryStructInfos.add(queryStructInfo);
- return validQueryStructInfos;
+ protected List<StructInfo> getValidQueryStructInfos(Plan queryPlan,
CascadesContext cascadesContext,
+ BitSet materializedViewTableSet) {
+ return MaterializedViewUtils.extractStructInfo(queryPlan,
cascadesContext, materializedViewTableSet)
+ .stream()
+ .filter(queryStructInfo -> {
+ boolean valid = checkPattern(queryStructInfo);
+ if (!valid) {
+
cascadesContext.getMaterializationContexts().forEach(ctx ->
+ ctx.recordFailReason(queryStructInfo, "Query
struct info is invalid",
+ () -> String.format("query table
bitmap is %s, plan is %s",
+
queryStructInfo.getTableBitSet(), queryPlan.treeString())
+ ));
+ }
+ return valid;
+ })
+ .collect(Collectors.toList());
}
/**
@@ -140,22 +152,7 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
protected List<Plan> doRewrite(StructInfo queryStructInfo, CascadesContext
cascadesContext,
MaterializationContext materializationContext) {
List<Plan> rewriteResults = new ArrayList<>();
- List<StructInfo> viewStructInfos =
MaterializedViewUtils.extractStructInfo(
- materializationContext.getMvPlan(), cascadesContext);
- if (viewStructInfos.size() > 1) {
- // view struct info should only have one
- materializationContext.recordFailReason(queryStructInfo,
- "The num of view struct info is more then one",
- () -> String.format("mv plan is %s",
materializationContext.getMvPlan().treeString()));
- return rewriteResults;
- }
- StructInfo viewStructInfo = viewStructInfos.get(0);
- if (!checkPattern(viewStructInfo)) {
- materializationContext.recordFailReason(queryStructInfo,
- "View struct info is invalid",
- () -> String.format(", view plan is %s",
viewStructInfo.getOriginalPlan().treeString()));
- return rewriteResults;
- }
+ StructInfo viewStructInfo = materializationContext.getStructInfo();
MatchMode matchMode = decideMatchMode(queryStructInfo.getRelations(),
viewStructInfo.getRelations());
if (MatchMode.COMPLETE != matchMode) {
materializationContext.recordFailReason(queryStructInfo, "Match
mode is invalid",
@@ -178,15 +175,6 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
continue;
}
SlotMapping viewToQuerySlotMapping =
queryToViewSlotMapping.inverse();
- // check the column used in query is in mv or not
- if (!checkColumnUsedValid(queryStructInfo, viewStructInfo,
queryToViewSlotMapping)) {
- materializationContext.recordFailReason(queryStructInfo,
- "The columns used by query are not in view",
- () -> String.format("query struct info is %s, view
struct info is %s",
- queryStructInfo.getTopPlan().treeString(),
- viewStructInfo.getTopPlan().treeString()));
- continue;
- }
LogicalCompatibilityContext compatibilityContext =
LogicalCompatibilityContext.from(
queryToViewTableMapping, queryToViewSlotMapping,
queryStructInfo, viewStructInfo);
ComparisonResult comparisonResult =
StructInfo.isGraphLogicalEquals(queryStructInfo, viewStructInfo,
@@ -212,14 +200,14 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
}
Plan rewrittenPlan;
Plan mvScan = materializationContext.getMvScanPlan();
- Plan originalPlan = queryStructInfo.getOriginalPlan();
+ Plan topPlan = queryStructInfo.getTopPlan();
if (compensatePredicates.isAlwaysTrue()) {
rewrittenPlan = mvScan;
} else {
// Try to rewrite compensate predicates by using mv scan
List<Expression> rewriteCompensatePredicates =
rewriteExpression(compensatePredicates.toList(),
- originalPlan,
materializationContext.getMvExprToMvScanExprMapping(),
- viewToQuerySlotMapping, true);
+ topPlan,
materializationContext.getMvExprToMvScanExprMapping(),
+ viewToQuerySlotMapping, true,
queryStructInfo.getTableBitSet());
if (rewriteCompensatePredicates.isEmpty()) {
materializationContext.recordFailReason(queryStructInfo,
"Rewrite compensate predicate by view fail",
@@ -237,13 +225,13 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
if (rewrittenPlan == null) {
continue;
}
- final Plan finalRewrittenPlan = rewriteByRules(cascadesContext,
rewrittenPlan, originalPlan);
- if (!isOutputValid(originalPlan, finalRewrittenPlan)) {
+ final Plan finalRewrittenPlan = rewriteByRules(cascadesContext,
rewrittenPlan, topPlan);
+ if (!isOutputValid(topPlan, finalRewrittenPlan)) {
materializationContext.recordFailReason(queryStructInfo,
"RewrittenPlan output logical properties is different
with target group",
() -> String.format("planOutput logical"
+ " properties = %s,\n groupOutput
logical properties = %s",
- finalRewrittenPlan.getLogicalProperties(),
originalPlan.getLogicalProperties()));
+ finalRewrittenPlan.getLogicalProperties(),
topPlan.getLogicalProperties()));
continue;
}
// check the partitions used by rewritten plan is valid or not
@@ -260,32 +248,12 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
.collect(Collectors.toSet())));
continue;
}
- recordIfRewritten(originalPlan, materializationContext);
+ recordIfRewritten(queryStructInfo.getOriginalPlan(),
materializationContext);
rewriteResults.add(finalRewrittenPlan);
}
return rewriteResults;
}
- /**
- * Check the column used by query is in materialized view output or not
- */
- protected boolean checkColumnUsedValid(StructInfo queryInfo, StructInfo
mvInfo,
- SlotMapping queryToViewSlotMapping) {
- Set<ExprId> queryUsedSlotSetViewBased =
ExpressionUtils.shuttleExpressionWithLineage(
- queryInfo.getTopPlan().getOutput(),
queryInfo.getTopPlan()).stream()
- .flatMap(expr -> ExpressionUtils.replace(expr,
queryToViewSlotMapping.toSlotReferenceMap())
- .collectToSet(each -> each instanceof Slot).stream())
- .map(each -> ((Slot) each).getExprId())
- .collect(Collectors.toSet());
-
- Set<ExprId> viewUsedSlotSet =
ExpressionUtils.shuttleExpressionWithLineage(mvInfo.getTopPlan().getOutput(),
- mvInfo.getTopPlan()).stream()
- .flatMap(expr -> expr.collectToSet(each -> each instanceof
Slot).stream())
- .map(each -> ((Slot) each).getExprId())
- .collect(Collectors.toSet());
- return viewUsedSlotSet.containsAll(queryUsedSlotSetViewBased);
- }
-
/**
* Rewrite by rules and try to make output is the same after optimize by
rules
*/
@@ -398,13 +366,13 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
*/
protected List<Expression> rewriteExpression(List<? extends Expression>
sourceExpressionsToWrite, Plan sourcePlan,
ExpressionMapping targetExpressionMapping, SlotMapping
targetToSourceMapping,
- boolean targetExpressionNeedSourceBased) {
+ boolean targetExpressionNeedSourceBased, BitSet sourcePlanBitSet) {
// Firstly, rewrite the target expression using source with inverse
mapping
// then try to use the target expression to represent the query. if
any of source expressions
// can not be represented by target expressions, return null.
// generate target to target replacement expression mapping, and
change target expression to source based
List<? extends Expression> sourceShuttledExpressions =
ExpressionUtils.shuttleExpressionWithLineage(
- sourceExpressionsToWrite, sourcePlan);
+ sourceExpressionsToWrite, sourcePlan, sourcePlanBitSet);
ExpressionMapping expressionMappingKeySourceBased =
targetExpressionNeedSourceBased
? targetExpressionMapping.keyPermute(targetToSourceMapping) :
targetExpressionMapping;
// target to target replacement expression mapping, because mv is 1:1
so get first element
@@ -516,6 +484,12 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
|| residualCompensatePredicates == null) {
return SplitPredicate.INVALID_INSTANCE;
}
+ if (equalCompensateConjunctions.stream().anyMatch(expr ->
expr.containsType(AggregateFunction.class))
+ || rangeCompensatePredicates.stream().anyMatch(expr ->
expr.containsType(AggregateFunction.class))
+ || residualCompensatePredicates.stream().anyMatch(expr ->
+ expr.containsType(AggregateFunction.class))) {
+ return SplitPredicate.INVALID_INSTANCE;
+ }
return SplitPredicate.of(equalCompensateConjunctions.isEmpty() ?
BooleanLiteral.TRUE
: ExpressionUtils.and(equalCompensateConjunctions),
rangeCompensatePredicates.isEmpty() ? BooleanLiteral.TRUE
@@ -592,7 +566,7 @@ public abstract class AbstractMaterializedViewRule
implements ExplorationRuleFac
protected void recordIfRewritten(Plan plan, MaterializationContext
context) {
context.setSuccess(true);
if (plan.getGroupExpression().isPresent()) {
-
context.addMatchedGroup(plan.getGroupExpression().get().getOwnerGroup().getGroupId());
+
context.addMatchedGroup(plan.getGroupExpression().get().getOwnerGroup().getGroupId(),
true);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/InitMaterializationContextHook.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/InitMaterializationContextHook.java
index 2d5c9bf377b..08c312b4737 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/InitMaterializationContextHook.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/InitMaterializationContextHook.java
@@ -24,23 +24,16 @@ import org.apache.doris.mtmv.BaseTableInfo;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.NereidsPlanner;
import org.apache.doris.nereids.PlannerHook;
-import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.PreAggStatus;
-import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.trees.plans.visitor.TableCollector;
import
org.apache.doris.nereids.trees.plans.visitor.TableCollector.TableCollectorContext;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -77,25 +70,15 @@ public class InitMaterializationContextHook implements
PlannerHook {
Set<MTMV> availableMTMVs =
Env.getCurrentEnv().getMtmvService().getRelationManager()
.getAvailableMTMVs(usedBaseTables,
cascadesContext.getConnectContext());
if (availableMTMVs.isEmpty()) {
+ LOG.warn(String.format("enable materialized view rewrite but
availableMTMVs is empty, current queryId "
+ + "is %s",
cascadesContext.getConnectContext().getQueryIdentifier()));
return;
}
for (MTMV materializedView : availableMTMVs) {
- // generate outside, maybe add partition filter in the future
- LogicalOlapScan mvScan = new LogicalOlapScan(
- cascadesContext.getStatementContext().getNextRelationId(),
- materializedView,
- ImmutableList.of(materializedView.getQualifiedDbName()),
- // this must be empty, or it will be used to sample
- Lists.newArrayList(),
- Lists.newArrayList(),
- Optional.empty());
- mvScan = mvScan.withMaterializedIndexSelected(PreAggStatus.on(),
materializedView.getBaseIndexId());
- List<NamedExpression> mvProjects =
mvScan.getOutput().stream().map(NamedExpression.class::cast)
- .collect(Collectors.toList());
- // todo should force keep consistency to mv sql plan output
- Plan projectScan = new LogicalProject<Plan>(mvProjects, mvScan);
cascadesContext.addMaterializationContext(
-
MaterializationContext.fromMaterializedView(materializedView, projectScan,
cascadesContext));
+
MaterializationContext.fromMaterializedView(materializedView,
+
MaterializedViewUtils.generateMvScanPlan(materializedView, cascadesContext),
+ cascadesContext));
}
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
index 3cd3000a670..7f92735da64 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
@@ -56,7 +56,7 @@ public class LogicalCompatibilityContext {
this.queryToViewNodeMapping = queryToViewNodeMapping;
this.queryToViewEdgeExpressionMapping =
queryToViewEdgeExpressionMapping;
this.queryToViewNodeIDMapping = HashBiMap.create();
- this.planNodeId =
queryStructInfo.getOriginalPlan().getGroupExpression()
+ this.planNodeId = queryStructInfo.getTopPlan().getGroupExpression()
.map(GroupExpression::getId).orElseGet(() -> new ObjectId(-1));
queryToViewNodeMapping.forEach((k, v) ->
queryToViewNodeIDMapping.put(k.getIndex(), v.getIndex()));
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializationContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializationContext.java
index db9f58ae070..1af63dab21f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializationContext.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializationContext.java
@@ -26,6 +26,7 @@ import org.apache.doris.mtmv.MTMVCache;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.memo.GroupId;
import org.apache.doris.nereids.rules.exploration.mv.mapping.ExpressionMapping;
+import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.ObjectId;
import org.apache.doris.nereids.trees.plans.Plan;
import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
@@ -37,6 +38,7 @@ import com.google.common.collect.ImmutableSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import java.util.BitSet;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -53,23 +55,27 @@ public class MaterializationContext {
private static final Logger LOG =
LogManager.getLogger(MaterializationContext.class);
private final MTMV mtmv;
- // Should use stmt id generator in query context
- private final Plan mvScanPlan;
private final List<Table> baseTables;
private final List<Table> baseViews;
// Group ids that are rewritten by this mv to reduce rewrite times
- private final Set<GroupId> matchedGroups = new HashSet<>();
- // generate form mv scan plan
+ private final Set<GroupId> matchedFailGroups = new HashSet<>();
+ private final Set<GroupId> matchedSuccessGroups = new HashSet<>();
+ // if rewrite by mv fail, record the reason, if success the failReason
should be empty.
+ // The key is the query belonged group expression objectId, the value is
the fail reason
+ private final Map<ObjectId, Pair<String, String>> failReason = new
LinkedHashMap<>();
+ // Should regenerate when materialization is already rewritten
successfully because one query may hit repeatedly
+ // make sure output is different in multi using
+ private Plan mvScanPlan;
+ // generated expressions form mv scan plan
private ExpressionMapping mvExprToMvScanExprMapping;
+ private List<? extends Expression> mvPlanOutputShuttledExpressions;
private boolean available = true;
// the mv plan from cache at present, record it to make sure query rewrite
by mv is right when cache change.
private Plan mvPlan;
// mark rewrite success or not
private boolean success = false;
- // if rewrite by mv fail, record the reason, if success the failReason
should be empty.
- // The key is the query belonged group expression objectId, the value is
the fail reason
- private final Map<ObjectId, Pair<String, String>> failReason = new
LinkedHashMap<>();
private boolean enableRecordFailureDetail = false;
+ private StructInfo structInfo;
/**
* MaterializationContext, this contains necessary info for query
rewriting by mv
@@ -93,22 +99,50 @@ public class MaterializationContext {
this.available = false;
return;
}
+ this.mvPlanOutputShuttledExpressions =
ExpressionUtils.shuttleExpressionWithLineage(
+ mtmvCache.getOriginalPlan().getOutput(),
+ mtmvCache.getOriginalPlan(),
+ new BitSet());
// mv output expression shuttle, this will be used to expression
rewrite
- this.mvExprToMvScanExprMapping = ExpressionMapping.generate(
- ExpressionUtils.shuttleExpressionWithLineage(
- mtmvCache.getOriginalPlan().getOutput(),
- mtmvCache.getOriginalPlan()),
- mvScanPlan.getExpressions());
+ this.mvExprToMvScanExprMapping =
ExpressionMapping.generate(this.mvPlanOutputShuttledExpressions,
+ this.mvScanPlan.getExpressions());
// copy the plan from cache, which the plan in cache may change
this.mvPlan = mtmvCache.getLogicalPlan();
+ List<StructInfo> viewStructInfos =
MaterializedViewUtils.extractStructInfo(
+ mtmvCache.getLogicalPlan(), cascadesContext, new BitSet());
+ if (viewStructInfos.size() > 1) {
+ // view struct info should only have one, log error and use the
first struct info
+ LOG.warn(String.format("view strut info is more than one, mv name
is %s, mv plan is %s",
+ mtmv.getName(), mvPlan.treeString()));
+ }
+ this.structInfo = viewStructInfos.get(0);
}
public boolean alreadyRewrite(GroupId groupId) {
- return this.matchedGroups.contains(groupId);
+ return this.matchedFailGroups.contains(groupId) ||
this.matchedSuccessGroups.contains(groupId);
}
- public void addMatchedGroup(GroupId groupId) {
- matchedGroups.add(groupId);
+ public void addMatchedGroup(GroupId groupId, boolean rewriteSuccess) {
+ if (rewriteSuccess) {
+ this.matchedSuccessGroups.add(groupId);
+ } else {
+ this.matchedFailGroups.add(groupId);
+ }
+ }
+
+ /**
+ * Try to generate scan plan for materialized view
+ * if MaterializationContext is already rewritten by materialized view,
then should generate in real time
+ * when query rewrite, because one plan may hit the materialized view
repeatedly and the mv scan output
+ * should be different
+ */
+ public void tryReGenerateMvScanPlan(CascadesContext cascadesContext) {
+ if (!this.matchedSuccessGroups.isEmpty()) {
+ this.mvScanPlan =
MaterializedViewUtils.generateMvScanPlan(this.mtmv, cascadesContext);
+ // mv output expression shuttle, this will be used to expression
rewrite
+ this.mvExprToMvScanExprMapping =
ExpressionMapping.generate(this.mvPlanOutputShuttledExpressions,
+ this.mvScanPlan.getExpressions());
+ }
}
public MTMV getMTMV() {
@@ -152,13 +186,18 @@ public class MaterializationContext {
this.failReason.clear();
}
+ public StructInfo getStructInfo() {
+ return structInfo;
+ }
+
/**
* recordFailReason
*/
public void recordFailReason(StructInfo structInfo, String summary,
Supplier<String> failureReasonSupplier) {
// record it's rewritten
if (structInfo.getTopPlan().getGroupExpression().isPresent()) {
-
this.addMatchedGroup(structInfo.getTopPlan().getGroupExpression().get().getOwnerGroup().getGroupId());
+
this.addMatchedGroup(structInfo.getTopPlan().getGroupExpression().get().getOwnerGroup().getGroupId(),
+ false);
}
// once success, do not record the fail reason
if (this.success) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateRule.java
index 8e0f8d6f717..20a7965f08b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateRule.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import com.google.common.collect.ImmutableList;
@@ -36,7 +37,7 @@ public class MaterializedViewAggregateRule extends
AbstractMaterializedViewAggre
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
- logicalAggregate(any()).thenApplyMultiNoThrow(ctx -> {
+
logicalAggregate(any().when(LogicalPlan.class::isInstance)).thenApplyMultiNoThrow(ctx
-> {
LogicalAggregate<Plan> root = ctx.root;
return rewrite(root, ctx.cascadesContext);
}).toRule(RuleType.MATERIALIZED_VIEW_ONLY_AGGREGATE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterAggregateRule.java
index 40c8b6d681b..10b7aa5e84d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterAggregateRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import com.google.common.collect.ImmutableList;
@@ -37,9 +38,10 @@ public class MaterializedViewFilterAggregateRule extends
AbstractMaterializedVie
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
-
logicalFilter(logicalAggregate(any())).thenApplyMultiNoThrow(ctx -> {
- LogicalFilter<LogicalAggregate<Plan>> root = ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
+
logicalFilter(logicalAggregate(any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(
+ ctx -> {
+ LogicalFilter<LogicalAggregate<Plan>> root =
ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterJoinRule.java
index d1ffa522bb0..e7b12e6bb1f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterJoinRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import com.google.common.collect.ImmutableList;
@@ -36,8 +37,8 @@ public class MaterializedViewFilterJoinRule extends
AbstractMaterializedViewJoin
@Override
public List<Rule> buildRules() {
- return ImmutableList.of(
- logicalFilter(logicalJoin(any(),
any())).thenApplyMultiNoThrow(ctx -> {
+ return
ImmutableList.of(logicalFilter(logicalJoin(any().when(LogicalPlan.class::isInstance),
+
any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(ctx -> {
LogicalFilter<LogicalJoin<Plan, Plan>> root = ctx.root;
return rewrite(root, ctx.cascadesContext);
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_JOIN));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
index 40655e97394..bd7437a7d90 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -39,9 +40,10 @@ public class MaterializedViewFilterProjectAggregateRule
extends AbstractMaterial
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
-
logicalFilter(logicalProject(logicalAggregate(any()))).thenApplyMultiNoThrow(ctx
-> {
- LogicalFilter<LogicalProject<LogicalAggregate<Plan>>> root
= ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
+
logicalFilter(logicalProject(logicalAggregate(any().when(LogicalPlan.class::isInstance))))
+ .thenApplyMultiNoThrow(ctx -> {
+
LogicalFilter<LogicalProject<LogicalAggregate<Plan>>> root = ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectJoinRule.java
index 2c9cca199de..c18347dce08 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectJoinRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -38,9 +39,10 @@ public class MaterializedViewFilterProjectJoinRule extends
AbstractMaterializedV
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
- logicalFilter(logicalProject(logicalJoin(any(),
any()))).thenApplyMultiNoThrow(ctx -> {
- LogicalFilter<LogicalProject<LogicalJoin<Plan, Plan>>>
root = ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_JOIN));
+
logicalFilter(logicalProject(logicalJoin(any().when(LogicalPlan.class::isInstance),
+
any().when(LogicalPlan.class::isInstance)))).thenApplyMultiNoThrow(ctx -> {
+ LogicalFilter<LogicalProject<LogicalJoin<Plan,
Plan>>> root = ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_JOIN));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewOnlyJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewOnlyJoinRule.java
index a9f8333f4df..2735ca87fe9 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewOnlyJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewOnlyJoinRule.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
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.LogicalPlan;
import com.google.common.collect.ImmutableList;
@@ -35,8 +36,8 @@ public class MaterializedViewOnlyJoinRule extends
AbstractMaterializedViewJoinRu
@Override
public List<Rule> buildRules() {
- return ImmutableList.of(
- logicalJoin(any(), any()).thenApplyMultiNoThrow(ctx -> {
+ return
ImmutableList.of(logicalJoin(any().when(LogicalPlan.class::isInstance),
+
any().when(LogicalPlan.class::isInstance)).thenApplyMultiNoThrow(ctx -> {
LogicalJoin<Plan, Plan> root = ctx.root;
return rewrite(root, ctx.cascadesContext);
}).toRule(RuleType.MATERIALIZED_VIEW_ONLY_JOIN));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectAggregateRule.java
index 106de2a7f9c..d857d4eab0b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectAggregateRule.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -35,9 +36,10 @@ public class MaterializedViewProjectAggregateRule extends
AbstractMaterializedVi
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
-
logicalProject(logicalAggregate(any())).thenApplyMultiNoThrow(ctx -> {
- LogicalProject<LogicalAggregate<Plan>> root = ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_AGGREGATE));
+
logicalProject(logicalAggregate(any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(
+ ctx -> {
+ LogicalProject<LogicalAggregate<Plan>> root =
ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+
}).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_AGGREGATE));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
index b841862d5b2..906ca31b4c2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -38,8 +39,8 @@ public class MaterializedViewProjectFilterAggregateRule
extends AbstractMaterial
@Override
public List<Rule> buildRules() {
- return ImmutableList.of(
-
logicalProject(logicalFilter(logicalAggregate(any()))).thenApplyMultiNoThrow(ctx
-> {
+ return ImmutableList.of(logicalProject(logicalFilter(logicalAggregate(
+
any().when(LogicalPlan.class::isInstance)))).thenApplyMultiNoThrow(ctx -> {
LogicalProject<LogicalFilter<LogicalAggregate<Plan>>> root
= ctx.root;
return rewrite(root, ctx.cascadesContext);
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterJoinRule.java
index e97a5378b83..d82f838ea6b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterJoinRule.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -38,9 +39,10 @@ public class MaterializedViewProjectFilterJoinRule extends
AbstractMaterializedV
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
- logicalProject(logicalFilter(logicalJoin(any(),
any()))).thenApplyMultiNoThrow(ctx -> {
- LogicalProject<LogicalFilter<LogicalJoin<Plan, Plan>>>
root = ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_JOIN));
+
logicalProject(logicalFilter(logicalJoin(any().when(LogicalPlan.class::isInstance),
+
any().when(LogicalPlan.class::isInstance)))).thenApplyMultiNoThrow(ctx -> {
+ LogicalProject<LogicalFilter<LogicalJoin<Plan,
Plan>>> root = ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+
}).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_JOIN));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectJoinRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectJoinRule.java
index c9e309c0096..bbeda87191a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectJoinRule.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectJoinRule.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
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.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import com.google.common.collect.ImmutableList;
@@ -37,9 +38,10 @@ public class MaterializedViewProjectJoinRule extends
AbstractMaterializedViewJoi
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
- logicalProject(logicalJoin(any(),
any())).thenApplyMultiNoThrow(ctx -> {
- LogicalProject<LogicalJoin<Plan, Plan>> root = ctx.root;
- return rewrite(root, ctx.cascadesContext);
- }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_JOIN));
+
logicalProject(logicalJoin(any().when(LogicalPlan.class::isInstance),
+
any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(ctx -> {
+ LogicalProject<LogicalJoin<Plan, Plan>> root =
ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+ }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_JOIN));
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
index ce12e059b77..ac4b9ccad38 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java
@@ -18,12 +18,15 @@
package org.apache.doris.nereids.rules.exploration.mv;
import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.MTMV;
import org.apache.doris.catalog.PartitionType;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.common.Pair;
import org.apache.doris.mtmv.BaseTableInfo;
import org.apache.doris.mtmv.MTMVRelatedTableIf;
import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.StructInfoMap;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
@@ -31,6 +34,7 @@ import
org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.WindowExpression;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.PreAggStatus;
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.LogicalFileScan;
@@ -44,9 +48,12 @@ import
org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -132,18 +139,46 @@ public class MaterializedViewUtils {
/**
* Extract struct info from plan, support to get struct info from logical
plan or plan in group.
*/
- public static List<StructInfo> extractStructInfo(Plan plan,
CascadesContext cascadesContext) {
- if (plan.getGroupExpression().isPresent() &&
!plan.getGroupExpression().get().getOwnerGroup().getStructInfos()
- .isEmpty()) {
- return
plan.getGroupExpression().get().getOwnerGroup().getStructInfos();
- } else {
- // build struct info and add them to current group
- List<StructInfo> structInfos = StructInfo.of(plan);
- if (plan.getGroupExpression().isPresent()) {
-
plan.getGroupExpression().get().getOwnerGroup().addStructInfo(structInfos);
+ public static List<StructInfo> extractStructInfo(Plan plan,
CascadesContext cascadesContext,
+ BitSet materializedViewTableSet) {
+ // If plan belong to some group, construct it with group struct info
+ if (plan.getGroupExpression().isPresent()) {
+ Group ownerGroup = plan.getGroupExpression().get().getOwnerGroup();
+ StructInfoMap structInfoMap = ownerGroup.getstructInfoMap();
+ structInfoMap.refresh(ownerGroup);
+ Set<BitSet> queryTableSets = structInfoMap.getTableMaps();
+ if (!queryTableSets.isEmpty()) {
+ return queryTableSets.stream()
+ // Just construct the struct info which mv table set
contains all the query table set
+ .filter(queryTableSet ->
materializedViewTableSet.isEmpty()
+ ||
StructInfo.containsAll(materializedViewTableSet, queryTableSet))
+ .map(tableMap -> structInfoMap.getStructInfo(tableMap,
tableMap, ownerGroup, plan))
+ .collect(Collectors.toList());
}
- return structInfos;
}
+ // if plan doesn't belong to any group, construct it directly
+ return ImmutableList.of(StructInfo.of(plan));
+ }
+
+ /**
+ * Generate scan plan for materialized view
+ * if MaterializationContext is already rewritten by materialized view,
then should generate in real time
+ * when query rewrite, because one plan may hit the materialized view
repeatedly and the mv scan output
+ * should be different
+ */
+ public static Plan generateMvScanPlan(MTMV materializedView,
CascadesContext cascadesContext) {
+ LogicalOlapScan mvScan = new LogicalOlapScan(
+ cascadesContext.getStatementContext().getNextRelationId(),
+ materializedView,
+ ImmutableList.of(materializedView.getQualifiedDbName()),
+ // this must be empty, or it will be used to sample
+ Lists.newArrayList(),
+ Lists.newArrayList(),
+ Optional.empty());
+ mvScan = mvScan.withMaterializedIndexSelected(PreAggStatus.on(),
materializedView.getBaseIndexId());
+ List<NamedExpression> mvProjects =
mvScan.getOutput().stream().map(NamedExpression.class::cast)
+ .collect(Collectors.toList());
+ return new LogicalProject<Plan>(mvProjects, mvScan);
}
private static final class TableQueryOperatorChecker extends
DefaultPlanVisitor<Boolean, Void> {
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 0d280bb8340..604e7853d48 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
@@ -47,12 +47,12 @@ import
org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
import org.apache.doris.nereids.trees.plans.visitor.ExpressionLineageReplacer;
import org.apache.doris.nereids.util.ExpressionUtils;
-import com.google.common.collect.ImmutableList;
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.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -83,6 +83,7 @@ public class StructInfo {
// bottom plan which top plan only contain join or scan. this is needed by
hyper graph
private final Plan bottomPlan;
private final List<CatalogRelation> relations;
+ private final BitSet tableBitSet = new BitSet();
// this is for LogicalCompatibilityContext later
private final Map<RelationId, StructInfoNode> relationIdStructInfoNodeMap;
// this recorde the predicates which can pull up, not shuttled
@@ -112,6 +113,7 @@ public class StructInfo {
this.topPlan = topPlan;
this.bottomPlan = bottomPlan;
this.relations = relations;
+ relations.forEach(relation -> this.tableBitSet.set((int)
(relation.getTable().getId())));
this.relationIdStructInfoNodeMap = relationIdStructInfoNodeMap;
this.predicates = predicates;
if (predicates == null) {
@@ -120,7 +122,8 @@ public class StructInfo {
topPlan.accept(PREDICATE_COLLECTOR, topPlanPredicates);
this.predicates = Predicates.of(topPlanPredicates);
}
- Pair<SplitPredicate, EquivalenceClass> derivedPredicates =
predicatesDerive(this.predicates, originalPlan);
+ Pair<SplitPredicate, EquivalenceClass> derivedPredicates =
+ predicatesDerive(this.predicates, topPlan, tableBitSet);
this.splitPredicate = derivedPredicates.key();
this.equivalenceClass = derivedPredicates.value();
this.shuttledHashConjunctsToConjunctsMap =
shuttledHashConjunctsToConjunctsMap;
@@ -140,8 +143,24 @@ public class StructInfo {
Plan topPlan,
Map<Expression, Expression> shuttledHashConjunctsToConjunctsMap,
Map<ExprId, Expression> namedExprIdAndExprMapping,
- ImmutableList.Builder<CatalogRelation> relationBuilder,
+ List<CatalogRelation> relations,
Map<RelationId, StructInfoNode> relationIdStructInfoNodeMap) {
+
+ // Collect relations from hyper graph which in the bottom plan firstly
+ BitSet hyperTableBitSet = new BitSet();
+ hyperGraph.getNodes().forEach(node -> {
+ // plan relation collector and set to map
+ Plan nodePlan = node.getPlan();
+ List<CatalogRelation> nodeRelations = new ArrayList<>();
+ nodePlan.accept(RELATION_COLLECTOR, nodeRelations);
+ relations.addAll(nodeRelations);
+ nodeRelations.forEach(relation -> hyperTableBitSet.set((int)
relation.getTable().getId()));
+ // every node should only have one relation, this is for
LogicalCompatibilityContext
+ if (!nodeRelations.isEmpty()) {
+
relationIdStructInfoNodeMap.put(nodeRelations.get(0).getRelationId(),
(StructInfoNode) node);
+ }
+ });
+
// Collect expression from join condition in hyper graph
for (JoinEdge edge : hyperGraph.getJoinEdges()) {
List<Expression> hashJoinConjuncts = edge.getHashJoinConjuncts();
@@ -151,9 +170,8 @@ public class StructInfo {
hashJoinConjuncts.forEach(conjunctExpr -> {
ExpressionLineageReplacer.ExpressionReplaceContext
replaceContext =
new ExpressionLineageReplacer.ExpressionReplaceContext(
- Lists.newArrayList(conjunctExpr),
- ImmutableSet.of(),
- ImmutableSet.of());
+ Lists.newArrayList(conjunctExpr),
ImmutableSet.of(),
+ ImmutableSet.of(), hyperTableBitSet);
topPlan.accept(ExpressionLineageReplacer.INSTANCE,
replaceContext);
// Replace expressions by expression map
List<Expression> replacedExpressions =
replaceContext.getReplacedExpressions();
@@ -167,27 +185,17 @@ public class StructInfo {
return false;
}
}
- // Collect relations from hyper graph which in the bottom plan
+ // Record expressions in node
hyperGraph.getNodes().forEach(node -> {
// plan relation collector and set to map
StructInfoNode structInfoNode = (StructInfoNode) node;
- // plan relation collector and set to map
- Plan nodePlan = node.getPlan();
- List<CatalogRelation> nodeRelations = new ArrayList<>();
- nodePlan.accept(RELATION_COLLECTOR, nodeRelations);
- relationBuilder.addAll(nodeRelations);
- // every node should only have one relation, this is for
LogicalCompatibilityContext
- if (!nodeRelations.isEmpty()) {
-
relationIdStructInfoNodeMap.put(nodeRelations.get(0).getRelationId(),
(StructInfoNode) node);
- }
// record expressions in node
if (structInfoNode.getExpressions() != null) {
structInfoNode.getExpressions().forEach(expression -> {
ExpressionLineageReplacer.ExpressionReplaceContext
replaceContext =
new
ExpressionLineageReplacer.ExpressionReplaceContext(
- Lists.newArrayList(expression),
- ImmutableSet.of(),
- ImmutableSet.of());
+ Lists.newArrayList(expression),
ImmutableSet.of(),
+ ImmutableSet.of(), hyperTableBitSet);
structInfoNode.getPlan().accept(ExpressionLineageReplacer.INSTANCE,
replaceContext);
// Replace expressions by expression map
List<Expression> replacedExpressions =
replaceContext.getReplacedExpressions();
@@ -204,18 +212,19 @@ public class StructInfo {
filterExpressions.forEach(predicate -> {
// this is used for LogicalCompatibilityContext
ExpressionUtils.extractConjunction(predicate).forEach(expr ->
- shuttledHashConjunctsToConjunctsMap.put(
-
ExpressionUtils.shuttleExpressionWithLineage(predicate, topPlan), predicate));
+
shuttledHashConjunctsToConjunctsMap.put(ExpressionUtils.shuttleExpressionWithLineage(
+ predicate, topPlan, hyperTableBitSet),
predicate));
});
});
return true;
}
// derive some useful predicate by predicates
- private Pair<SplitPredicate, EquivalenceClass> predicatesDerive(Predicates
predicates, Plan originalPlan) {
+ private Pair<SplitPredicate, EquivalenceClass> predicatesDerive(Predicates
predicates, Plan originalPlan,
+ BitSet tableBitSet) {
// construct equivalenceClass according to equals predicates
List<Expression> shuttledExpression =
ExpressionUtils.shuttleExpressionWithLineage(
- new ArrayList<>(predicates.getPulledUpPredicates()),
originalPlan).stream()
+ new ArrayList<>(predicates.getPulledUpPredicates()),
originalPlan, tableBitSet).stream()
.map(Expression.class::cast)
.collect(Collectors.toList());
SplitPredicate splitPredicate =
Predicates.splitPredicates(ExpressionUtils.and(shuttledExpression));
@@ -238,20 +247,23 @@ public class StructInfo {
* Build Struct info from plan.
* Maybe return multi structInfo when original plan already be rewritten
by mv
*/
- public static List<StructInfo> of(Plan originalPlan) {
- // TODO only consider the inner join currently, Should support outer
join
+ public static StructInfo of(Plan originalPlan) {
+ return of(originalPlan, originalPlan);
+ }
+
+ /**
+ * Build Struct info from plan.
+ * Maybe return multi structInfo when original plan already be rewritten
by mv
+ */
+ public static StructInfo of(Plan derivedPlan, Plan originalPlan) {
// Split plan by the boundary which contains multi child
LinkedHashSet<Class<? extends Plan>> set = Sets.newLinkedHashSet();
set.add(LogicalJoin.class);
PlanSplitContext planSplitContext = new PlanSplitContext(set);
// if single table without join, the bottom is
- originalPlan.accept(PLAN_SPLITTER, planSplitContext);
-
- List<HyperGraph> structInfos =
HyperGraph.builderForMv(planSplitContext.getBottomPlan()).buildAll();
- return structInfos.stream()
- .map(hyperGraph -> StructInfo.of(originalPlan,
planSplitContext.getTopPlan(),
- planSplitContext.getBottomPlan(), hyperGraph))
- .collect(Collectors.toList());
+ derivedPlan.accept(PLAN_SPLITTER, planSplitContext);
+ return StructInfo.of(originalPlan, planSplitContext.getTopPlan(),
planSplitContext.getBottomPlan(),
+
HyperGraph.builderForMv(planSplitContext.getBottomPlan()).build());
}
/**
@@ -271,16 +283,16 @@ public class StructInfo {
topPlan = planSplitContext.getTopPlan();
}
// collect struct info fromGraph
- ImmutableList.Builder<CatalogRelation> relationBuilder =
ImmutableList.builder();
+ List<CatalogRelation> relationList = new ArrayList<>();
Map<RelationId, StructInfoNode> relationIdStructInfoNodeMap = new
LinkedHashMap<>();
Map<Expression, Expression> shuttledHashConjunctsToConjunctsMap = new
LinkedHashMap<>();
Map<ExprId, Expression> namedExprIdAndExprMapping = new
LinkedHashMap<>();
boolean valid = collectStructInfoFromGraph(hyperGraph, topPlan,
shuttledHashConjunctsToConjunctsMap,
namedExprIdAndExprMapping,
- relationBuilder,
+ relationList,
relationIdStructInfoNodeMap);
return new StructInfo(originalPlan, originalPlanId, hyperGraph, valid,
topPlan, bottomPlan,
- relationBuilder.build(), relationIdStructInfoNodeMap, null,
shuttledHashConjunctsToConjunctsMap,
+ relationList, relationIdStructInfoNodeMap, null,
shuttledHashConjunctsToConjunctsMap,
namedExprIdAndExprMapping);
}
@@ -338,8 +350,8 @@ public class StructInfo {
}
public List<? extends Expression> getExpressions() {
- return originalPlan instanceof LogicalProject
- ? ((LogicalProject<Plan>) originalPlan).getProjects() :
originalPlan.getOutput();
+ return topPlan instanceof LogicalProject
+ ? ((LogicalProject<Plan>) topPlan).getProjects() :
topPlan.getOutput();
}
public ObjectId getOriginalPlanId() {
@@ -350,6 +362,10 @@ public class StructInfo {
return namedExprIdAndExprMapping;
}
+ public BitSet getTableBitSet() {
+ return tableBitSet;
+ }
+
/**
* Judge the source graph logical is whether the same as target
* For inner join should judge only the join tables,
@@ -361,6 +377,11 @@ public class StructInfo {
.isLogicCompatible(queryStructInfo.hyperGraph,
viewStructInfo.hyperGraph, compatibilityContext);
}
+ @Override
+ public String toString() {
+ return "StructInfo{ originalPlanId = " + originalPlanId + ", relations
= " + relations + '}';
+ }
+
private static class RelationCollector extends DefaultPlanVisitor<Void,
List<CatalogRelation>> {
@Override
public Void visit(Plan plan, List<CatalogRelation> collectedRelations)
{
@@ -409,6 +430,12 @@ public class StructInfo {
}
}
+ public static boolean containsAll(BitSet source, BitSet target) {
+ BitSet intersection = (BitSet) source.clone();
+ intersection.and(target);
+ return intersection.equals(target);
+ }
+
/**
* Plan split context, this hold bottom and top plan, and boundary plan
setting
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/ExpressionLineageReplacer.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/ExpressionLineageReplacer.java
index b7cc0dff80b..2060718ec13 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/ExpressionLineageReplacer.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/ExpressionLineageReplacer.java
@@ -32,9 +32,11 @@ import org.apache.doris.nereids.trees.plans.Plan;
import
org.apache.doris.nereids.trees.plans.visitor.ExpressionLineageReplacer.ExpressionReplaceContext;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -43,12 +45,12 @@ import java.util.stream.Collectors;
* Get from rewrite plan and can also get from plan struct info, if from plan
struct info it depends on
* the nodes from graph.
*/
-public class ExpressionLineageReplacer extends DefaultPlanVisitor<Expression,
ExpressionReplaceContext> {
+public class ExpressionLineageReplacer extends DefaultPlanVisitor<Void,
ExpressionReplaceContext> {
public static final ExpressionLineageReplacer INSTANCE = new
ExpressionLineageReplacer();
@Override
- public Expression visit(Plan plan, ExpressionReplaceContext context) {
+ public Void visit(Plan plan, ExpressionReplaceContext context) {
List<? extends Expression> expressions = plan.getExpressions();
Map<ExprId, Expression> targetExpressionMap =
context.getExprIdExpressionMap();
// Filter the namedExpression used by target and collect the
namedExpression
@@ -60,19 +62,27 @@ public class ExpressionLineageReplacer extends
DefaultPlanVisitor<Expression, Ex
}
@Override
- public Expression visitGroupPlan(GroupPlan groupPlan,
ExpressionReplaceContext context) {
+ public Void visitGroupPlan(GroupPlan groupPlan, ExpressionReplaceContext
context) {
Group group = groupPlan.getGroup();
if (group == null) {
return visit(groupPlan, context);
}
- List<StructInfo> structInfos = group.getStructInfos();
+ Collection<StructInfo> structInfos =
group.getstructInfoMap().getStructInfos();
if (structInfos.isEmpty()) {
return visit(groupPlan, context);
}
- // TODO only support group has one struct info, will support more
struct info later
- StructInfo structInfo = structInfos.get(0);
-
context.getExprIdExpressionMap().putAll(structInfo.getNamedExprIdAndExprMapping());
- return visit(groupPlan, context);
+ // Find first info which the context's bitmap contains all to make
sure that
+ // the expression lineage is correct
+ Optional<StructInfo> structInfoOptional = structInfos.stream()
+ .filter(info -> (context.getTableBitSet().isEmpty()
+ || StructInfo.containsAll(context.getTableBitSet(),
info.getTableBitSet()))
+ && !info.getNamedExprIdAndExprMapping().isEmpty())
+ .findFirst();
+ if (!structInfoOptional.isPresent()) {
+ return visit(groupPlan, context);
+ }
+
context.getExprIdExpressionMap().putAll(structInfoOptional.get().getNamedExprIdAndExprMapping());
+ return null;
}
/**
@@ -144,7 +154,8 @@ public class ExpressionLineageReplacer extends
DefaultPlanVisitor<Expression, Ex
private final List<Expression> targetExpressions;
private final Set<TableType> targetTypes;
private final Set<String> tableIdentifiers;
- private Map<ExprId, Expression> exprIdExpressionMap;
+ private final Map<ExprId, Expression> exprIdExpressionMap;
+ private final BitSet tableBitSet;
private List<Expression> replacedExpressions;
/**
@@ -152,10 +163,12 @@ public class ExpressionLineageReplacer extends
DefaultPlanVisitor<Expression, Ex
*/
public ExpressionReplaceContext(List<Expression> targetExpressions,
Set<TableType> targetTypes,
- Set<String> tableIdentifiers) {
+ Set<String> tableIdentifiers,
+ BitSet tableBitSet) {
this.targetExpressions = targetExpressions;
this.targetTypes = targetTypes;
this.tableIdentifiers = tableIdentifiers;
+ this.tableBitSet = tableBitSet;
// collect the named expressions used in target expression and
will be replaced later
this.exprIdExpressionMap = targetExpressions.stream()
.map(each ->
each.collectToList(NamedExpression.class::isInstance))
@@ -181,6 +194,10 @@ public class ExpressionLineageReplacer extends
DefaultPlanVisitor<Expression, Ex
return exprIdExpressionMap;
}
+ public BitSet getTableBitSet() {
+ return tableBitSet;
+ }
+
/**
* getReplacedExpressions
*/
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 e5e79f7b725..51eef31de2f 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
@@ -65,6 +65,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -225,14 +226,14 @@ public class ExpressionUtils {
return result;
}
- public static Expression shuttleExpressionWithLineage(Expression
expression, Plan plan) {
+ public static Expression shuttleExpressionWithLineage(Expression
expression, Plan plan, BitSet tableBitSet) {
return shuttleExpressionWithLineage(Lists.newArrayList(expression),
- plan, ImmutableSet.of(), ImmutableSet.of()).get(0);
+ plan, ImmutableSet.of(), ImmutableSet.of(),
tableBitSet).get(0);
}
public static List<? extends Expression>
shuttleExpressionWithLineage(List<? extends Expression> expressions,
- Plan plan) {
- return shuttleExpressionWithLineage(expressions, plan,
ImmutableSet.of(), ImmutableSet.of());
+ Plan plan, BitSet tableBitSet) {
+ return shuttleExpressionWithLineage(expressions, plan,
ImmutableSet.of(), ImmutableSet.of(), tableBitSet);
}
/**
@@ -247,7 +248,8 @@ public class ExpressionUtils {
public static List<? extends Expression>
shuttleExpressionWithLineage(List<? extends Expression> expressions,
Plan plan,
Set<TableType> targetTypes,
- Set<String> tableIdentifiers) {
+ Set<String> tableIdentifiers,
+ BitSet tableBitSet) {
if (expressions.isEmpty()) {
return ImmutableList.of();
}
@@ -255,7 +257,8 @@ public class ExpressionUtils {
new ExpressionLineageReplacer.ExpressionReplaceContext(
expressions.stream().map(Expression.class::cast).collect(Collectors.toList()),
targetTypes,
- tableIdentifiers);
+ tableIdentifiers,
+ tableBitSet);
plan.accept(ExpressionLineageReplacer.INSTANCE, replaceContext);
// Replace expressions by expression map
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 afdce7ca08d..9ebb04e6ba3 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
@@ -37,6 +37,7 @@ import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
import java.util.List;
class CompareOuterJoinTest extends SqlTestBase {
@@ -63,8 +64,8 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
Assertions.assertFalse(
HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2)).isInvalid());
}
@@ -82,8 +83,8 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
Assertions.assertFalse(
HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2)).isInvalid());
}
@@ -108,8 +109,8 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(1, res.getQueryExpressions().size());
Assertions.assertEquals("(id = 0)",
res.getQueryExpressions().get(0).toSql());
@@ -135,8 +136,8 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
List<Expression> exprList = HyperGraphComparator.isLogicCompatible(h1,
h2, constructContext(p1, p2)).getQueryExpressions();
Assertions.assertEquals(0, exprList.size());
}
@@ -162,8 +163,8 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(1, res.getQueryExpressions().size());
Assertions.assertEquals("(id = 0)",
res.getQueryExpressions().get(0).toSql());
@@ -190,17 +191,17 @@ class CompareOuterJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(res.isInvalid());
}
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferJoinTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferJoinTest.java
index 05f56c4de20..d61224c1433 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferJoinTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferJoinTest.java
@@ -35,6 +35,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
import java.util.stream.Collectors;
class InferJoinTest extends SqlTestBase {
@@ -58,8 +59,8 @@ class InferJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertFalse(res.isInvalid());
Assertions.assertEquals(1, res.getViewNoNullableSlot().size());
@@ -87,8 +88,8 @@ class InferJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertFalse(res.isInvalid());
Assertions.assertEquals(1, res.getViewNoNullableSlot().size());
@@ -124,8 +125,8 @@ class InferJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertFalse(res.isInvalid());
Assertions.assertEquals(1, res.getViewNoNullableSlot().size());
@@ -155,17 +156,17 @@ class InferJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(res.isInvalid());
}
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferPredicateTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferPredicateTest.java
index 8bb1ede8048..fe705fda72c 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferPredicateTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/InferPredicateTest.java
@@ -33,6 +33,8 @@ import org.apache.doris.nereids.util.PlanChecker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
+
class InferPredicateTest extends SqlTestBase {
@Test
void testPullUpQueryFilter() {
@@ -53,8 +55,8 @@ class InferPredicateTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertFalse(res.isInvalid());
Assertions.assertEquals("(id = 1)",
res.getQueryExpressions().get(0).toSql());
@@ -62,9 +64,9 @@ class InferPredicateTest extends SqlTestBase {
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java
index 6e65dba4f03..b564f166ed5 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/PullupExpressionTest.java
@@ -33,6 +33,8 @@ import org.apache.doris.nereids.util.PlanChecker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
+
class PullupExpressionTest extends SqlTestBase {
@Test
void testPullUpQueryFilter() {
@@ -53,8 +55,8 @@ class PullupExpressionTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(1, res.getQueryExpressions().size());
Assertions.assertEquals("(id = 1)",
res.getQueryExpressions().get(0).toSql());
@@ -79,8 +81,8 @@ class PullupExpressionTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(1, res.getQueryExpressions().size());
Assertions.assertEquals("(score = score)",
res.getQueryExpressions().get(0).toSql());
@@ -105,8 +107,8 @@ class PullupExpressionTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(2, res.getViewExpressions().size());
Assertions.assertEquals("(id = 1)",
res.getViewExpressions().get(0).toSql());
@@ -132,8 +134,8 @@ class PullupExpressionTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertEquals(1, res.getViewExpressions().size());
Assertions.assertEquals("(score = score)",
res.getViewExpressions().get(0).toSql());
@@ -141,9 +143,9 @@ class PullupExpressionTest extends SqlTestBase {
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/StructInfoMapTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/StructInfoMapTest.java
index c2d9d072ac3..13bdf35252e 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/StructInfoMapTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/StructInfoMapTest.java
@@ -172,7 +172,7 @@ class StructInfoMapTest extends SqlTestBase {
BitSet mvMap = structInfoMap.getTableMaps().stream()
.filter(b -> b.cardinality() == 2)
.collect(Collectors.toList()).get(0);
- StructInfo structInfo = structInfoMap.getStructInfo(mvMap, mvMap,
root);
+ StructInfo structInfo = structInfoMap.getStructInfo(mvMap, mvMap,
root, null);
System.out.println(structInfo.getOriginalPlan().treeString());
BitSet bitSet = new BitSet();
structInfo.getRelations().forEach(r -> bitSet.set((int)
r.getTable().getId()));
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 20324ff8739..a3fc234f983 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
@@ -25,8 +25,6 @@ import org.apache.doris.nereids.util.PlanChecker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import java.util.List;
-
class BuildStructInfoTest extends SqlTestBase {
@Test
void testSimpleSQL() {
@@ -58,8 +56,8 @@ class BuildStructInfoTest extends SqlTestBase {
.deriveStats()
.matches(logicalJoin()
.when(j -> {
- List<HyperGraph> hyperGraph =
HyperGraph.builderForMv(j).buildAll();
-
Assertions.assertTrue(hyperGraph.get(0).getNodes().stream()
+ HyperGraph hyperGraph =
HyperGraph.builderForMv(j).build();
+
Assertions.assertTrue(hyperGraph.getNodes().stream()
.allMatch(n -> n.getPlan()
.collectToList(GroupPlan.class::isInstance).isEmpty()));
return true;
@@ -77,7 +75,7 @@ class BuildStructInfoTest extends SqlTestBase {
.rewrite()
.matches(logicalJoin()
.when(j -> {
- HyperGraph structInfo =
HyperGraph.builderForMv(j).buildAll().get(0);
+ HyperGraph structInfo =
HyperGraph.builderForMv(j).build();
Assertions.assertTrue(structInfo.getJoinEdge(0).getJoinType().isLeftOuterJoin());
Assertions.assertEquals(0,
structInfo.getFilterEdge(0).getLeftRejectEdge().size());
Assertions.assertEquals(1,
structInfo.getFilterEdge(0).getRightRejectEdge().size());
@@ -91,7 +89,7 @@ class BuildStructInfoTest extends SqlTestBase {
.rewrite()
.matches(logicalJoin()
.when(j -> {
- HyperGraph structInfo =
HyperGraph.builderForMv(j).buildAll().get(0);
+ HyperGraph structInfo =
HyperGraph.builderForMv(j).build();
Assertions.assertTrue(structInfo.getJoinEdge(0).getJoinType().isLeftOuterJoin());
return true;
}));
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/EliminateJoinTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/EliminateJoinTest.java
index cc8b7147423..08faf589390 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/EliminateJoinTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/EliminateJoinTest.java
@@ -30,6 +30,8 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
+
class EliminateJoinTest extends SqlTestBase {
@Test
void testLOJWithGroupBy() {
@@ -62,9 +64,9 @@ class EliminateJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
- HyperGraph h3 = HyperGraph.builderForMv(p3).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
+ HyperGraph h3 = HyperGraph.builderForMv(p3).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertTrue(!HyperGraphComparator.isLogicCompatible(h1, h3,
constructContext(p1, p2)).isInvalid());
@@ -93,8 +95,8 @@ class EliminateJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertTrue(res.getViewExpressions().isEmpty());
@@ -134,9 +136,9 @@ class EliminateJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
- HyperGraph h3 = HyperGraph.builderForMv(p3).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
+ HyperGraph h3 = HyperGraph.builderForMv(p3).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertTrue(res.getViewExpressions().isEmpty());
@@ -169,8 +171,8 @@ class EliminateJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertTrue(res.getViewExpressions().isEmpty());
@@ -202,8 +204,8 @@ class EliminateJoinTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertTrue(res.getViewExpressions().isEmpty());
@@ -213,9 +215,9 @@ class EliminateJoinTest extends SqlTestBase {
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
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
index 38ebc99c479..be4ce1cd054 100644
---
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
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
import java.util.Objects;
class HyperGraphAggTest extends SqlTestBase {
@@ -49,7 +50,7 @@ class HyperGraphAggTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p2).build();
Assertions.assertEquals("id", Objects.requireNonNull(((StructInfoNode)
h1.getNode(1)).getExpressions()).get(0).toSql());
}
@@ -79,8 +80,8 @@ class HyperGraphAggTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertEquals(2, res.getViewNoNullableSlot().size());
@@ -88,9 +89,9 @@ class HyperGraphAggTest extends SqlTestBase {
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparatorTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparatorTest.java
index 1fd2ac86ab6..066f9dd0881 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparatorTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparatorTest.java
@@ -30,6 +30,8 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
+
class HyperGraphComparatorTest extends SqlTestBase {
@Test
void testInnerJoinAndLOJ() {
@@ -55,8 +57,8 @@ class HyperGraphComparatorTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertEquals(2, res.getViewNoNullableSlot().size());
@@ -86,8 +88,8 @@ class HyperGraphComparatorTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertEquals(2, res.getViewNoNullableSlot().size());
@@ -118,8 +120,8 @@ class HyperGraphComparatorTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertEquals(2, res.getViewNoNullableSlot().size());
@@ -153,8 +155,8 @@ class HyperGraphComparatorTest extends SqlTestBase {
.rewrite()
.applyExploration(RuleSet.BUSHY_TREE_JOIN_REORDER)
.getAllPlan().get(0).child(0);
- HyperGraph h1 = HyperGraph.builderForMv(p1).buildAll().get(0);
- HyperGraph h2 = HyperGraph.builderForMv(p2).buildAll().get(0);
+ HyperGraph h1 = HyperGraph.builderForMv(p1).build();
+ HyperGraph h2 = HyperGraph.builderForMv(p2).build();
ComparisonResult res = HyperGraphComparator.isLogicCompatible(h1, h2,
constructContext(p1, p2));
Assertions.assertTrue(!res.isInvalid());
Assertions.assertEquals(2, res.getViewNoNullableSlot().size());
@@ -162,9 +164,9 @@ class HyperGraphComparatorTest extends SqlTestBase {
LogicalCompatibilityContext constructContext(Plan p1, Plan p2) {
StructInfo st1 = MaterializedViewUtils.extractStructInfo(p1,
- null).get(0);
+ null, new BitSet()).get(0);
StructInfo st2 = MaterializedViewUtils.extractStructInfo(p2,
- null).get(0);
+ null, new BitSet()).get(0);
RelationMapping rm = RelationMapping.generate(st1.getRelations(),
st2.getRelations()).get(0);
SlotMapping sm = SlotMapping.generate(rm);
return LogicalCompatibilityContext.from(rm, sm, st1, st2);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
index f68d37a24db..83a1faace1e 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExpressionUtilsTest.java
@@ -26,6 +26,7 @@ import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.BitSet;
import java.util.List;
/**
@@ -173,11 +174,8 @@ public class ExpressionUtilsTest extends TestWithFeService
{
Plan rewrittenPlan =
nereidsPlanner.getRewrittenPlan();
List<? extends Expression> originalExpressions =
rewrittenPlan.getExpressions();
List<? extends Expression> shuttledExpressions
- =
ExpressionUtils.shuttleExpressionWithLineage(
- originalExpressions,
- rewrittenPlan,
- Sets.newHashSet(),
- Sets.newHashSet());
+ =
ExpressionUtils.shuttleExpressionWithLineage(originalExpressions, rewrittenPlan,
+ Sets.newHashSet(), Sets.newHashSet(), new
BitSet());
assertExpect(originalExpressions,
shuttledExpressions,
"(cast(abs((cast(O_TOTALPRICE as
DECIMALV3(16, 2)) + 10.00)) as "
+ "DOUBLE) +
abs(sqrt(cast(PS_SUPPLYCOST as DOUBLE))))",
diff --git
a/regression-test/data/nereids_rules_p0/mv/nested/nested_materialized_view.out
b/regression-test/data/nereids_rules_p0/mv/nested/nested_materialized_view.out
new file mode 100644
index 00000000000..09c11bcee6a
--- /dev/null
+++
b/regression-test/data/nereids_rules_p0/mv/nested/nested_materialized_view.out
@@ -0,0 +1,20 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !query1_0_before --
+4
+4
+4
+4
+6
+6
+6
+6
+
+-- !query1_0_after --
+4
+4
+4
+4
+6
+6
+6
+6
\ No newline at end of file
diff --git
a/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy
b/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy
index 01672af1be0..d8037301c04 100644
---
a/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy
+++
b/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy
@@ -176,31 +176,37 @@ suite("aggregate_with_roll_up") {
// multi table
// filter inside + left + use roll up dimension
- def mv13_0 = "select l_shipdate, o_orderdate, l_partkey, l_suppkey, " +
- "sum(o_totalprice) as sum_total, " +
- "max(o_totalprice) as max_total, " +
- "min(o_totalprice) as min_total, " +
- "count(*) as count_all, " +
- "bitmap_union(to_bitmap(case when o_shippriority > 1 and
o_orderkey IN (1, 3) then o_custkey else null end)) as bitmap_union_basic " +
- "from lineitem " +
- "left join orders on lineitem.l_orderkey = orders.o_orderkey and
l_shipdate = o_orderdate " +
- "group by " +
- "l_shipdate, " +
- "o_orderdate, " +
- "l_partkey, " +
- "l_suppkey"
- def query13_0 = "select t1.l_partkey, t1.l_suppkey, o_orderdate, " +
- "sum(o_totalprice), " +
- "max(o_totalprice), " +
- "min(o_totalprice), " +
- "count(*), " +
- "count(distinct case when o_shippriority > 1 and o_orderkey IN (1,
3) then o_custkey else null end) " +
- "from (select * from lineitem where l_shipdate = '2023-12-11') t1
" +
- "left join orders on t1.l_orderkey = orders.o_orderkey and
t1.l_shipdate = o_orderdate " +
- "group by " +
- "o_orderdate, " +
- "l_partkey, " +
- "l_suppkey"
+ def mv13_0 =
+ """
+ select l_shipdate, o_orderdate, l_partkey, l_suppkey,
+ sum(o_totalprice) as sum_total,
+ max(o_totalprice) as max_total,
+ min(o_totalprice) as min_total,
+ count(*) as count_all,
+ bitmap_union(to_bitmap(case when o_shippriority > 1 and o_orderkey
IN (1, 3) then o_custkey else null end)) as bitmap_union_basic
+ from lineitem
+ left join orders on lineitem.l_orderkey = orders.o_orderkey and
l_shipdate = o_orderdate
+ group by
+ l_shipdate,
+ o_orderdate,
+ l_partkey,
+ l_suppkey
+ """
+ def query13_0 =
+ """
+ select t1.l_partkey, t1.l_suppkey, o_orderdate,
+ sum(o_totalprice),
+ max(o_totalprice),
+ min(o_totalprice),
+ count(*),
+ count(distinct case when o_shippriority > 1 and o_orderkey IN (1,
3) then o_custkey else null end)
+ from (select * from lineitem where l_shipdate = '2023-12-11') t1
+ left join orders on t1.l_orderkey = orders.o_orderkey and
t1.l_shipdate = o_orderdate
+ group by
+ o_orderdate,
+ l_partkey,
+ l_suppkey
+ """
order_qt_query13_0_before "${query13_0}"
check_mv_rewrite_success(db, mv13_0, query13_0, "mv13_0")
order_qt_query13_0_after "${query13_0}"
diff --git
a/regression-test/suites/nereids_rules_p0/mv/join/inner/inner_join.groovy
b/regression-test/suites/nereids_rules_p0/mv/join/inner/inner_join.groovy
index 118fa959c9a..9f0b66fc66a 100644
--- a/regression-test/suites/nereids_rules_p0/mv/join/inner/inner_join.groovy
+++ b/regression-test/suites/nereids_rules_p0/mv/join/inner/inner_join.groovy
@@ -355,13 +355,19 @@ suite("inner_join") {
// filter outside + left + right
- def mv4_0 = "select l_linenumber, o_custkey, o_orderkey, o_orderstatus " +
- "from lineitem " +
- "inner join orders on lineitem.l_orderkey = orders.o_orderkey "
- def query4_0 = "select lineitem.l_linenumber " +
- "from lineitem " +
- "inner join orders on lineitem.l_orderkey = orders.o_orderkey " +
- "where o_orderstatus = 'o' AND l_linenumber in (1, 2, 3, 4, 5) "
+ def mv4_0 =
+ """
+ select l_linenumber, o_custkey, o_orderkey, o_orderstatus
+ from lineitem
+ inner join orders on lineitem.l_orderkey = orders.o_orderkey
+ """
+ def query4_0 =
+ """
+ select lineitem.l_linenumber
+ from lineitem
+ inner join orders on lineitem.l_orderkey = orders.o_orderkey
+ where o_orderstatus = 'o' AND l_linenumber in (1, 2, 3, 4, 5)
+ """
order_qt_query4_0_before "${query4_0}"
check_mv_rewrite_success(db, mv4_0, query4_0, "mv4_0")
order_qt_query4_0_after "${query4_0}"
diff --git
a/regression-test/suites/nereids_rules_p0/mv/nested/nested_materialized_view.groovy
b/regression-test/suites/nereids_rules_p0/mv/nested/nested_materialized_view.groovy
new file mode 100644
index 00000000000..6ad175e85ce
--- /dev/null
+++
b/regression-test/suites/nereids_rules_p0/mv/nested/nested_materialized_view.groovy
@@ -0,0 +1,182 @@
+// 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.
+
+suite("nested_materialized_view") {
+ String db = context.config.getDbNameByFile(context.file)
+ sql "use ${db}"
+ sql "SET enable_nereids_planner=true"
+ sql "set runtime_filter_mode=OFF"
+ sql "SET enable_fallback_to_original_planner=false"
+ sql "SET enable_materialized_view_rewrite=true"
+ sql "SET enable_nereids_timeout = false"
+
+ def create_mtmv = { db_name, mv_name, mv_sql ->
+ sql """DROP MATERIALIZED VIEW IF EXISTS ${mv_name}"""
+ sql"""
+ CREATE MATERIALIZED VIEW ${mv_name}
+ BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
+ DISTRIBUTED BY RANDOM BUCKETS 2
+ PROPERTIES ('replication_num' = '1')
+ AS ${mv_sql}
+ """
+
+ def job_name = getJobName(db_name, mv_name);
+ waitingMTMVTaskFinished(job_name)
+ }
+
+ sql """
+ drop table if exists orders
+ """
+
+ sql """
+ CREATE TABLE IF NOT EXISTS orders (
+ o_orderkey INTEGER NOT NULL,
+ o_custkey INTEGER NOT NULL,
+ o_orderstatus CHAR(1) NOT NULL,
+ o_totalprice DECIMALV3(15,2) NOT NULL,
+ o_orderdate DATE NOT NULL,
+ o_orderpriority CHAR(15) NOT NULL,
+ o_clerk CHAR(15) NOT NULL,
+ o_shippriority INTEGER NOT NULL,
+ o_comment VARCHAR(79) NOT NULL
+ )
+ DUPLICATE KEY(o_orderkey, o_custkey)
+ PARTITION BY RANGE(o_orderdate) (PARTITION `day_2` VALUES LESS THAN
('2023-12-30'))
+ DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ drop table if exists lineitem
+ """
+
+ sql"""
+ CREATE TABLE IF NOT EXISTS lineitem (
+ l_orderkey INTEGER NOT NULL,
+ l_partkey INTEGER NOT NULL,
+ l_suppkey INTEGER NOT NULL,
+ l_linenumber INTEGER NOT NULL,
+ l_quantity DECIMALV3(15,2) NOT NULL,
+ l_extendedprice DECIMALV3(15,2) NOT NULL,
+ l_discount DECIMALV3(15,2) NOT NULL,
+ l_tax DECIMALV3(15,2) NOT NULL,
+ l_returnflag CHAR(1) NOT NULL,
+ l_linestatus CHAR(1) NOT NULL,
+ l_shipdate DATE NOT NULL,
+ l_commitdate DATE NOT NULL,
+ l_receiptdate DATE NOT NULL,
+ l_shipinstruct CHAR(25) NOT NULL,
+ l_shipmode CHAR(10) NOT NULL,
+ l_comment VARCHAR(44) NOT NULL
+ )
+ DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
+ PARTITION BY RANGE(l_shipdate) (PARTITION `day_1` VALUES LESS THAN
('2023-12-30'))
+ DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ drop table if exists partsupp
+ """
+
+ sql """
+ CREATE TABLE IF NOT EXISTS partsupp (
+ ps_partkey INTEGER NOT NULL,
+ ps_suppkey INTEGER NOT NULL,
+ ps_availqty INTEGER NOT NULL,
+ ps_supplycost DECIMALV3(15,2) NOT NULL,
+ ps_comment VARCHAR(199) NOT NULL
+ )
+ DUPLICATE KEY(ps_partkey, ps_suppkey)
+ DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """ insert into lineitem values
+ (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-08', '2023-12-09',
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+ (2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-09', '2023-12-09',
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+ (3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-10', '2023-12-09',
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+ (4, 3, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-11', '2023-12-09',
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+ (5, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-12-12', '2023-12-12',
'2023-12-13', 'c', 'd', 'xxxxxxxxx');
+ """
+
+ sql """
+ insert into orders values
+ (1, 1, 'o', 9.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+ (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+ (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+ (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+ (3, 1, 'o', 33.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+ (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+ (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+ (5, 2, 'o', 1.2, '2023-12-12', 'c','d',2, 'mi');
+ """
+
+ sql """
+ insert into partsupp values
+ (2, 3, 9, 10.01, 'supply1'),
+ (2, 3, 10, 11.01, 'supply2');
+ """
+
+ // simple nested materialized view
+ def mv1_0_inner_mv = """
+ select
+ l_linenumber,
+ o_custkey,
+ o_orderkey,
+ o_orderstatus,
+ l_partkey,
+ l_suppkey,
+ l_orderkey
+ from lineitem
+ inner join orders on lineitem.l_orderkey = orders.o_orderkey;
+ """
+
+ def mv1_0 =
+ """
+ select
+ l_linenumber,
+ o_custkey,
+ o_orderkey,
+ o_orderstatus,
+ l_partkey,
+ l_suppkey,
+ l_orderkey,
+ ps_availqty
+ from mv1_0_inner_mv
+ inner join partsupp on l_partkey = ps_partkey AND l_suppkey =
ps_suppkey;
+ """
+ def query1_0 = """
+ select lineitem.l_linenumber
+ from lineitem
+ inner join orders on l_orderkey = o_orderkey
+ inner join partsupp on l_partkey = ps_partkey AND l_suppkey =
ps_suppkey
+ where o_orderstatus = 'o'
+ """
+ order_qt_query1_0_before "${query1_0}"
+ create_mtmv(db, "mv1_0_inner_mv", mv1_0_inner_mv)
+ check_mv_rewrite_success(db, mv1_0, query1_0, "mv1_0")
+ order_qt_query1_0_after "${query1_0}"
+ sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_0_inner_mv"""
+ sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_0"""
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]