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 40dbb5998df [feat](Nereids) Add support for slot pruning in functional 
dependencies (#37045)
40dbb5998df is described below

commit 40dbb5998df09bc002c8bd8f4c56c86d8c2c90ae
Author: 谢健 <jianx...@gmail.com>
AuthorDate: Tue Jul 2 17:21:20 2024 +0800

    [feat](Nereids) Add support for slot pruning in functional dependencies 
(#37045)
    
    Implement slot pruning functionality for functional dependencies to
    optimize performance and resource utilization. This enhancement allows
    for more efficient handling of dependencies by removing unnecessary
    slots.
---
 .../apache/doris/nereids/properties/DataTrait.java |  2 +
 .../apache/doris/nereids/properties/FuncDeps.java  |  6 ++-
 .../doris/nereids/properties/FuncDepsDG.java       | 47 +++++++++++++++++
 .../rewrite/PushDownAggThroughJoinOnPkFk.java      |  7 +--
 .../nereids/trees/plans/logical/LogicalPlan.java   |  7 +++
 .../trees/plans/logical/LogicalProject.java        |  3 --
 .../doris/nereids/util/ImmutableEqualSet.java      | 23 +++++++++
 .../doris/nereids/properties/FuncDepsDGTest.java   | 43 ++++++++++++++++
 .../doris/nereids/util/ImmutableEqualSetTest.java  | 59 ++++++++++++++++++++++
 9 files changed, 190 insertions(+), 7 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/DataTrait.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/DataTrait.java
index 3a74f58b328..1d5210a1e6a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/DataTrait.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/DataTrait.java
@@ -317,6 +317,8 @@ public class DataTrait {
         public void pruneSlots(Set<Slot> outputSlots) {
             uniformSet.removeNotContain(outputSlots);
             uniqueSet.removeNotContain(outputSlots);
+            equalSetBuilder.removeNotContain(outputSlots);
+            fdDgBuilder.removeNotContain(outputSlots);
         }
 
         public void replace(Map<Slot, Slot> replaceMap) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDeps.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDeps.java
index be7b0853605..e637af8982c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDeps.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDeps.java
@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
  * Function dependence items.
  */
 public class FuncDeps {
-    class FuncDepsItem {
+    static class FuncDepsItem {
         final Set<Slot> determinants;
         final Set<Slot> dependencies;
 
@@ -165,6 +165,10 @@ public class FuncDeps {
                 && items.contains(new FuncDepsItem(dependency, dominate));
     }
 
+    public Set<FuncDeps.FuncDepsItem> getItems() {
+        return items;
+    }
+
     /**
      * find the determinants of dependencies
      */
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDepsDG.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDepsDG.java
index 1245762ee29..a6637f09768 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDepsDG.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/FuncDepsDG.java
@@ -150,6 +150,53 @@ public class FuncDepsDG {
             return new FuncDepsDG(ImmutableMap.copyOf(itemMap), 
ImmutableList.copyOf(dgItems));
         }
 
+        public void removeNotContain(Set<Slot> validSlot) {
+            FuncDeps funcDeps = findValidFuncDeps(validSlot);
+            dgItems.clear();
+            itemMap.clear();
+            for (FuncDeps.FuncDepsItem item : funcDeps.getItems()) {
+                this.addDeps(item.determinants, item.dependencies);
+            }
+        }
+
+        /**
+         * Finds all functional dependencies that are applicable to a given 
set of valid slots.
+         */
+        public FuncDeps findValidFuncDeps(Set<Slot> validSlot) {
+            FuncDeps res = new FuncDeps();
+            for (Entry<Set<Slot>, Integer> entry : itemMap.entrySet()) {
+                if (validSlot.containsAll(entry.getKey())) {
+                    Set<DGItem> visited = new HashSet<>();
+                    Set<DGItem> children = new HashSet<>();
+                    DGItem dgItem = dgItems.get(entry.getValue());
+                    visited.add(dgItem);
+                    collectAllChildren(validSlot, dgItem, visited, children);
+                    for (DGItem child : children) {
+                        res.addFuncItems(dgItem.slots, child.slots);
+                    }
+                }
+            }
+            return res;
+        }
+
+        /**
+         * Helper method to recursively collect all child nodes of a given 
root node
+         * that are valid according to the specified slots.
+         */
+        private void collectAllChildren(Set<Slot> validSlot, DGItem root,
+                Set<DGItem> visited, Set<DGItem> children) {
+            for (int childIdx : root.children) {
+                DGItem child = dgItems.get(childIdx);
+                if (!visited.contains(child)) {
+                    if (validSlot.containsAll(child.slots)) {
+                        children.add(child);
+                    }
+                    visited.add(child);
+                    collectAllChildren(validSlot, child, visited, children);
+                }
+            }
+        }
+
         public void addDeps(Set<Slot> dominant, Set<Slot> dependency) {
             DGItem dominateItem = getOrCreateNode(dominant);
             DGItem dependencyItem = getOrCreateNode(dependency);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownAggThroughJoinOnPkFk.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownAggThroughJoinOnPkFk.java
index 0fb3ed11562..827f0819637 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownAggThroughJoinOnPkFk.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownAggThroughJoinOnPkFk.java
@@ -98,7 +98,8 @@ public class PushDownAggThroughJoinOnPkFk implements 
RewriteRuleFactory {
             if (primaryAndForeign == null) {
                 continue;
             }
-            LogicalAggregate<?> newAgg = eliminatePrimaryOutput(agg, 
primaryAndForeign.first, primaryAndForeign.second);
+            LogicalAggregate<?> newAgg =
+                    eliminatePrimaryOutput(agg, subJoin, 
primaryAndForeign.first, primaryAndForeign.second);
             if (newAgg == null) {
                 return null;
             }
@@ -114,7 +115,7 @@ public class PushDownAggThroughJoinOnPkFk implements 
RewriteRuleFactory {
     }
 
     // eliminate the slot of primary plan in agg
-    private LogicalAggregate<?> eliminatePrimaryOutput(LogicalAggregate<?> agg,
+    private LogicalAggregate<?> eliminatePrimaryOutput(LogicalAggregate<?> 
agg, Plan child,
             Plan primary, Plan foreign) {
         Set<Slot> aggInputs = agg.getInputSlots();
         if (primary.getOutputSet().stream().noneMatch(aggInputs::contains)) {
@@ -122,7 +123,7 @@ public class PushDownAggThroughJoinOnPkFk implements 
RewriteRuleFactory {
         }
         Set<Slot> primaryOutputSet = primary.getOutputSet();
         Set<Slot> primarySlots = Sets.intersection(aggInputs, 
primaryOutputSet);
-        DataTrait dataTrait = agg.child().getLogicalProperties().getTrait();
+        DataTrait dataTrait = child.getLogicalProperties().getTrait();
         FuncDeps funcDeps = 
dataTrait.getAllValidFuncDeps(Sets.union(foreign.getOutputSet(), 
primary.getOutputSet()));
         HashMap<Slot, Slot> primaryToForeignDeps = new HashMap<>();
         for (Slot slot : primarySlots) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
index 89a0ef658ba..2e1c580ca5f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
@@ -88,6 +88,13 @@ public interface LogicalPlan extends Plan {
             fdBuilder.addUniformByEqualSet(validEqualSet);
             fdBuilder.addUniqueByEqualSet(validEqualSet);
         }
+        Set<Slot> output = this.getOutputSet();
+        for (Plan child : children()) {
+            if (!output.containsAll(child.getOutputSet())) {
+                fdBuilder.pruneSlots(output);
+                break;
+            }
+        }
         return fdBuilder.build();
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
index 2440c6c3c50..1a7f3e2dead 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
@@ -233,7 +233,6 @@ public class LogicalProject<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHILD_
                 }
             }
         }
-        builder.pruneSlots(getOutputSet());
     }
 
     @Override
@@ -252,7 +251,6 @@ public class LogicalProject<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHILD_
                 }
             }
         }
-        builder.pruneSlots(getOutputSet());
     }
 
     @Override
@@ -270,7 +268,6 @@ public class LogicalProject<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHILD_
                 }
             }
         }
