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 5cb5241a9ea [feature](mtmv) materialized view rewrite framework
(#27059)
5cb5241a9ea is described below
commit 5cb5241a9ea9cc2bdea5c04ad451ec113e4e2248
Author: seawinde <[email protected]>
AuthorDate: Mon Nov 27 11:15:54 2023 +0800
[feature](mtmv) materialized view rewrite framework (#27059)
materialized view rewrite framework, support to query rewrite by struct
info.
The idea is from "Optimizing Queries Using Materialized Views- A Practical,
Scalable Solution"
---
.../org/apache/doris/nereids/CascadesContext.java | 12 +
.../org/apache/doris/nereids/NereidsPlanner.java | 4 +
.../jobs/cascades/OptimizeGroupExpressionJob.java | 3 +
.../java/org/apache/doris/nereids/memo/Group.java | 11 +
.../org/apache/doris/nereids/rules/RuleSet.java | 9 +
.../org/apache/doris/nereids/rules/RuleType.java | 17 ++
.../mv/AbstractMaterializedViewAggregateRule.java | 25 ++
.../mv/AbstractMaterializedViewJoinRule.java | 62 +++++
.../mv/AbstractMaterializedViewRule.java | 253 +++++++++++++++++++++
.../rules/exploration/mv/EquivalenceClass.java | 92 ++++++++
.../nereids/rules/exploration/mv/Mapping.java | 144 ++++++++++++
.../exploration/mv/MaterializationContext.java | 68 ++++++
.../mv/MaterializedViewAggregateRule.java | 33 +++
.../mv/MaterializedViewProjectJoinRule.java | 47 ++++
.../exploration/mv/MaterializedViewScanRule.java | 34 +++
.../nereids/rules/exploration/mv/Predicates.java | 131 +++++++++++
.../rules/exploration/mv/RelationMapping.java | 63 +++++
.../nereids/rules/exploration/mv/SlotMapping.java | 49 ++++
.../nereids/rules/exploration/mv/StructInfo.java | 106 +++++++++
.../expressions/visitor/ExpressionVisitors.java | 49 ++++
.../apache/doris/nereids/util/ExpressionUtils.java | 28 +++
.../java/org/apache/doris/qe/SessionVariable.java | 25 ++
22 files changed, 1265 insertions(+)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
index ebef71feb85..3c21a988fb5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
@@ -44,6 +44,7 @@ import org.apache.doris.nereids.properties.PhysicalProperties;
import org.apache.doris.nereids.rules.RuleFactory;
import org.apache.doris.nereids.rules.RuleSet;
import
org.apache.doris.nereids.rules.analysis.BindRelation.CustomTableResolver;
+import org.apache.doris.nereids.rules.exploration.mv.MaterializationContext;
import org.apache.doris.nereids.trees.expressions.CTEId;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
@@ -112,6 +113,8 @@ public class CascadesContext implements ScheduleContext {
private final Optional<CTEId> currentTree;
private final Optional<CascadesContext> parent;
+ private final List<MaterializationContext> materializationContexts;
+
/**
* Constructor of OptimizerContext.
*
@@ -133,6 +136,7 @@ public class CascadesContext implements ScheduleContext {
this.currentJobContext = new JobContext(this, requireProperties,
Double.MAX_VALUE);
this.subqueryExprIsAnalyzed = new HashMap<>();
this.runtimeFilterContext = new
RuntimeFilterContext(getConnectContext().getSessionVariable());
+ this.materializationContexts = new ArrayList<>();
}
/**
@@ -309,6 +313,14 @@ public class CascadesContext implements ScheduleContext {
this.outerScope = Optional.ofNullable(outerScope);
}
+ public List<MaterializationContext> getMaterializationContexts() {
+ return materializationContexts;
+ }
+
+ public void addMaterializationContext(MaterializationContext
materializationContext) {
+ this.materializationContexts.add(materializationContext);
+ }
+
/**
* getAndCacheSessionVariable
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
index bf870f9dd6b..63aadc7af19 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
@@ -259,6 +259,10 @@ public class NereidsPlanner extends Planner {
if (statementContext.getConnectContext().getTables() != null) {
cascadesContext.setTables(statementContext.getConnectContext().getTables());
}
+ if
(statementContext.getConnectContext().getSessionVariable().isEnableMaterializedViewRewrite())
{
+ // TODO Pre handle materialized view to materializationContext and
+ // call cascadesContext.addMaterializationContext() to add it
+ }
}
private void analyze() {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
index 38c0c4484bc..08b7731fd09 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
@@ -46,6 +46,9 @@ public class OptimizeGroupExpressionJob extends Job {
countJobExecutionTimesOfGroupExpressions(groupExpression);
List<Rule> implementationRules = getRuleSet().getImplementationRules();
List<Rule> explorationRules = getExplorationRules();
+ if
(context.getCascadesContext().getConnectContext().getSessionVariable().isEnableMaterializedViewRewrite())
{
+ explorationRules.addAll(getRuleSet().getMaterializedViewRules());
+ }
for (Rule rule : explorationRules) {
if (rule.isInvalid(disableRules, groupExpression)) {
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 ece30e1f4da..8d09c8afac2 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
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.cost.Cost;
import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph;
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,6 +77,8 @@ public class Group {
private int chosenGroupExpressionId = -1;
+ private Optional<StructInfo> structInfo = Optional.empty();
+
/**
* Constructor for Group.
*
@@ -538,4 +541,12 @@ public class Group {
return TreeStringUtils.treeString(this, toString, getChildren,
getExtraPlans, displayExtraPlan);
}
+
+ public Optional<StructInfo> getStructInfo() {
+ return structInfo;
+ }
+
+ public void setStructInfo(StructInfo structInfo) {
+ this.structInfo = Optional.ofNullable(structInfo);
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index 736ad7f7a87..ed2bc775e25 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -40,6 +40,7 @@ import
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughInn
import
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughSemiJoin;
import
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTranspose;
import
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTransposeProject;
+import
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewProjectJoinRule;
import org.apache.doris.nereids.rules.implementation.AggregateStrategies;
import
org.apache.doris.nereids.rules.implementation.LogicalAssertNumRowsToPhysicalAssertNumRows;
import
org.apache.doris.nereids.rules.implementation.LogicalCTEAnchorToPhysicalCTEAnchor;
@@ -220,6 +221,10 @@ public class RuleSet {
.add(JoinCommute.BUSHY.build())
.build();
+ public static final List<Rule> MATERIALIZED_VIEW_RULES =
planRuleFactories()
+ .add(MaterializedViewProjectJoinRule.INSTANCE)
+ .build();
+
public List<Rule> getDPHypReorderRules() {
return DPHYP_REORDER_RULES;
}
@@ -240,6 +245,10 @@ public class RuleSet {
return IMPLEMENTATION_RULES;
}
+ public List<Rule> getMaterializedViewRules() {
+ return MATERIALIZED_VIEW_RULES;
+ }
+
public static RuleFactories planRuleFactories() {
return new RuleFactories();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index 40a63a056c0..e91b91360e5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -227,6 +227,7 @@ public enum RuleType {
MATERIALIZED_INDEX_PROJECT_SCAN(RuleTypeClass.REWRITE),
MATERIALIZED_INDEX_PROJECT_FILTER_SCAN(RuleTypeClass.REWRITE),
MATERIALIZED_INDEX_FILTER_PROJECT_SCAN(RuleTypeClass.REWRITE),
+
OLAP_SCAN_PARTITION_PRUNE(RuleTypeClass.REWRITE),
FILE_SCAN_PARTITION_PRUNE(RuleTypeClass.REWRITE),
PUSH_CONJUNCTS_INTO_JDBC_SCAN(RuleTypeClass.REWRITE),
@@ -321,6 +322,22 @@ public enum RuleType {
EAGER_SPLIT(RuleTypeClass.EXPLORATION),
EXPLORATION_SENTINEL(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_PROJECT_JOIN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_FILTER_JOIN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_PROJECT_FILTER_JOIN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_FILTER_PROJECT_JOIN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_ONLY_JOIN(RuleTypeClass.EXPLORATION),
+
+ MATERIALIZED_VIEW_PROJECT_AGGREGATE(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_FILTER_AGGREGATE(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_ONLY_AGGREGATE(RuleTypeClass.EXPLORATION),
+
+ MATERIALIZED_VIEW_FILTER_SCAN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_PROJECT_SCAN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_FILTER_PROJECT_SCAN(RuleTypeClass.EXPLORATION),
+ MATERIALIZED_VIEW_PROJECT_FILTER_SCAN(RuleTypeClass.EXPLORATION),
// implementation rules
LOGICAL_ONE_ROW_RELATION_TO_PHYSICAL_ONE_ROW_RELATION(RuleTypeClass.IMPLEMENTATION),
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
new file mode 100644
index 00000000000..a9a8b754d33
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
@@ -0,0 +1,25 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+/**
+ * AbstractMaterializedViewAggregateRule
+ * This is responsible for common aggregate rewriting
+ * */
+public abstract class AbstractMaterializedViewAggregateRule extends
AbstractMaterializedViewRule {
+}
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
new file mode 100644
index 00000000000..17df9ef88ed
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import java.util.List;
+
+/**
+ * AbstractMaterializedViewJoinRule
+ * This is responsible for common join rewriting
+ */
+public abstract class AbstractMaterializedViewJoinRule extends
AbstractMaterializedViewRule {
+
+ @Override
+ protected Plan rewriteQueryByView(MatchMode matchMode,
+ StructInfo queryStructInfo,
+ StructInfo viewStructInfo,
+ RelationMapping queryToViewTableMappings,
+ Plan tempRewritedPlan) {
+
+ // Rewrite top projects, represent the query projects by view
+ List<NamedExpression> expressions = rewriteExpression(
+ queryStructInfo.getExpressions(),
+ queryStructInfo,
+ viewStructInfo,
+ queryToViewTableMappings,
+ tempRewritedPlan
+ );
+ // Can not rewrite, bail out
+ if (expressions == null) {
+ return null;
+ }
+ return new LogicalProject<>(expressions, tempRewritedPlan);
+ }
+
+ // Check join is whether valid or not. Support join's input can not
contain aggregate
+ // Only support project, filter, join, logical relation node and
+ // join condition should be slot reference equals currently
+ @Override
+ protected boolean checkPattern(StructInfo structInfo) {
+ // TODO Should get struct info from hyper graph and check
+ return false;
+ }
+}
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
new file mode 100644
index 00000000000..c52acdb3fda
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
@@ -0,0 +1,253 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.memo.Group;
+import
org.apache.doris.nereids.rules.exploration.mv.Mapping.ExpressionIndexMapping;
+import org.apache.doris.nereids.rules.exploration.mv.Predicates.SplitPredicate;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * The abstract class for all materialized view rules
+ */
+public abstract class AbstractMaterializedViewRule {
+
+ /**
+ * The abstract template method for query rewrite, it contains the main
logic and different query
+ * pattern should override the sub logic.
+ */
+ protected List<Plan> rewrite(Plan queryPlan, CascadesContext
cascadesContext) {
+ List<MaterializationContext> materializationContexts =
cascadesContext.getMaterializationContexts();
+ List<Plan> rewriteResults = new ArrayList<>();
+ if (materializationContexts.isEmpty()) {
+ return rewriteResults;
+ }
+ StructInfo queryStructInfo = extractStructInfo(queryPlan,
cascadesContext);
+ // Check query queryPlan
+ if (!checkPattern(queryStructInfo)) {
+ return rewriteResults;
+ }
+
+ for (MaterializationContext materializationContext :
materializationContexts) {
+ Plan mvPlan = materializationContext.getMvPlan();
+ StructInfo viewStructInfo = extractStructInfo(mvPlan,
cascadesContext);
+ if (!checkPattern(viewStructInfo)) {
+ continue;
+ }
+ if
(!StructInfo.isGraphLogicalEquals(queryStructInfo.getHyperGraph(),
viewStructInfo.getHyperGraph())) {
+ continue;
+ }
+ MatchMode matchMode =
decideMatchMode(queryStructInfo.getRelations(), viewStructInfo.getRelations());
+ if (MatchMode.NOT_MATCH == matchMode) {
+ continue;
+ }
+ List<RelationMapping> queryToViewTableMappings =
+ RelationMapping.generate(queryStructInfo.getRelations(),
viewStructInfo.getRelations());
+ for (RelationMapping queryToViewTableMapping :
queryToViewTableMappings) {
+ SplitPredicate compensatePredicates =
predicatesCompensate(queryStructInfo, viewStructInfo,
+ queryToViewTableMapping);
+ // Can not compensate, bail out
+ if (compensatePredicates == null ||
compensatePredicates.isEmpty()) {
+ continue;
+ }
+ Plan rewritedPlan;
+ Plan mvScan = materializationContext.getScanPlan();
+ if (compensatePredicates.isAlwaysTrue()) {
+ rewritedPlan = mvScan;
+ } else {
+ // Try to rewrite compensate predicates by using mv scan
+ List<NamedExpression> rewriteCompensatePredicates =
rewriteExpression(
+ compensatePredicates.toList(),
+ queryStructInfo,
+ viewStructInfo,
+ queryToViewTableMapping,
+ mvScan);
+ if (rewriteCompensatePredicates.isEmpty()) {
+ continue;
+ }
+ rewritedPlan = new
LogicalFilter<>(Sets.newHashSet(rewriteCompensatePredicates), mvScan);
+ }
+ // Rewrite query by view
+ rewritedPlan = rewriteQueryByView(matchMode, queryStructInfo,
viewStructInfo,
+ queryToViewTableMapping, rewritedPlan);
+ if (rewritedPlan == null) {
+ continue;
+ }
+ rewriteResults.add(rewritedPlan);
+ }
+ }
+ return rewriteResults;
+ }
+
+ /**Rewrite query by view, for aggregate or join rewriting should be
different inherit class implementation*/
+ protected Plan rewriteQueryByView(MatchMode matchMode,
+ StructInfo queryStructInfo,
+ StructInfo viewStructInfo,
+ RelationMapping queryToViewTableMappings,
+ Plan tempRewritedPlan) {
+ return tempRewritedPlan;
+ }
+
+ /**Use target output expression to represent the source expression*/
+ protected List<NamedExpression> rewriteExpression(List<? extends
Expression> sourceExpressions,
+ StructInfo sourceStructInfo,
+ StructInfo targetStructInfo,
+ RelationMapping sourceToTargetMapping,
+ Plan targetScanNode) {
+ // TODO represent the sourceExpressions by using target scan node
+ // Firstly, rewrite the target plan output expression using query with
inverse mapping
+ // then try to use the mv expression to represent the query. if any of
source expressions
+ // can not be represented by mv, return null
+ //
+ // example as following:
+ // source target
+ // project(slot 1, 2) project(slot 3, 2, 1)
+ // scan(table) scan(table)
+ //
+ // transform source to:
+ // project(slot 2, 1)
+ // target
+ List<? extends Expression> targetTopExpressions =
targetStructInfo.getExpressions();
+ List<? extends Expression> shuttledTargetExpressions =
ExpressionUtils.shuttleExpressionWithLineage(
+ targetTopExpressions, targetStructInfo.getOriginalPlan(),
Sets.newHashSet(), Sets.newHashSet());
+ SlotMapping sourceToTargetSlotMapping =
SlotMapping.generate(sourceToTargetMapping);
+ // mv sql plan expressions transform to query based
+ List<? extends Expression> queryBasedExpressions =
ExpressionUtils.permute(shuttledTargetExpressions,
+ sourceToTargetSlotMapping.inverse());
+ // mv sql query based expression and index mapping
+ ExpressionIndexMapping.generate(queryBasedExpressions);
+ // TODO visit source expression and replace the expression with
expressionIndexMapping
+ return ImmutableList.of();
+ }
+
+ /**
+ * Compensate mv predicates by query predicates, compensate predicate
result is query based.
+ * Such as a > 5 in mv, and a > 10 in query, the compensatory predicate is
a > 10.
+ * For another example as following:
+ * predicate a = b in mv, and a = b and c = d in query, the compensatory
predicate is c = d
+ */
+ protected SplitPredicate predicatesCompensate(
+ StructInfo queryStructInfo,
+ StructInfo viewStructInfo,
+ RelationMapping queryToViewTableMapping
+ ) {
+ // TODO Equal predicate compensate
+ EquivalenceClass queryEquivalenceClass =
queryStructInfo.getEquivalenceClass();
+ EquivalenceClass viewEquivalenceClass =
viewStructInfo.getEquivalenceClass();
+ if (queryEquivalenceClass.isEmpty()
+ && !viewEquivalenceClass.isEmpty()) {
+ return null;
+ }
+ // TODO range predicates and residual predicates compensate
+ return SplitPredicate.empty();
+ }
+
+ /**
+ * Decide the match mode
+ * @see MatchMode
+ */
+ private MatchMode decideMatchMode(List<CatalogRelation> queryRelations,
List<CatalogRelation> viewRelations) {
+ List<TableIf> queryTableRefs = queryRelations
+ .stream()
+ .map(CatalogRelation::getTable)
+ .collect(Collectors.toList());
+ List<TableIf> viewTableRefs = viewRelations
+ .stream()
+ .map(CatalogRelation::getTable)
+ .collect(Collectors.toList());
+ boolean sizeSame = viewTableRefs.size() == queryTableRefs.size();
+ boolean queryPartial = viewTableRefs.containsAll(queryTableRefs);
+ if (!sizeSame && queryPartial) {
+ return MatchMode.QUERY_PARTIAL;
+ }
+ boolean viewPartial = queryTableRefs.containsAll(viewTableRefs);
+ if (!sizeSame && viewPartial) {
+ return MatchMode.VIEW_PARTIAL;
+ }
+ if (sizeSame && queryPartial && viewPartial) {
+ return MatchMode.COMPLETE;
+ }
+ return MatchMode.NOT_MATCH;
+ }
+
+ /**
+ * Extract struct info from plan, support to get struct info from logical
plan or plan in group.
+ */
+ protected StructInfo extractStructInfo(Plan plan, CascadesContext
cascadesContext) {
+
+ if (plan.getGroupExpression().isPresent()
+ &&
plan.getGroupExpression().get().getOwnerGroup().getStructInfo().isPresent()) {
+ Group belongGroup =
plan.getGroupExpression().get().getOwnerGroup();
+ return belongGroup.getStructInfo().get();
+ } else {
+ // TODO build graph from plan and extract struct from graph and
set to group if exist
+ // Should get structInfo from hyper graph and add into current
group
+ StructInfo structInfo = StructInfo.of(plan);
+ if (plan.getGroupExpression().isPresent()) {
+
plan.getGroupExpression().get().getOwnerGroup().setStructInfo(structInfo);
+ }
+ return structInfo;
+ }
+ }
+
+ /**
+ * Check the pattern of query or materializedView is supported or not.
+ */
+ protected boolean checkPattern(StructInfo structInfo) {
+ if (structInfo.getRelations().isEmpty()) {
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Query and mv match node
+ */
+ protected enum MatchMode {
+ /**
+ * The tables in query are same to the tables in view
+ */
+ COMPLETE,
+ /**
+ * The tables in query contains all the tables in view
+ */
+ VIEW_PARTIAL,
+ /**
+ * The tables in view contains all the tables in query
+ */
+ QUERY_PARTIAL,
+ /**
+ * Except for COMPLETE and VIEW_PARTIAL and QUERY_PARTIAL
+ */
+ NOT_MATCH
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/EquivalenceClass.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/EquivalenceClass.java
new file mode 100644
index 00000000000..d140582aa64
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/EquivalenceClass.java
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * EquivalenceClass, this is used for equality propagation when predicate
compensation
+ */
+public class EquivalenceClass {
+
+ private final Map<SlotReference, Set<SlotReference>> equivalenceSlotMap =
new LinkedHashMap<>();
+
+ public EquivalenceClass() {
+ }
+
+ /**
+ * EquivalenceClass
+ */
+ public void addEquivalenceClass(SlotReference leftSlot, SlotReference
rightSlot) {
+
+ Set<SlotReference> leftSlotSet = equivalenceSlotMap.get(leftSlot);
+ Set<SlotReference> rightSlotSet = equivalenceSlotMap.get(rightSlot);
+ if (leftSlotSet != null && rightSlotSet != null) {
+ // Both present, we need to merge
+ if (leftSlotSet.size() < rightSlotSet.size()) {
+ // We swap them to merge
+ Set<SlotReference> tmp = rightSlotSet;
+ rightSlotSet = leftSlotSet;
+ leftSlotSet = tmp;
+ }
+ for (SlotReference newRef : rightSlotSet) {
+ leftSlotSet.add(newRef);
+ equivalenceSlotMap.put(newRef, leftSlotSet);
+ }
+ } else if (leftSlotSet != null) {
+ // leftSlotSet present, we need to merge into it
+ leftSlotSet.add(rightSlot);
+ equivalenceSlotMap.put(rightSlot, leftSlotSet);
+ } else if (rightSlotSet != null) {
+ // rightSlotSet present, we need to merge into it
+ rightSlotSet.add(leftSlot);
+ equivalenceSlotMap.put(leftSlot, rightSlotSet);
+ } else {
+ // None are present, add to same equivalence class
+ Set<SlotReference> equivalenceClass = new LinkedHashSet<>();
+ equivalenceClass.add(leftSlot);
+ equivalenceClass.add(rightSlot);
+ equivalenceSlotMap.put(leftSlot, equivalenceClass);
+ equivalenceSlotMap.put(rightSlot, equivalenceClass);
+ }
+ }
+
+ public Map<SlotReference, Set<SlotReference>> getEquivalenceSlotMap() {
+ return equivalenceSlotMap;
+ }
+
+ public boolean isEmpty() {
+ return equivalenceSlotMap.isEmpty();
+ }
+
+ /**
+ * EquivalenceClass
+ */
+ public List<Set<SlotReference>> getEquivalenceValues() {
+ List<Set<SlotReference>> values = new ArrayList<>();
+ equivalenceSlotMap.values().forEach(each -> values.add(each));
+ return values;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Mapping.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Mapping.java
new file mode 100644
index 00000000000..487fc92ce50
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Mapping.java
@@ -0,0 +1,144 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.trees.expressions.ExprId;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.RelationId;
+import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Mapping slot from query to view or inversely,
+ * it can also represent the mapping from slot to it's index
+ */
+public abstract class Mapping {
+
+ /**
+ * The relation for mapping
+ */
+ public static final class MappedRelation {
+ public final RelationId relationId;
+ public final CatalogRelation belongedRelation;
+
+ public MappedRelation(RelationId relationId, CatalogRelation
belongedRelation) {
+ this.relationId = relationId;
+ this.belongedRelation = belongedRelation;
+ }
+
+ public MappedRelation of(RelationId relationId, CatalogRelation
belongedRelation) {
+ return new MappedRelation(relationId, belongedRelation);
+ }
+
+ public RelationId getRelationId() {
+ return relationId;
+ }
+
+ public CatalogRelation getBelongedRelation() {
+ return belongedRelation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MappedRelation that = (MappedRelation) o;
+ return Objects.equals(relationId, that.relationId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(relationId);
+ }
+ }
+
+ /**
+ * The slot for mapping
+ */
+ public static final class MappedSlot {
+
+ public final ExprId exprId;
+ public final CatalogRelation belongedRelation;
+
+ public MappedSlot(ExprId exprId, CatalogRelation belongedRelation) {
+ this.exprId = exprId;
+ this.belongedRelation = belongedRelation;
+ }
+
+ public MappedSlot of(ExprId exprId, CatalogRelation belongedRelation) {
+ return new MappedSlot(exprId, belongedRelation);
+ }
+
+ public ExprId getExprId() {
+ return exprId;
+ }
+
+ public CatalogRelation getBelongedRelation() {
+ return belongedRelation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MappedSlot that = (MappedSlot) o;
+ return Objects.equals(exprId, that.exprId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(exprId);
+ }
+ }
+
+ /**
+ * Expression and it's index mapping
+ */
+ public static class ExpressionIndexMapping extends Mapping {
+ private final Multimap<Expression, Integer> expressionIndexMapping;
+
+ public ExpressionIndexMapping(Multimap<Expression, Integer>
expressionIndexMapping) {
+ this.expressionIndexMapping = expressionIndexMapping;
+ }
+
+ public Multimap<Expression, Integer> getExpressionIndexMapping() {
+ return expressionIndexMapping;
+ }
+
+ public static ExpressionIndexMapping generate(List<? extends
Expression> expressions) {
+ Multimap<Expression, Integer> expressionIndexMapping =
ArrayListMultimap.create();
+ for (int i = 0; i < expressions.size(); i++) {
+ expressionIndexMapping.put(expressions.get(i), i);
+ }
+ return new ExpressionIndexMapping(expressionIndexMapping);
+ }
+ }
+}
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
new file mode 100644
index 00000000000..b0de1ccfa46
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializationContext.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.View;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.memo.GroupId;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Maintain the context for query rewrite by materialized view
+ */
+public class MaterializationContext {
+
+ // TODO add MaterializedView class
+ private final Plan mvPlan;
+ private final CascadesContext context;
+ private final List<Table> baseTables;
+ private final List<View> baseViews;
+ // Group ids that are rewritten by this mv to reduce rewrite times
+ private final Set<GroupId> matchedGroups = new HashSet<>();
+ private final Plan scanPlan;
+
+ public MaterializationContext(Plan mvPlan, CascadesContext context,
+ List<Table> baseTables, List<View> baseViews, Plan scanPlan) {
+ this.mvPlan = mvPlan;
+ this.context = context;
+ this.baseTables = baseTables;
+ this.baseViews = baseViews;
+ this.scanPlan = scanPlan;
+ }
+
+ public Set<GroupId> getMatchedGroups() {
+ return matchedGroups;
+ }
+
+ public void addMatchedGroup(GroupId groupId) {
+ matchedGroups.add(groupId);
+ }
+
+ public Plan getMvPlan() {
+ return mvPlan;
+ }
+
+ public Plan getScanPlan() {
+ return scanPlan;
+ }
+}
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
new file mode 100644
index 00000000000..ce9c208e5f5
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateRule.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
+
+import java.util.List;
+
+/**
+ * This is responsible for aggregate rewriting according to different pattern
+ * */
+public class MaterializedViewAggregateRule extends
AbstractMaterializedViewAggregateRule implements RewriteRuleFactory {
+ @Override
+ public List<Rule> buildRules() {
+ return null;
+ }
+}
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
new file mode 100644
index 00000000000..92f102dc1de
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectJoinRule.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * This is responsible for join rewriting according to different pattern
+ * */
+public class MaterializedViewProjectJoinRule extends
AbstractMaterializedViewJoinRule implements RewriteRuleFactory {
+
+ public static final MaterializedViewProjectJoinRule INSTANCE = new
MaterializedViewProjectJoinRule();
+
+ @Override
+ public List<Rule> buildRules() {
+ return ImmutableList.of(
+ logicalProject(logicalJoin(any(), any())).thenApplyMulti(ctx
-> {
+ LogicalProject<LogicalJoin<Plan, Plan>> root = ctx.root;
+ return rewrite(root, ctx.cascadesContext);
+ }).toRule(RuleType.MATERIALIZED_VIEW_ONLY_JOIN,
RulePromise.EXPLORE));
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
new file mode 100644
index 00000000000..c5909822adb
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
+
+import java.util.List;
+
+/**
+ * This is responsible for single table rewriting according to different
pattern
+ * */
+public class MaterializedViewScanRule extends AbstractMaterializedViewRule
implements RewriteRuleFactory {
+
+ @Override
+ public List<Rule> buildRules() {
+ return null;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
new file mode 100644
index 00000000000..40b91994be7
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
+import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitors.PredicatesSpliter;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This record the predicates which can be pulled up or some other type
predicates
+ * */
+public class Predicates {
+
+ // Predicates that can be pulled up
+ private final Set<Expression> pulledUpPredicates;
+
+ public Predicates(Set<Expression> pulledUpPredicates) {
+ this.pulledUpPredicates = pulledUpPredicates;
+ }
+
+ public static Predicates of(Set<Expression> pulledUpPredicates) {
+ return new Predicates(pulledUpPredicates);
+ }
+
+ public Set<Expression> getPulledUpPredicates() {
+ return pulledUpPredicates;
+ }
+
+ public Expression composedExpression() {
+ return ExpressionUtils.and(pulledUpPredicates);
+ }
+
+ /**
+ * Split the expression to equal, range and residual predicate.
+ * */
+ public static SplitPredicate splitPredicates(Expression expression) {
+ PredicatesSpliter predicatesSplit = new PredicatesSpliter(expression);
+ expression.accept(predicatesSplit, null);
+ return predicatesSplit.getSplitPredicate();
+ }
+
+ /**
+ * The split different representation for predicate expression, such as
equal, range and residual predicate.
+ * */
+ public static final class SplitPredicate {
+ private final Expression equalPredicates;
+ private final Expression rangePredicates;
+ private final Expression residualPredicates;
+
+ public SplitPredicate(Expression equalPredicates, Expression
rangePredicates, Expression residualPredicates) {
+ this.equalPredicates = equalPredicates;
+ this.rangePredicates = rangePredicates;
+ this.residualPredicates = residualPredicates;
+ }
+
+ public Expression getEqualPredicates() {
+ return equalPredicates;
+ }
+
+ public Expression getRangePredicates() {
+ return rangePredicates;
+ }
+
+ public Expression getResidualPredicates() {
+ return residualPredicates;
+ }
+
+ public static SplitPredicate empty() {
+ return new SplitPredicate(null, null, null);
+ }
+
+ /**
+ * SplitPredicate construct
+ * */
+ public static SplitPredicate of(Expression equalPredicates,
+ Expression rangePredicates,
+ Expression residualPredicates) {
+ return new SplitPredicate(equalPredicates, rangePredicates,
residualPredicates);
+ }
+
+ /**
+ * isEmpty
+ * */
+ public boolean isEmpty() {
+ return equalPredicates == null
+ && rangePredicates == null
+ && residualPredicates == null;
+ }
+
+ public Expression composedExpression() {
+ return ExpressionUtils.and(equalPredicates, rangePredicates,
residualPredicates);
+ }
+
+ public List<Expression> toList() {
+ return ImmutableList.of(equalPredicates, rangePredicates,
residualPredicates);
+ }
+
+ /**
+ * Check the predicates in SplitPredicate is whether all true or not
+ */
+ public boolean isAlwaysTrue() {
+ return equalPredicates instanceof BooleanLiteral
+ && rangePredicates instanceof BooleanLiteral
+ && residualPredicates instanceof BooleanLiteral
+ && ((BooleanLiteral) equalPredicates).getValue()
+ && ((BooleanLiteral) rangePredicates).getValue()
+ && ((BooleanLiteral) residualPredicates).getValue();
+ }
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/RelationMapping.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/RelationMapping.java
new file mode 100644
index 00000000000..ea91104a246
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/RelationMapping.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+
+import java.util.List;
+
+/**
+ * Relation mapping
+ * such as query pattern is a1 left join a2 left join b
+ * view pattern is a1 left join a2 left join b. the mapping will be
+ * [{a1:a1, a2:a2, b:b}, {a1:a2, a2:a1, b:b}]
+ */
+public class RelationMapping extends Mapping {
+
+ private final BiMap<MappedRelation, MappedRelation> mappedRelationMap;
+
+ public RelationMapping(BiMap<MappedRelation, MappedRelation>
mappedRelationMap) {
+ this.mappedRelationMap = mappedRelationMap;
+ }
+
+ public BiMap<MappedRelation, MappedRelation> getMappedRelationMap() {
+ return mappedRelationMap;
+ }
+
+ /**
+ * Generate mapping according to source and target relation
+ */
+ public static List<RelationMapping> generate(List<CatalogRelation> source,
List<CatalogRelation> target) {
+ Multimap<TableIf, CatalogRelation> queryTableRelationIdMap =
ArrayListMultimap.create();
+ for (CatalogRelation relation : source) {
+ queryTableRelationIdMap.put(relation.getTable(), relation);
+ }
+ Multimap<TableIf, CatalogRelation> viewTableRelationIdMap =
ArrayListMultimap.create();
+ for (CatalogRelation relation : target) {
+ viewTableRelationIdMap.put(relation.getTable(), relation);
+ }
+ // todo generate relation map
+ return ImmutableList.of();
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/SlotMapping.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/SlotMapping.java
new file mode 100644
index 00000000000..7c50d79c6a2
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/SlotMapping.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import com.google.common.collect.BiMap;
+
+/**
+ * SlotMapping, this is open generated from relationMapping
+ */
+public class SlotMapping extends Mapping {
+
+ private final BiMap<MappedSlot, MappedSlot> relationSlotMap;
+
+ public SlotMapping(BiMap<MappedSlot, MappedSlot> relationSlotMap) {
+ this.relationSlotMap = relationSlotMap;
+ }
+
+ public BiMap<MappedSlot, MappedSlot> getRelationSlotMap() {
+ return relationSlotMap;
+ }
+
+ public SlotMapping inverse() {
+ return SlotMapping.of(relationSlotMap.inverse());
+ }
+
+ public static SlotMapping of(BiMap<MappedSlot, MappedSlot>
relationSlotMap) {
+ return new SlotMapping(relationSlotMap);
+ }
+
+ public static SlotMapping generate(RelationMapping relationMapping) {
+ // TODO implement
+ return SlotMapping.of(null);
+ }
+}
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
new file mode 100644
index 00000000000..141b8a98bcc
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.rules.exploration.mv.Predicates.SplitPredicate;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import java.util.List;
+
+/**
+ * StructInfo
+ */
+public class StructInfo {
+ private final List<CatalogRelation> relations;
+ private final Predicates predicates;
+ // Used by predicate compensation
+ private final EquivalenceClass equivalenceClass;
+ private final Plan originalPlan;
+ private final HyperGraph hyperGraph;
+
+ private StructInfo(List<CatalogRelation> relations,
+ Predicates predicates,
+ Plan originalPlan,
+ HyperGraph hyperGraph) {
+ this.relations = relations;
+ this.predicates = predicates;
+ this.originalPlan = originalPlan;
+ this.hyperGraph = hyperGraph;
+ // construct equivalenceClass according to equals predicates
+ this.equivalenceClass = new EquivalenceClass();
+ SplitPredicate splitPredicate =
Predicates.splitPredicates(predicates.composedExpression());
+ for (Expression expression :
ExpressionUtils.extractConjunction(splitPredicate.getEqualPredicates())) {
+ EqualTo equalTo = (EqualTo) expression;
+ equivalenceClass.addEquivalenceClass(
+ (SlotReference) equalTo.getArguments().get(0),
+ (SlotReference) equalTo.getArguments().get(1));
+ }
+ }
+
+ public static StructInfo of(Plan originalPlan) {
+ // TODO build graph from original plan and get relations and
predicates from graph
+ return new StructInfo(null, null, originalPlan, null);
+ }
+
+ public static StructInfo of(Group group) {
+ // TODO build graph from original plan and get relations and
predicates from graph
+ return new StructInfo(null, null,
group.getLogicalExpression().getPlan(), null);
+ }
+
+ public List<CatalogRelation> getRelations() {
+ return relations;
+ }
+
+ public Predicates getPredicates() {
+ return predicates;
+ }
+
+ public EquivalenceClass getEquivalenceClass() {
+ return equivalenceClass;
+ }
+
+ public Plan getOriginalPlan() {
+ return originalPlan;
+ }
+
+ public HyperGraph getHyperGraph() {
+ return hyperGraph;
+ }
+
+ public List<? extends Expression> getExpressions() {
+ return originalPlan instanceof LogicalProject
+ ? ((LogicalProject<Plan>) originalPlan).getProjects() :
originalPlan.getOutput();
+ }
+
+ /**
+ * Judge the source graph logical is whether the same as target
+ * For inner join should judge only the join tables,
+ * for other join type should also judge the join direction, it's input
filter that can not be pulled up etc.
+ * */
+ public static boolean isGraphLogicalEquals(HyperGraph source, HyperGraph
target) {
+ return false;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java
index 513da0e93d9..86949f63e16 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java
@@ -17,9 +17,16 @@
package org.apache.doris.nereids.trees.expressions.visitor;
+import org.apache.doris.nereids.rules.exploration.mv.Predicates;
+import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.WindowExpression;
import
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* This is the factory for all ExpressionVisitor instance.
@@ -54,4 +61,46 @@ public class ExpressionVisitors {
return true;
}
}
+
+ /**
+ * Split the expression to equal, range and residual predicate.
+ * Should instance when used.
+ */
+ public static class PredicatesSpliter extends
DefaultExpressionVisitor<Void, Void> {
+
+ private List<Expression> equalPredicates = new ArrayList<>();
+ private List<Expression> rangePredicates = new ArrayList<>();
+ private List<Expression> residualPredicates = new ArrayList<>();
+ private final Expression target;
+
+ public PredicatesSpliter(Expression target) {
+ this.target = target;
+ }
+
+ @Override
+ public Void visitComparisonPredicate(ComparisonPredicate
comparisonPredicate, Void context) {
+ // TODO Smallest implement, complete later
+ if (comparisonPredicate instanceof EqualTo) {
+ Expression leftArgument = comparisonPredicate.getArgument(0);
+ Expression rightArgument = comparisonPredicate.getArgument(1);
+ if (leftArgument.isSlot() && rightArgument.isSlot()) {
+ equalPredicates.add(comparisonPredicate);
+ } else {
+ rangePredicates.add(comparisonPredicate);
+ }
+ }
+ return super.visit(comparisonPredicate, context);
+ }
+
+ public Expression getTarget() {
+ return target;
+ }
+
+ public Predicates.SplitPredicate getSplitPredicate() {
+ return Predicates.SplitPredicate.of(
+ equalPredicates.isEmpty() ? null :
ExpressionUtils.and(equalPredicates),
+ rangePredicates.isEmpty() ? null :
ExpressionUtils.and(rangePredicates),
+ residualPredicates.isEmpty() ? null :
ExpressionUtils.and(residualPredicates));
+ }
+ }
}
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 0c5faa20957..4793395cfe3 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
@@ -17,7 +17,9 @@
package org.apache.doris.nereids.util;
+import org.apache.doris.catalog.TableIf.TableType;
import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.exploration.mv.SlotMapping;
import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule;
import org.apache.doris.nereids.trees.TreeNode;
@@ -39,6 +41,7 @@ import
org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import
org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
+import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -196,6 +199,31 @@ public class ExpressionUtils {
.orElse(BooleanLiteral.of(type == And.class));
}
+ /**
+ * Replace the slot in expression with the lineage identifier from
specified
+ * baseTable sets or target table types.
+ * <p>
+ * For example as following:
+ * select a + 10 as a1, d from (
+ * select b - 5 as a, d from table
+ * );
+ * after shuttle a1, d in select will be b - 5 + 10, d
+ */
+ public static List<? extends Expression>
shuttleExpressionWithLineage(List<? extends Expression> expression,
+ Plan plan,
+ Set<TableType> targetTypes,
+ Set<String> tableIdentifiers) {
+ return ImmutableList.of();
+ }
+
+ /**
+ * Replace the slot in expressions according to the slotMapping
+ * if any slot cannot be mapped then return null
+ */
+ public static List<? extends Expression> permute(List<? extends
Expression> expressions, SlotMapping slotMapping) {
+ return ImmutableList.of();
+ }
+
/**
* Choose the minimum slot from input parameter.
*/
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index 00432fd8af6..c07b8df6c19 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -451,6 +451,12 @@ public class SessionVariable implements Serializable,
Writable {
public static final String TABLE_STATS_HEALTH_THRESHOLD
= "table_stats_health_threshold";
+ public static final String ENABLE_MATERIALIZED_VIEW_REWRITE
+ = "enable_materialized_view_rewrite";
+
+ public static final String
MATERIALIZED_VIEW_REWRITE_ENABLE_CONTAIN_FOREIGN_TABLE
+ = "materialized_view_rewrite_enable_contain_foreign_table";
+
public static final List<String> DEBUG_VARIABLES = ImmutableList.of(
SKIP_DELETE_PREDICATE,
SKIP_DELETE_BITMAP,
@@ -1369,6 +1375,17 @@ public class SessionVariable implements Serializable,
Writable {
+ "considered outdated."})
public int tableStatsHealthThreshold = 60;
+ @VariableMgr.VarAttr(name = ENABLE_MATERIALIZED_VIEW_REWRITE, needForward
= true,
+ description = {"是否开启基于结构信息的物化视图透明改写",
+ "Whether to enable materialized view rewriting based on
struct info"})
+ public boolean enableMaterializedViewRewrite = false;
+
+ @VariableMgr.VarAttr(name =
MATERIALIZED_VIEW_REWRITE_ENABLE_CONTAIN_FOREIGN_TABLE, needForward = true,
+ description = {"基于结构信息的透明改写,是否使用包含外表的物化视图",
+ "whether to use a materialized view that contains the
foreign table "
+ + "when using rewriting based on struct info"})
+ public boolean materializedViewRewriteEnableContainForeignTable = false;
+
public static final String IGNORE_RUNTIME_FILTER_IDS =
"ignore_runtime_filter_ids";
public Set<Integer> getIgnoredRuntimeFilterIds() {
@@ -2956,4 +2973,12 @@ public class SessionVariable implements Serializable,
Writable {
public boolean isEnableInsertGroupCommit() {
return enableInsertGroupCommit ||
Config.wait_internal_group_commit_finish;
}
+
+ public boolean isEnableMaterializedViewRewrite() {
+ return enableMaterializedViewRewrite;
+ }
+
+ public boolean isMaterializedViewRewriteEnableContainForeignTable() {
+ return materializedViewRewriteEnableContainForeignTable;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]