This is an automated email from the ASF dual-hosted git repository.

jakevin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new dbccbe0fbba [feat](Nereids): add struct info map in group (#31800)
dbccbe0fbba is described below

commit dbccbe0fbbaaa6550eee7b3234c15910615c63a5
Author: 谢健 <jianx...@gmail.com>
AuthorDate: Wed Mar 6 16:49:04 2024 +0800

    [feat](Nereids): add struct info map in group (#31800)
---
 .../org/apache/doris/mtmv/MTMVRelationManager.java |  10 +-
 .../java/org/apache/doris/nereids/memo/Group.java  |   7 +-
 .../apache/doris/nereids/memo/StructInfoMap.java   | 123 +++++++++++++++++++++
 .../mv/InitMaterializationContextHook.java         |   7 +-
 .../doris/nereids/memo/StructInfoMapTest.java      |  81 ++++++++++++++
 .../org/apache/doris/nereids/util/PlanChecker.java |   2 +
 .../apache/doris/utframe/TestWithFeService.java    |  28 +++++
 7 files changed, 252 insertions(+), 6 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java 
b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
index aa7ffd2426d..723deaff740 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
@@ -35,6 +35,7 @@ import 
org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo;
 import org.apache.doris.persist.AlterMTMV;
 import org.apache.doris.qe.ConnectContext;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -71,8 +72,7 @@ public class MTMVRelationManager implements MTMVHookService {
         for (BaseTableInfo tableInfo : mvInfos) {
             try {
                 MTMV mtmv = (MTMV) MTMVUtil.getTable(tableInfo);
-                if (!CollectionUtils
-                        
.isEmpty(MTMVRewriteUtil.getMTMVCanRewritePartitions(mtmv, ctx, 
System.currentTimeMillis()))) {
+                if (isMVPartitionValid(mtmv, ctx)) {
                     res.add(mtmv);
                 }
             } catch (AnalysisException e) {
@@ -83,6 +83,12 @@ public class MTMVRelationManager implements MTMVHookService {
         return res;
     }
 
+    @VisibleForTesting
+    public boolean isMVPartitionValid(MTMV mtmv, ConnectContext ctx) {
+        return !CollectionUtils
+                .isEmpty(MTMVRewriteUtil.getMTMVCanRewritePartitions(mtmv, 
ctx, System.currentTimeMillis()));
+    }
+
     private Set<BaseTableInfo> getMTMVInfos(List<BaseTableInfo> tableInfos) {
         Set<BaseTableInfo> mvInfos = Sets.newHashSet();
         for (BaseTableInfo tableInfo : tableInfos) {
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 2a0e83c72a4..5a5abd56f95 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
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.memo;
 
 import org.apache.doris.common.Pair;
 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;
@@ -78,6 +77,8 @@ public class Group {
 
     private List<StructInfo> structInfos = new ArrayList<>();
 
+    private StructInfoMap structInfoMap = new StructInfoMap();
+
     /**
      * Constructor for Group.
      *
@@ -418,8 +419,8 @@ public class Group {
         return false;
     }
 
-    public List<HyperGraph> getHyperGraphs() {
-        return new ArrayList<>();
+    public StructInfoMap getstructInfoMap() {
+        return structInfoMap;
     }
 
     public boolean isProjectGroup() {
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
new file mode 100644
index 00000000000..f7e09fd44d9
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/StructInfoMap.java
@@ -0,0 +1,123 @@
+// 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.memo;
+
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
+
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * Representation for group in cascades optimizer.
+ */
+public class StructInfoMap {
+    private final Map<BitSet, GroupExpression> groupExpressionMap = new 
HashMap<>();
+    private final Map<BitSet, StructInfo> infoMap = new HashMap<>();
+
+    /**
+     * get struct info according to table map
+     * @param mvTableMap the original table map
+     * @param foldTableMap the fold table map
+     * @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) {
+        if (!infoMap.containsKey(mvTableMap)) {
+            if ((groupExpressionMap.containsKey(foldTableMap) || 
groupExpressionMap.isEmpty())
+                    && !groupExpressionMap.containsKey(mvTableMap)) {
+                refresh(group);
+            }
+            if (groupExpressionMap.containsKey(mvTableMap)) {
+                StructInfo structInfo = 
constructStructInfo(groupExpressionMap.get(mvTableMap));
+                infoMap.put(mvTableMap, structInfo);
+            }
+        }
+
+        return infoMap.get(mvTableMap);
+    }
+
+    public Set<BitSet> getTableMaps() {
+        return groupExpressionMap.keySet();
+    }
+
+    private StructInfo constructStructInfo(GroupExpression groupExpression) {
+        throw new RuntimeException("has not been implemented for" + 
groupExpression);
+    }
+
+    /**
+     * refresh group expression map
+     * @param group the root group
+     */
+    public void refresh(Group group) {
+        List<Set<BitSet>> childrenTableMap = new ArrayList<>();
+        Set<Group> refreshedGroup = new HashSet<>();
+        for (GroupExpression groupExpression : group.getLogicalExpressions()) {
+            if (groupExpression.children().isEmpty()) {
+                groupExpressionMap.put(constructLeaf(groupExpression), 
groupExpression);
+                continue;
+            }
+            for (Group child : groupExpression.children()) {
+                if (!refreshedGroup.contains(child)) {
+                    StructInfoMap childStructInfoMap = 
child.getstructInfoMap();
+                    childStructInfoMap.refresh(child);
+                }
+                refreshedGroup.add(child);
+                childrenTableMap.add(child.getstructInfoMap().getTableMaps());
+            }
+            Set<BitSet> bitSets = cartesianProduct(childrenTableMap);
+            for (BitSet bitSet : bitSets) {
+                groupExpressionMap.put(bitSet, groupExpression);
+            }
+        }
+    }
+
+    private BitSet constructLeaf(GroupExpression groupExpression) {
+        Plan plan = groupExpression.getPlan();
+        BitSet tableMap = new BitSet();
+        if (plan instanceof LogicalCatalogRelation) {
+            // TODO: Bitmap is not compatible with long, use tree map instead
+            tableMap.set((int) ((LogicalCatalogRelation) 
plan).getTable().getId());
+        }
+        // one row relation / CTE consumer
+        return tableMap;
+    }
+
+    private Set<BitSet> cartesianProduct(List<Set<BitSet>> childrenTableMap) {
+        return Sets.cartesianProduct(childrenTableMap)
+                .stream()
+                .map(bitSetList -> {
+                    BitSet bitSet = new BitSet();
+                    for (BitSet b : bitSetList) {
+                        bitSet.or(b);
+                    }
+                    return bitSet;
+                })
+                .collect(Collectors.toSet());
+    }
+}
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 baf714fe280..8046639d1ba 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
@@ -32,6 +32,7 @@ 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;
@@ -56,7 +57,11 @@ public class InitMaterializationContextHook implements 
PlannerHook {
         initMaterializationContext(planner.getCascadesContext());
     }
 
-    private void initMaterializationContext(CascadesContext cascadesContext) {
+    /**
+     * init materialization context
+     */
+    @VisibleForTesting
+    public void initMaterializationContext(CascadesContext cascadesContext) {
         if 
(!cascadesContext.getConnectContext().getSessionVariable().isEnableMaterializedViewRewrite())
 {
             return;
         }
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
new file mode 100644
index 00000000000..0699f04b92f
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/StructInfoMapTest.java
@@ -0,0 +1,81 @@
+// 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.memo;
+
+import org.apache.doris.catalog.MTMV;
+import org.apache.doris.mtmv.MTMVRelationManager;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.sqltest.SqlTestBase;
+import org.apache.doris.nereids.util.PlanChecker;
+import org.apache.doris.qe.ConnectContext;
+
+import mockit.Mock;
+import mockit.MockUp;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.BitSet;
+import java.util.Set;
+
+class StructInfoMapTest extends SqlTestBase {
+    @Test
+    void testTableMap() throws Exception {
+        CascadesContext c1 = createCascadesContext(
+                "select T1.id from T1 inner join T2 "
+                        + "on T1.id = T2.id "
+                        + "inner join T3 on T1.id = T3.id",
+                connectContext
+        );
+        PlanChecker.from(c1)
+                .analyze()
+                .rewrite()
+                .optimize();
+        Group root = c1.getMemo().getRoot();
+        Set<BitSet> tableMaps = root.getstructInfoMap().getTableMaps();
+        Assertions.assertTrue(tableMaps.isEmpty());
+        root.getstructInfoMap().refresh(root);
+        Assertions.assertEquals(1, tableMaps.size());
+        new MockUp<MTMVRelationManager>() {
+            @Mock
+            public boolean isMVPartitionValid(MTMV mtmv, ConnectContext ctx) {
+                return true;
+            }
+        };
+        connectContext.getSessionVariable().enableMaterializedViewRewrite = 
true;
+        createMvByNereids("create materialized view mv1 BUILD IMMEDIATE 
REFRESH COMPLETE ON MANUAL\n"
+                + "        DISTRIBUTED BY RANDOM BUCKETS 1\n"
+                + "        PROPERTIES ('replication_num' = '1') \n"
+                + "        as select T1.id from T1 inner join T2 "
+                + "on T1.id = T2.id;");
+        c1 = createCascadesContext(
+                "select T1.id from T1 inner join T2 "
+                        + "on T1.id = T2.id "
+                        + "inner join T3 on T1.id = T3.id",
+                connectContext
+        );
+        PlanChecker.from(c1)
+                .analyze()
+                .rewrite()
+                .optimize()
+                .printlnBestPlanTree();
+        root = c1.getMemo().getRoot();
+        root.getstructInfoMap().refresh(root);
+        tableMaps = root.getstructInfoMap().getTableMaps();
+        Assertions.assertEquals(2, tableMaps.size());
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
index 0c6cc0e577e..9471e18f6a5 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
@@ -49,6 +49,7 @@ import org.apache.doris.nereids.rules.RuleFactory;
 import org.apache.doris.nereids.rules.RuleSet;
 import org.apache.doris.nereids.rules.RuleType;
 import 
org.apache.doris.nereids.rules.analysis.BindRelation.CustomTableResolver;
+import 
org.apache.doris.nereids.rules.exploration.mv.InitMaterializationContextHook;
 import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -121,6 +122,7 @@ public class PlanChecker {
     public PlanChecker analyze() {
         this.cascadesContext.newAnalyzer().analyze();
         this.cascadesContext.toMemo();
+        
InitMaterializationContextHook.INSTANCE.initMaterializationContext(this.cascadesContext);
         return this;
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java 
b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
index 58b55f0a7b5..7de8a9a830b 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
@@ -58,6 +58,7 @@ import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.util.SqlParserUtils;
 import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.job.base.AbstractJob;
 import org.apache.doris.nereids.CascadesContext;
 import org.apache.doris.nereids.StatementContext;
 import org.apache.doris.nereids.glue.LogicalPlanAdapter;
@@ -65,10 +66,13 @@ import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
 import org.apache.doris.nereids.trees.plans.commands.AddConstraintCommand;
+import org.apache.doris.nereids.trees.plans.commands.CreateMTMVCommand;
 import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
 import org.apache.doris.nereids.trees.plans.commands.DropConstraintCommand;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.util.MemoTestUtils;
+import org.apache.doris.persist.CreateTableInfo;
+import org.apache.doris.persist.EditLog;
 import org.apache.doris.planner.Planner;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.DdlExecutor;
@@ -795,6 +799,30 @@ public abstract class TestWithFeService {
         Thread.sleep(100);
     }
 
+    protected void createMvByNereids(String sql) throws Exception {
+        new MockUp<EditLog>() {
+            @Mock
+            public void logCreateTable(CreateTableInfo info) {
+                System.out.println("skip log create table...");
+            }
+
+            @Mock
+            public void logCreateJob(AbstractJob job) {
+                System.out.println("skip log create job...");
+            }
+        };
+        NereidsParser nereidsParser = new NereidsParser();
+        LogicalPlan parsed = nereidsParser.parseSingle(sql);
+        StmtExecutor stmtExecutor = new StmtExecutor(connectContext, sql);
+        if (parsed instanceof CreateMTMVCommand) {
+            ((CreateMTMVCommand) parsed).run(connectContext, stmtExecutor);
+        }
+        checkAlterJob();
+        // waiting table state to normal
+        Thread.sleep(1000);
+
+    }
+
     private void updateReplicaPathHash() {
         com.google.common.collect.Table<Long, Long, Replica> replicaMetaTable 
= Env.getCurrentInvertedIndex()
                 .getReplicaMetaTable();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to