-        builder.pruneSlots(getOutputSet());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEqualSet.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEqualSet.java
index c8aaf60ab0b..72d7ffce2b4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEqualSet.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEqualSet.java
@@ -20,7 +20,9 @@ package org.apache.doris.nereids.util;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -71,6 +73,27 @@ public class ImmutableEqualSet<T> {
             parent = newMap;
         }
 
+        /**
+         * Remove all not contain in containSet
+         * @param containSet the set to contain
+         */
+        public void removeNotContain(Set<T> containSet) {
+            List<Set<T>> equalSetList = calEqualSetList();
+            this.parent.clear();
+            for (Set<T> equalSet : equalSetList) {
+                Set<T> intersect = Sets.intersection(containSet, equalSet);
+                if (intersect.size() <= 1) {
+                    continue;
+                }
+                Iterator<T> iterator = intersect.iterator();
+                T first = intersect.iterator().next();
+                while (iterator.hasNext()) {
+                    T next = iterator.next();
+                    this.addEqualPair(first, next);
+                }
+            }
+        }
+
         /**
          * Add a equal pair
          */
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/FuncDepsDGTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/FuncDepsDGTest.java
index a20085897da..e92fa31abec 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/FuncDepsDGTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/FuncDepsDGTest.java
@@ -73,4 +73,47 @@ class FuncDepsDGTest {
         FuncDeps res = dg.build().findValidFuncDeps(Sets.newHashSet(s1, s4, 
s3));
         Assertions.assertEquals(2, res.size());
     }
