Skip to content

Commit 129f8b5

Browse files
committed
apply review
1 parent 10367bc commit 129f8b5

File tree

2 files changed

+91
-26
lines changed

2 files changed

+91
-26
lines changed

iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/TreePatternPruningTest.java

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121

2222
import org.apache.iotdb.commons.pipe.config.constant.PipeSourceConstant;
2323
import org.apache.iotdb.commons.pipe.datastructure.pattern.IoTDBTreePattern;
24+
import org.apache.iotdb.commons.pipe.datastructure.pattern.PrefixTreePattern;
2425
import org.apache.iotdb.commons.pipe.datastructure.pattern.TreePattern;
2526
import org.apache.iotdb.commons.pipe.datastructure.pattern.UnionIoTDBTreePattern;
26-
import org.apache.iotdb.commons.pipe.datastructure.pattern.WithExclusionIoTDBTreePattern;
27-
import org.apache.iotdb.commons.pipe.datastructure.pattern.WithExclusionTreePattern;
2827
import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters;
2928
import org.apache.iotdb.pipe.api.exception.PipeException;
3029

@@ -80,11 +79,8 @@ public void testInclusionPrunedByExclusion_Partial() {
8079

8180
final TreePattern result = TreePattern.parsePipePatternFromSourceParameters(params);
8281

83-
Assert.assertTrue(result instanceof WithExclusionIoTDBTreePattern);
84-
final WithExclusionIoTDBTreePattern exclusionPattern = (WithExclusionIoTDBTreePattern) result;
85-
86-
Assert.assertEquals("root.sg.d2", exclusionPattern.getInclusionPattern().getPattern());
87-
Assert.assertEquals("root.sg.d1", exclusionPattern.getExclusionPattern().getPattern());
82+
Assert.assertTrue(result instanceof IoTDBTreePattern);
83+
Assert.assertEquals("root.sg.d2", result.getPattern());
8884
}
8985

9086
@Test
@@ -119,10 +115,8 @@ public void testComplexPruning() {
119115

120116
final TreePattern result = TreePattern.parsePipePatternFromSourceParameters(params);
121117

122-
Assert.assertTrue(result instanceof WithExclusionIoTDBTreePattern);
123-
final WithExclusionIoTDBTreePattern excPattern = (WithExclusionIoTDBTreePattern) result;
124-
125-
Assert.assertEquals("root.sg.B", excPattern.getInclusionPattern().getPattern());
118+
Assert.assertTrue(result instanceof IoTDBTreePattern);
119+
Assert.assertEquals("root.sg.B", result.getPattern());
126120
}
127121

128122
@Test
@@ -139,10 +133,8 @@ public void testComplexPruning_Prefix() {
139133

140134
final TreePattern result = TreePattern.parsePipePatternFromSourceParameters(params);
141135

142-
Assert.assertTrue(result instanceof WithExclusionTreePattern);
143-
final WithExclusionTreePattern excPattern = (WithExclusionTreePattern) result;
144-
145-
Assert.assertEquals("root.sg.B", excPattern.getInclusionPattern().getPattern());
136+
Assert.assertTrue(result instanceof PrefixTreePattern);
137+
Assert.assertEquals("root.sg.B", result.getPattern());
146138
}
147139

148140
@Test
@@ -158,11 +150,7 @@ public void testUnionPreservedWhenNotCovered() {
158150

159151
final TreePattern result = TreePattern.parsePipePatternFromSourceParameters(params);
160152

161-
Assert.assertTrue(result instanceof WithExclusionIoTDBTreePattern);
162-
final WithExclusionIoTDBTreePattern excResult = (WithExclusionIoTDBTreePattern) result;
163-
164-
Assert.assertTrue(excResult.getInclusionPattern() instanceof UnionIoTDBTreePattern);
165-
final UnionIoTDBTreePattern unionInc = (UnionIoTDBTreePattern) excResult.getInclusionPattern();
166-
Assert.assertEquals(2, unionInc.getPatterns().size());
153+
Assert.assertTrue(result instanceof UnionIoTDBTreePattern);
154+
Assert.assertEquals("root.sg.d1,root.sg.d2", result.getPattern());
167155
}
168156
}

iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/TreePattern.java

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,23 @@ public static TreePattern parsePipePatternFromSourceParameters(
179179

180180
// 5. Check if the resulting inclusion pattern is empty
181181
if (inclusionPatterns.isEmpty()) {
182-
throw new PipeException(
183-
"Pipe: The inclusion pattern is empty after pruning by the exclusion pattern. "
184-
+ "This pipe pattern will match nothing.");
182+
final String msg =
183+
String.format(
184+
"Pipe: The provided exclusion pattern fully covers the inclusion pattern. "
185+
+ "This pipe pattern will match nothing. "
186+
+ "Inclusion: %s, Exclusion: %s",
187+
sourceParameters.getStringByKeys(EXTRACTOR_PATTERN_KEY, SOURCE_PATTERN_KEY),
188+
sourceParameters.getStringByKeys(
189+
EXTRACTOR_PATTERN_EXCLUSION_KEY, SOURCE_PATTERN_EXCLUSION_KEY));
190+
LOGGER.warn(msg);
191+
throw new PipeException(msg);
185192
}
186193

187-
// 6. Build final patterns
194+
// 6. Prune exclusion patterns: if an exclusion pattern does not overlap with
195+
// ANY of the remaining inclusion patterns, it is useless and should be removed.
196+
exclusionPatterns = pruneIrrelevantExclusions(inclusionPatterns, exclusionPatterns);
197+
198+
// 7. Build final patterns
188199
final TreePattern finalInclusionPattern =
189200
buildUnionPattern(isTreeModelDataAllowedToBeCaptured, inclusionPatterns);
190201

@@ -195,7 +206,7 @@ public static TreePattern parsePipePatternFromSourceParameters(
195206
final TreePattern finalExclusionPattern =
196207
buildUnionPattern(isTreeModelDataAllowedToBeCaptured, exclusionPatterns);
197208

198-
// 7. Combine inclusion and exclusion
209+
// 8. Combine inclusion and exclusion
199210
if (finalInclusionPattern instanceof IoTDBTreePatternOperations
200211
&& finalExclusionPattern instanceof IoTDBTreePatternOperations) {
201212
return new WithExclusionIoTDBTreePattern(
@@ -395,6 +406,37 @@ private static List<TreePattern> pruneInclusionPatterns(
395406
return prunedInclusion;
396407
}
397408

409+
/**
410+
* Prunes patterns from the exclusion list that do NOT overlap with any of the remaining inclusion
411+
* patterns.
412+
*/
413+
private static List<TreePattern> pruneIrrelevantExclusions(
414+
final List<TreePattern> inclusion, final List<TreePattern> exclusion) {
415+
if (exclusion == null || exclusion.isEmpty()) {
416+
return new ArrayList<>();
417+
}
418+
if (inclusion == null || inclusion.isEmpty()) {
419+
// If inclusion is empty, exclusion is irrelevant anyway, but usually this case
420+
// throws exception earlier.
421+
return new ArrayList<>();
422+
}
423+
424+
final List<TreePattern> relevantExclusion = new ArrayList<>();
425+
for (final TreePattern exc : exclusion) {
426+
boolean overlapsWithAnyInclusion = false;
427+
for (final TreePattern inc : inclusion) {
428+
if (overlaps(exc, inc)) {
429+
overlapsWithAnyInclusion = true;
430+
break;
431+
}
432+
}
433+
if (overlapsWithAnyInclusion) {
434+
relevantExclusion.add(exc);
435+
}
436+
}
437+
return relevantExclusion;
438+
}
439+
398440
/** Checks if 'coverer' pattern fully covers 'coveree' pattern. */
399441
private static boolean covers(final TreePattern coverer, final TreePattern coveree) {
400442
try {
@@ -423,6 +465,41 @@ private static boolean covers(final TreePattern coverer, final TreePattern cover
423465
} catch (final Exception e) {
424466
// In case of path parsing errors or unsupported operations, assume no coverage
425467
// to be safe and avoid aggressive pruning.
468+
LOGGER.warn(
469+
"Pipe: Failed to check if pattern [{}] covers [{}]. Assuming false.",
470+
coverer.getPattern(),
471+
coveree.getPattern(),
472+
e);
473+
return false;
474+
}
475+
}
476+
477+
/** Checks if 'patternA' overlaps with 'patternB'. */
478+
private static boolean overlaps(final TreePattern patternA, final TreePattern patternB) {
479+
try {
480+
final List<PartialPath> pathsA = patternA.getBaseInclusionPaths();
481+
final List<PartialPath> pathsB = patternB.getBaseInclusionPaths();
482+
483+
if (pathsA.isEmpty() || pathsB.isEmpty()) {
484+
return false;
485+
}
486+
487+
// Logic: Check if ANY path in A overlaps with ANY path in B.
488+
for (final PartialPath pathA : pathsA) {
489+
for (final PartialPath pathB : pathsB) {
490+
if (pathA.overlapWith(pathB)) {
491+
return true;
492+
}
493+
}
494+
}
495+
return false;
496+
} catch (final Exception e) {
497+
// Best effort check
498+
LOGGER.warn(
499+
"Pipe: Failed to check if pattern [{}] overlaps with [{}]. Assuming false.",
500+
patternA.getPattern(),
501+
patternB.getPattern(),
502+
e);
426503
return false;
427504
}
428505
}

0 commit comments

Comments
 (0)