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

chenyz pushed a commit to branch rel/1.2
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/1.2 by this push:
     new 47dc350609c Implement intersect with prefix pattern for PartialPath 
and PathPatternTree (#10909)
47dc350609c is described below

commit 47dc350609cba837e94c676c378c018a012c377a
Author: Chen YZ <[email protected]>
AuthorDate: Mon Aug 21 09:06:12 2023 +0800

    Implement intersect with prefix pattern for PartialPath and PathPatternTree 
(#10909)
---
 .../org/apache/iotdb/commons/path/PartialPath.java | 158 +++++++++++++++------
 .../iotdb/commons/path/PathPatternTreeUtils.java   |  53 +++++++
 .../apache/iotdb/commons/path/PathPatternUtil.java |   4 +-
 .../apache/iotdb/commons/path/PartialPathTest.java |  68 +++++++++
 .../iotdb/commons/path/PathPatternTreeTest.java    | 121 ++++++++++++++++
 5 files changed, 362 insertions(+), 42 deletions(-)

diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
index af0d037df33..1e7bbb0a324 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
@@ -29,6 +29,7 @@ import org.apache.iotdb.tsfile.utils.PublicBAOS;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.Validate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,6 +53,7 @@ import static 
org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCAR
 public class PartialPath extends Path implements Comparable<Path>, Cloneable {
 
   private static final Logger logger = 
LoggerFactory.getLogger(PartialPath.class);
+  private static final PartialPath ALL_MATCH_PATTERN = new PartialPath(new 
String[] {"root", "**"});
 
   protected String[] nodes;
 
@@ -116,14 +118,17 @@ public class PartialPath extends Path implements 
Comparable<Path>, Cloneable {
 
   public boolean hasMultiLevelMatchWildcard() {
     for (String node : nodes) {
-      // *, ** , d*, *d*
-      if (PathPatternUtil.hasMultiLevelMatchWildcard(node)) {
+      if (PathPatternUtil.isMultiLevelMatchWildcard(node)) {
         return true;
       }
     }
     return false;
   }
 
+  public boolean endWithMultiLevelWildcard() {
+    return PathPatternUtil.isMultiLevelMatchWildcard(nodes[nodes.length - 1]);
+  }
+
   // e.g. root.db.d.s, root.db.d.*, root.db.d.s*, not include patterns like 
root.db.d.**
   public boolean hasExplicitDevice() {
     if (nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
@@ -492,6 +497,62 @@ public class PartialPath extends Path implements 
Comparable<Path>, Cloneable {
     return this.nodes.length == rNodes.length;
   }
 
+  /**
+   * Try to check overlap between nodes1 and nodes2 with 
MULTI_LEVEL_PATH_WILDCARD. Time complexity
+   * O(n^2).
+   *
+   * @return true if overlapping, otherwise return false
+   */
+  private boolean checkOverlapWithMultiLevelWildcard(String[] nodes1, String[] 
nodes2) {
+    // dp[i][j] means if nodes1[0:i) and nodes[0:j) overlapping
+    boolean[][] dp = new boolean[nodes1.length + 1][nodes2.length + 1];
+    dp[0][0] = true;
+    for (int i = 1; i <= nodes1.length; i++) {
+      boolean prune = false; //
+      // prune if we've already found that these two path are never overlapped 
in the beginning
+      // steps.
+      // e.g. root.db1.**.s1 and root.db2.**.s1
+      for (int j = 1; j <= nodes2.length; j++) {
+        if (nodes1[i - 1].equals(MULTI_LEVEL_PATH_WILDCARD)
+            || nodes2[j - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+          // if encounter MULTI_LEVEL_PATH_WILDCARD
+          if (nodes1[i - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+            // if nodes1[i-1] is MULTI_LEVEL_PATH_WILDCARD, 
dp[i][k(k>=j)]=dp[i-1][j-1]
+            if (dp[i - 1][j - 1]) {
+              for (int k = j; k <= nodes2.length; k++) {
+                dp[i][k] = true;
+              }
+            }
+          }
+          if (nodes2[j - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+            // if nodes2[j-1] is MULTI_LEVEL_PATH_WILDCARD, 
dp[k(k>=i)][j]=dp[i-1][j-1]
+            if (dp[i - 1][j - 1]) {
+              for (int k = i; k <= nodes1.length; k++) {
+                dp[k][j] = true;
+              }
+            }
+          }
+        } else {
+          // if without MULTI_LEVEL_PATH_WILDCARD, scan and check
+          if ((PathPatternUtil.hasWildcard(nodes1[i - 1])
+                  && PathPatternUtil.isNodeMatch(nodes1[i - 1], nodes2[j - 1]))
+              || (PathPatternUtil.hasWildcard(nodes2[j - 1])
+                  && PathPatternUtil.isNodeMatch(nodes2[j - 1], nodes1[i - 1]))
+              || nodes1[i - 1].equals(nodes2[j - 1])) {
+            // if nodes1[i-1] and nodes[j-1] is matched, dp[i][j] = 
dp[i-1][j-1]
+            dp[i][j] |= dp[i - 1][j - 1];
+          }
+        }
+        prune |= dp[i][j];
+      }
+      if (!prune) {
+        break;
+      }
+    }
+
+    return dp[nodes1.length][nodes2.length];
+  }
+
   /**
    * Test if this path pattern overlaps with input prefix full path. Overlap 
means the result sets
    * generated by two path pattern share some common elements. e.g.
@@ -533,51 +594,68 @@ public class PartialPath extends Path implements 
Comparable<Path>, Cloneable {
   }
 
   /**
-   * Try to check overlap between nodes1 and nodes2 with 
MULTI_LEVEL_PATH_WILDCARD. Time complexity
-   * O(n^2).
+   * Generate a list of partial paths which are the intersection of this path 
pattern and input
+   * prefix pattern.
    *
-   * @return true if overlapping, otherwise return false
+   * @param prefixPattern must be a prefix full path ending with one "**", 
like "root.sg.**"
+   * @return a list of partial paths which are the intersection of this path 
pattern and input
+   *     prefix pattern.
    */
-  private boolean checkOverlapWithMultiLevelWildcard(String[] nodes1, String[] 
nodes2) {
-    // dp[i][j] means if nodes1[0:i) and nodes[0:j) overlapping
-    boolean[][] dp = new boolean[nodes1.length + 1][nodes2.length + 1];
-    dp[0][0] = true;
-    for (int i = 1; i <= nodes1.length; i++) {
-      for (int j = 1; j <= nodes2.length; j++) {
-        if (nodes1[i - 1].equals(MULTI_LEVEL_PATH_WILDCARD)
-            || nodes2[j - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
-          // if encounter MULTI_LEVEL_PATH_WILDCARD
-          if (nodes1[i - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
-            // if nodes1[i-1] is MULTI_LEVEL_PATH_WILDCARD, 
dp[i][k(k>=j)]=dp[i-1][j-1]
-            if (dp[i - 1][j - 1]) {
-              for (int k = j; k <= nodes2.length; k++) {
-                dp[i][k] = true;
-              }
-            }
-          }
-          if (nodes2[j - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
-            // if nodes2[j-1] is MULTI_LEVEL_PATH_WILDCARD, 
dp[k(k>=i)][j]=dp[i-1][j-1]
-            if (dp[i - 1][j - 1]) {
-              for (int k = i; k <= nodes1.length; k++) {
-                dp[k][j] = true;
-              }
-            }
-          }
+  public List<PartialPath> intersectWithPrefixPattern(PartialPath 
prefixPattern) {
+    if (prefixPattern.equals(ALL_MATCH_PATTERN)) {
+      return Collections.singletonList(this);
+    }
+    String[] prefixFullPath =
+        Arrays.copyOf(prefixPattern.getNodes(), prefixPattern.getNodeLength() 
- 1);
+    // init dp array
+    int thisLength = this.getNodeLength();
+    boolean[] matchIndex = new boolean[thisLength];
+    matchIndex[0] = true; // "root" must match "root"
+
+    // dp[i][j] means if nodes[0:i] matches prefixFullPath[0:j]
+    // for example: "root.**.d1.**" intersect "root.sg1.d1(.**)"
+    // dp[i][j] = (nodes[i]=="**"&&dp[i][j-1]) || (nodes[i] matches 
prefixFullPath[j]&&dp[i-1][j-1])
+    // 1 0 0 0 |→| 1 0 0 0 |→| 1 0 0 0
+    // 0 0 0 0 |↓| 0 1 0 0 |→| 0 1 0 0
+    // 0 0 0 0 |↓| 0 0 0 0 |↓| 0 1 1 0
+    // Since the derivation of the next row depends only on the previous row, 
the calculation can
+    // be performed using a one-dimensional array named "matchIndex"
+    for (int i = 1; i < prefixFullPath.length; i++) {
+      for (int j = thisLength - 1; j >= 1; j--) {
+        if (nodes[j].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+          matchIndex[j] = matchIndex[j] || matchIndex[j - 1];
+        } else if (PathPatternUtil.isNodeMatch(nodes[j], prefixFullPath[i])) {
+          matchIndex[j] = matchIndex[j - 1];
         } else {
-          // if without MULTI_LEVEL_PATH_WILDCARD, scan and check
-          if ((PathPatternUtil.hasWildcard(nodes1[i - 1])
-                  && PathPatternUtil.isNodeMatch(nodes1[i - 1], nodes2[j - 1]))
-              || (PathPatternUtil.hasWildcard(nodes2[j - 1])
-                  && PathPatternUtil.isNodeMatch(nodes2[j - 1], nodes1[i - 1]))
-              || nodes1[i - 1].equals(nodes2[j - 1])) {
-            // if nodes1[i-1] and nodes[2] is matched, dp[i][j] = dp[i-1][j-1]
-            dp[i][j] |= dp[i - 1][j - 1];
+          matchIndex[j] = false;
+        }
+      }
+    }
+    // Scan in reverse order to construct the result set.
+    // The structure of the result set is prefixFullPath+remaining nodes. 
【E.g.root.sg1.d1 + **】
+    // It can be pruned if the remaining nodes start with **.
+    List<PartialPath> res = new ArrayList<>();
+    if (matchIndex[thisLength - 1] && nodes[thisLength - 
1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+      res.add(new PartialPath(ArrayUtils.addAll(prefixFullPath, 
nodes[thisLength - 1])));
+    } else {
+      for (int j = thisLength - 2; j > 0; j--) {
+        if (matchIndex[j]) {
+          res.add(
+              new PartialPath(
+                  ArrayUtils.addAll(prefixFullPath, Arrays.copyOfRange(nodes, 
j + 1, thisLength))));
+          if (nodes[j + 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+            break;
+          }
+          if (nodes[j].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+            res.add(
+                new PartialPath(
+                    ArrayUtils.addAll(prefixFullPath, 
Arrays.copyOfRange(nodes, j, thisLength))));
+            break;
           }
         }
       }
     }
-
-    return dp[nodes1.length][nodes2.length];
+    return res;
   }
 
   @Override
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java
new file mode 100644
index 00000000000..563cedff6f6
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java
@@ -0,0 +1,53 @@
+/*
+ * 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.iotdb.commons.path;
+
+public class PathPatternTreeUtils {
+  /**
+   * Intersect the pattern tree with the full path prefix tree, and return the 
intersected pattern
+   * tree.
+   *
+   * @param patternTree any pattern tree
+   * @param fullPathPrefixTree the included pattern must be fullPath or prefix 
pattern(e.g.
+   *     root.sg.**)
+   * @return the intersected pattern tree
+   */
+  public static PathPatternTree intersectWithFullPathPrefixTree(
+      PathPatternTree patternTree, PathPatternTree fullPathPrefixTree) {
+    PathPatternTree result = new PathPatternTree();
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      for (PartialPath fullPathOrPrefix : 
fullPathPrefixTree.getAllPathPatterns()) {
+        if (fullPathOrPrefix.endWithMultiLevelWildcard()) {
+          // prefix
+          for (PartialPath temp : 
pathPattern.intersectWithPrefixPattern(fullPathOrPrefix)) {
+            result.appendPathPattern(temp);
+          }
+        } else {
+          // full path
+          if (pathPattern.matchFullPath(fullPathOrPrefix)) {
+            result.appendPathPattern(fullPathOrPrefix);
+          }
+        }
+      }
+    }
+    result.constructTree();
+    return result;
+  }
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternUtil.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternUtil.java
index 6d5b265a910..a8ba920813b 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternUtil.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternUtil.java
@@ -36,8 +36,8 @@ public class PathPatternUtil {
     return node.startsWith(ONE_LEVEL_PATH_WILDCARD) || 
node.endsWith(ONE_LEVEL_PATH_WILDCARD);
   }
 
-  public static boolean hasMultiLevelMatchWildcard(String node) {
-    return node.startsWith(ONE_LEVEL_PATH_WILDCARD);
+  public static boolean isMultiLevelMatchWildcard(String node) {
+    return MULTI_LEVEL_PATH_WILDCARD.equals(node);
   }
 
   /**
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PartialPathTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PartialPathTest.java
index 8874c34fd4e..c9917ccb8c8 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PartialPathTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PartialPathTest.java
@@ -24,7 +24,10 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import static org.junit.Assert.fail;
 
@@ -682,6 +685,71 @@ public class PartialPathTest {
     }
   }
 
+  @Test
+  public void testIntersectWithPrefixPattern() throws Exception {
+    checkIntersect(
+        new PartialPath("root.**.d*"),
+        new PartialPath("root.test.dac.device1.**"),
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.test.dac.device1.d*"));
+            add(new PartialPath("root.test.dac.device1.**.d*"));
+          }
+        });
+    checkIntersect(
+        new PartialPath("root.**.d*.**"),
+        new PartialPath("root.test.dac.device1.**"),
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.test.dac.device1.**"));
+          }
+        });
+    checkIntersect(
+        new PartialPath("root.**.d1.**"),
+        new PartialPath("root.sg1.d1.**"),
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.**"));
+          }
+        });
+    checkIntersect(
+        new PartialPath("root.**.d1.s1"),
+        new PartialPath("root.sg1.d1.**"),
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.s1"));
+            add(new PartialPath("root.sg1.d1.d1.s1"));
+            add(new PartialPath("root.sg1.d1.**.d1.s1"));
+          }
+        });
+    checkIntersect(
+        new PartialPath("root.**.d*"),
+        new PartialPath("root.sg1.d1.**"),
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.d*"));
+            add(new PartialPath("root.sg1.d1.**.d*"));
+          }
+        });
+    checkIntersect(
+        new PartialPath("root.sg1.d1"), new PartialPath("root.sg1.d1.**"), 
Collections.emptySet());
+    checkIntersect(
+        new PartialPath("root.sg1.d2.s1"),
+        new PartialPath("root.sg1.d1.**"),
+        Collections.emptySet());
+  }
+
+  private void checkIntersect(PartialPath pattern, PartialPath prefix, 
Set<PartialPath> expected) {
+    List<PartialPath> actual = pattern.intersectWithPrefixPattern(prefix);
+    for (PartialPath path : actual) {
+      if (!expected.contains(path)) {
+        System.out.println(path);
+      }
+      Assert.assertTrue(expected.remove(path));
+    }
+    Assert.assertTrue(expected.isEmpty());
+  }
+
   private void checkNodes(String[] expected, String[] actual) {
     Assert.assertEquals(expected.length, actual.length);
     for (int i = 0; i < expected.length; i++) {
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PathPatternTreeTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PathPatternTreeTest.java
index f8b3dea5acb..1566a82f75a 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PathPatternTreeTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/path/PathPatternTreeTest.java
@@ -29,7 +29,9 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 public class PathPatternTreeTest {
@@ -287,4 +289,123 @@ public class PathPatternTreeTest {
         Arrays.asList(new PartialPath("root.sg1.*.t1.s1"), new 
PartialPath("root.sg1.d1.t2.s2")),
         patternTree.getAllPathPatterns());
   }
+
+  @Test
+  public void testIntersectWithFullPathPrefixTree1() throws Exception {
+    List<PartialPath> partialPathList =
+        Arrays.asList(
+            new PartialPath("root.sg1.d1.t1.s1"),
+            new PartialPath("root.sg1.*.t1.s1"),
+            new PartialPath("root.sg1.d2.**"));
+    PathPatternTree patternTree = new PathPatternTree();
+    for (PartialPath path : partialPathList) {
+      patternTree.appendPathPattern(path);
+    }
+    patternTree.constructTree();
+
+    List<PartialPath> fullPathPrefixList =
+        Arrays.asList(
+            new PartialPath("root.sg1.d1.**"),
+            new PartialPath("root.sg1.d2.**"),
+            new PartialPath("root.sg1.d3.t1.s1"));
+    PathPatternTree fullPathPrefixTree = new PathPatternTree();
+    for (PartialPath path : fullPathPrefixList) {
+      fullPathPrefixTree.appendPathPattern(path);
+    }
+    fullPathPrefixTree.constructTree();
+
+    PathPatternTree res =
+        PathPatternTreeUtils.intersectWithFullPathPrefixTree(patternTree, 
fullPathPrefixTree);
+    Set<PartialPath> expected =
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.t1.s1"));
+            add(new PartialPath("root.sg1.d2.**"));
+            add(new PartialPath("root.sg1.d3.t1.s1"));
+          }
+        };
+    for (PartialPath path : res.getAllPathPatterns()) {
+      Assert.assertTrue(expected.remove(path));
+    }
+    Assert.assertTrue(expected.isEmpty());
+  }
+
+  @Test
+  public void testIntersectWithFullPathPrefixTree2() throws Exception {
+    List<PartialPath> partialPathList =
+        Arrays.asList(
+            new PartialPath("root.sg1.d1.t1.s1"),
+            new PartialPath("root.sg1.*.t1.s2"),
+            new PartialPath("root.**.t*.**"));
+    PathPatternTree patternTree = new PathPatternTree();
+    for (PartialPath path : partialPathList) {
+      patternTree.appendPathPattern(path);
+    }
+    patternTree.constructTree();
+
+    List<PartialPath> fullPathPrefixList =
+        Arrays.asList(new PartialPath("root.sg1.d1.**"), new 
PartialPath("root.sg1.d2.**"));
+    PathPatternTree fullPathPrefixTree = new PathPatternTree();
+    for (PartialPath path : fullPathPrefixList) {
+      fullPathPrefixTree.appendPathPattern(path);
+    }
+    fullPathPrefixTree.constructTree();
+
+    PathPatternTree res =
+        PathPatternTreeUtils.intersectWithFullPathPrefixTree(patternTree, 
fullPathPrefixTree);
+    Set<PartialPath> expected =
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.t*.**"));
+            add(new PartialPath("root.sg1.d1.**.t*.**"));
+            add(new PartialPath("root.sg1.d2.t*.**"));
+            add(new PartialPath("root.sg1.d2.**.t*.**"));
+          }
+        };
+    for (PartialPath path : res.getAllPathPatterns()) {
+      Assert.assertTrue(expected.remove(path));
+    }
+    Assert.assertTrue(expected.isEmpty());
+  }
+
+  @Test
+  public void testIntersectWithFullPathPrefixTree3() throws Exception {
+    List<PartialPath> partialPathList =
+        Arrays.asList(
+            new PartialPath("root.sg1.d1.t1.s1"),
+            new PartialPath("root.sg1.*.t1.s2"),
+            new PartialPath("root.**.h*.**"));
+    PathPatternTree patternTree = new PathPatternTree();
+    for (PartialPath path : partialPathList) {
+      patternTree.appendPathPattern(path);
+    }
+    patternTree.constructTree();
+
+    List<PartialPath> fullPathPrefixList =
+        Arrays.asList(new PartialPath("root.sg1.d1.**"), new 
PartialPath("root.sg1.d2.**"));
+    PathPatternTree fullPathPrefixTree = new PathPatternTree();
+    for (PartialPath path : fullPathPrefixList) {
+      fullPathPrefixTree.appendPathPattern(path);
+    }
+    fullPathPrefixTree.constructTree();
+
+    PathPatternTree res =
+        PathPatternTreeUtils.intersectWithFullPathPrefixTree(patternTree, 
fullPathPrefixTree);
+    Set<PartialPath> expected =
+        new HashSet<PartialPath>() {
+          {
+            add(new PartialPath("root.sg1.d1.h*.**"));
+            add(new PartialPath("root.sg1.d1.t1.s1"));
+            add(new PartialPath("root.sg1.d1.t1.s2"));
+            add(new PartialPath("root.sg1.d1.**.h*.**"));
+            add(new PartialPath("root.sg1.d2.h*.**"));
+            add(new PartialPath("root.sg1.d2.**.h*.**"));
+            add(new PartialPath("root.sg1.d2.t1.s2"));
+          }
+        };
+    for (PartialPath path : res.getAllPathPatterns()) {
+      Assert.assertTrue(expected.remove(path));
+    }
+    Assert.assertTrue(expected.isEmpty());
+  }
 }

Reply via email to