+
+    @Test
+    void testPruneTrans() {
+        FuncDepsDG.Builder dg = new FuncDepsDG.Builder();
+        Slot s1 = new SlotReference("s1", IntegerType.INSTANCE);
+        Slot s2 = new SlotReference("s2", IntegerType.INSTANCE);
+        Slot s3 = new SlotReference("s3", IntegerType.INSTANCE);
+        dg.addDeps(Sets.newHashSet(s1), Sets.newHashSet(s2));
+        dg.addDeps(Sets.newHashSet(s2), Sets.newHashSet(s3));
+        dg.removeNotContain(Sets.newHashSet(s1, s3));
+        FuncDeps res = dg.build().findValidFuncDeps(Sets.newHashSet(s1, s3));
+        System.out.println(res);
+        Assertions.assertEquals(1, res.size());
+    }
+
+    @Test
+    void testPruneCircle() {
+        FuncDepsDG.Builder dg = new FuncDepsDG.Builder();
+        Slot s1 = new SlotReference("s1", IntegerType.INSTANCE);
+        Slot s2 = new SlotReference("s2", IntegerType.INSTANCE);
+        Slot s3 = new SlotReference("s3", IntegerType.INSTANCE);
+        dg.addDeps(Sets.newHashSet(s1), Sets.newHashSet(s2));
+        dg.addDeps(Sets.newHashSet(s2), Sets.newHashSet(s3));
+        dg.addDeps(Sets.newHashSet(s3), Sets.newHashSet(s1));
+        dg.removeNotContain(Sets.newHashSet(s1, s3));
+        FuncDeps res = dg.build().findValidFuncDeps(Sets.newHashSet(s1, s3));
+        Assertions.assertEquals(2, res.size());
+    }
+
+    @Test
+    void testPruneTree() {
+        FuncDepsDG.Builder dg = new FuncDepsDG.Builder();
+        Slot s1 = new SlotReference("s1", IntegerType.INSTANCE);
+        Slot s2 = new SlotReference("s2", IntegerType.INSTANCE);
+        Slot s3 = new SlotReference("s3", IntegerType.INSTANCE);
+        Slot s4 = new SlotReference("s4", IntegerType.INSTANCE);
+        dg.addDeps(Sets.newHashSet(s1), Sets.newHashSet(s2));
+        dg.addDeps(Sets.newHashSet(s2), Sets.newHashSet(s3));
+        dg.addDeps(Sets.newHashSet(s2), Sets.newHashSet(s4));
+        dg.removeNotContain(Sets.newHashSet(s1, s4, s3));
+        FuncDeps res = dg.build().findValidFuncDeps(Sets.newHashSet(s1, s4, 
s3));
+        Assertions.assertEquals(2, res.size());
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ImmutableEqualSetTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ImmutableEqualSetTest.java
new file mode 100644
index 00000000000..9942813d377
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ImmutableEqualSetTest.java
@@ -0,0 +1,59 @@
+// 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.util;
+
+import com.google.common.collect.Sets;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ImmutableEqualSetTest {
+    @Test
+    void testRemoveCircle() {
+        ImmutableEqualSet.Builder<Integer> builder = new 
ImmutableEqualSet.Builder<>();
+        builder.addEqualPair(1, 2);
+        builder.addEqualPair(2, 3);
+        builder.addEqualPair(3, 1);
+        builder.removeNotContain(Sets.newHashSet(1, 3));
+        ImmutableEqualSet<Integer> e = builder.build();
+        Assertions.assertTrue(e.isEqual(1, 3));
+    }
+
+    @Test
+    void testRemoveInTree() {
+        ImmutableEqualSet.Builder<Integer> builder = new 
ImmutableEqualSet.Builder<>();
+        builder.addEqualPair(1, 2);
+        builder.addEqualPair(2, 3);
+        builder.addEqualPair(2, 4);
+        builder.removeNotContain(Sets.newHashSet(1, 3, 4));
+        ImmutableEqualSet<Integer> e = builder.build();
+        Assertions.assertTrue(e.isEqual(3, 4));
+        Assertions.assertTrue(e.isEqual(1, 3));
+        Assertions.assertTrue(e.isEqual(1, 4));
+    }
+
+    @Test
+    void testRemoveInTrans() {
+        ImmutableEqualSet.Builder<Integer> builder = new 
ImmutableEqualSet.Builder<>();
+        builder.addEqualPair(1, 2);
+        builder.addEqualPair(2, 3);
+        builder.addEqualPair(3, 4);
+        builder.removeNotContain(Sets.newHashSet(1, 4));
+        ImmutableEqualSet<Integer> e = builder.build();
+        Assertions.assertTrue(e.isEqual(1, 4));
+    }
+}


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

Reply via email to