This is an automated email from the ASF dual-hosted git repository. hui pushed a commit to branch lmh/likeDebug in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit c036ed84ac4e10fc3b89f72d97614c05b30e42bf Author: Minghui Liu <[email protected]> AuthorDate: Thu Oct 27 14:18:22 2022 +0800 Implement `NOT LIKE` filter --- .../iotdb/db/qp/logical/crud/LikeOperator.java | 40 ++++++++++++++++------ .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 2 +- .../qp/strategy/optimizer/ConcatPathOptimizer.java | 3 +- .../iotdb/db/qp/physical/PhysicalPlanTest.java | 3 +- .../iotdb/tsfile/read/filter/ValueFilter.java | 19 +++++----- .../iotdb/tsfile/read/filter/operator/Like.java | 13 ++++--- 6 files changed, 54 insertions(+), 26 deletions(-) diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java index 9183205230..1dd1e47151 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java @@ -38,12 +38,14 @@ import static org.apache.iotdb.tsfile.file.metadata.enums.TSDataType.TEXT; /** fuzzy query structure LikeOperator. */ public class LikeOperator extends FunctionOperator { + private boolean not; protected String value; - public LikeOperator(FilterType filterType, PartialPath path, String value) { + public LikeOperator(FilterType filterType, PartialPath path, String value, boolean not) { super(filterType); this.singlePath = path; this.value = value; + this.not = not; isLeaf = true; isSingle = true; } @@ -68,19 +70,20 @@ public class LikeOperator extends FunctionOperator { singlePath, (value.startsWith("'") && value.endsWith("'")) ? value.substring(1, value.length() - 1) - : value); + : value, + not); } return new Pair<>(ret, singlePath.getFullPath()); } private static class Like { public static <T extends Comparable<T>> IUnaryExpression getUnaryExpression( - PartialPath path, String value) { - return new SingleSeriesExpression(path, ValueFilter.like(value)); + PartialPath path, String value, boolean not) { + return new SingleSeriesExpression(path, ValueFilter.like(value, not)); } - public <T extends Comparable<T>> Filter getValueFilter(String value) { - return ValueFilter.like(value); + public <T extends Comparable<T>> Filter getValueFilter(String value, boolean not) { + return ValueFilter.like(value, not); } } @@ -90,13 +93,13 @@ public class LikeOperator extends FunctionOperator { for (int i = 0; i < spaceNum; i++) { sc.addTail(" "); } - sc.addTail(singlePath.getFullPath(), getFilterSymbol(), value, ", single\n"); + sc.addTail(singlePath.getFullPath(), getFilterSymbol(), not, value, ", single\n"); return sc.toString(); } @Override public LikeOperator copy() { - LikeOperator ret = new LikeOperator(this.filterType, singlePath.clone(), value); + LikeOperator ret = new LikeOperator(this.filterType, singlePath.clone(), value, not); ret.isLeaf = isLeaf; ret.isSingle = isSingle; ret.pathSet = pathSet; @@ -115,20 +118,35 @@ public class LikeOperator extends FunctionOperator { return false; } LikeOperator that = (LikeOperator) o; - return Objects.equals(value, that.value); + return Objects.equals(value, that.value) && not == that.not; } @Override public int hashCode() { - return Objects.hash(super.hashCode(), singlePath, value); + return Objects.hash(super.hashCode(), singlePath, value, not); } @Override public String toString() { - return "[" + singlePath.getFullPath() + getFilterSymbol() + value + "]"; + return "[" + + singlePath.getFullPath() + + (not ? " NOT " : " ") + + getFilterSymbol() + + " " + + value + + "]"; + } + + @Override + public void reverseFunc() { + not = !not; } public String getValue() { return value; } + + public boolean isNot() { + return not; + } } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java index 9b909b4aee..7f2f969d2e 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java @@ -2621,7 +2621,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { } return ctx.REGEXP() != null ? new RegexpOperator(FilterType.REGEXP, path, ctx.STRING_LITERAL().getText()) - : new LikeOperator(FilterType.LIKE, path, ctx.STRING_LITERAL().getText()); + : new LikeOperator(FilterType.LIKE, path, ctx.STRING_LITERAL().getText(), false); } else { if (ctx.TIME() != null || ctx.TIMESTAMP() != null) { path = new PartialPath(SQLConstant.getSingleTimeArray()); diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java index 756c27ac6b..a3ffabe5d5 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java @@ -343,7 +343,8 @@ public class ConcatPathOptimizer implements ILogicalOptimizer { new LikeOperator( operator.getFilterType(), noStarPaths.get(i), - ((LikeOperator) operator).getValue())); + ((LikeOperator) operator).getValue(), + ((LikeOperator) operator).isNot())); } else if (operator instanceof RegexpOperator) { currentNode.addChildOperator( new RegexpOperator( diff --git a/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java b/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java index 76fe66a39c..2018f0a27d 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java @@ -1443,7 +1443,8 @@ public class PhysicalPlanTest { PhysicalPlan plan = processor.parseSQLToPhysicalPlan(sqlStr); IExpression queryFilter = ((RawDataQueryPlan) plan).getExpression(); IExpression expect = - new SingleSeriesExpression(new Path("root.vehicle.d5", "s1"), ValueFilter.like("string*")); + new SingleSeriesExpression( + new Path("root.vehicle.d5", "s1"), ValueFilter.like("string*", false)); assertEquals(expect.toString(), queryFilter.toString()); } diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java index 3dcfbe94f8..fd06538cb7 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java @@ -74,8 +74,8 @@ public class ValueFilter { return new ValueRegexp(value); } - public static <T extends Comparable<T>> ValueLike<T> like(String value) { - return new ValueLike(value); + public static <T extends Comparable<T>> ValueLike<T> like(String value, boolean not) { + return new ValueLike(value, not); } public static class ValueIn<T extends Comparable<T>> extends In<T> { @@ -268,8 +268,8 @@ public class ValueFilter { public static class ValueLike<T extends Comparable<T>> extends Like<T> { - private ValueLike(String value) { - super(value, FilterType.VALUE_FILTER); + private ValueLike(String value, boolean not) { + super(value, FilterType.VALUE_FILTER, not); } } @@ -277,14 +277,17 @@ public class ValueFilter { private final int index; - private VectorValueLike(String value, int index) { - super(value); + private VectorValueLike(String value, int index, boolean not) { + super(value, not); this.index = index; } public boolean satisfy(long time, TsPrimitiveType[] values) { - Object v = filterType == FilterType.TIME_FILTER ? time : values[index].getValue(); - return this.value.equals(v); + if (filterType != FilterType.VALUE_FILTER) { + return false; + } + Object value = values[index].getValue(); + return pattern.matcher(value.toString()).find() != not; } } } diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java index fac3dfcf5b..c3230e586b 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java @@ -45,15 +45,18 @@ public class Like<T extends Comparable<T>> implements Filter { protected Pattern pattern; + protected boolean not; + private Like() {} /** * The main idea of this part comes from * https://codereview.stackexchange.com/questions/36861/convert-sql-like-to-regex/36864 */ - public Like(String value, FilterType filterType) { + public Like(String value, FilterType filterType, boolean not) { this.value = value; this.filterType = filterType; + this.not = not; try { String unescapeValue = unescapeString(value); String specialRegexStr = ".^$*+?{}[]|()"; @@ -94,7 +97,7 @@ public class Like<T extends Comparable<T>> implements Filter { if (filterType != FilterType.VALUE_FILTER) { return false; } - return pattern.matcher(value.toString()).find(); + return pattern.matcher(value.toString()).find() != not; } @Override @@ -109,7 +112,7 @@ public class Like<T extends Comparable<T>> implements Filter { @Override public Filter copy() { - return new Like(value, filterType); + return new Like(value, filterType, not); } @Override @@ -118,6 +121,7 @@ public class Like<T extends Comparable<T>> implements Filter { outputStream.write(getSerializeId().ordinal()); outputStream.write(filterType.ordinal()); ReadWriteIOUtils.writeObject(value, outputStream); + ReadWriteIOUtils.write(not, outputStream); } catch (IOException ex) { throw new IllegalArgumentException("Failed to serialize outputStream of type:", ex); } @@ -127,11 +131,12 @@ public class Like<T extends Comparable<T>> implements Filter { public void deserialize(ByteBuffer buffer) { filterType = FilterType.values()[buffer.get()]; value = ReadWriteIOUtils.readString(buffer); + not = ReadWriteIOUtils.readBool(buffer); } @Override public String toString() { - return filterType + " is " + value; + return filterType + (not ? " not like " : " like ") + value; } @Override
