You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ch...@apache.org on 2022/07/27 09:33:03 UTC
[iotdb] branch master updated: [IOTDB-3942] Support count timeseries where tag1 = v1 (#6763)
This is an automated email from the ASF dual-hosted git repository.
chaow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 159f669103 [IOTDB-3942] Support count timeseries where tag1 = v1 (#6763)
159f669103 is described below
commit 159f6691034666fe2c3251199765c878d438b5a4
Author: 任宇华 <79...@users.noreply.github.com>
AuthorDate: Wed Jul 27 17:32:58 2022 +0800
[IOTDB-3942] Support count timeseries where tag1 = v1 (#6763)
---
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 12 +--
docs/UserGuide/Operate-Metadata/Timeseries.md | 48 +++++++++-
docs/zh/UserGuide/Operate-Metadata/Timeseries.md | 50 +++++++++-
.../iotdb/db/it/schema/IoTDBMetadataFetchIT.java | 104 +++++++++++++++++++++
.../schemaregion/rocksdb/RSchemaRegion.java | 64 +++++++++++++
.../iotdb/db/metadata/mtree/IMTreeBelowSG.java | 17 ++++
.../db/metadata/mtree/MTreeBelowSGCachedImpl.java | 27 ++++++
.../db/metadata/mtree/MTreeBelowSGMemoryImpl.java | 27 ++++++
.../traverser/counter/MeasurementCounter.java | 24 +++++
.../counter/MeasurementGroupByLevelCounter.java | 24 +++++
.../db/metadata/schemaregion/ISchemaRegion.java | 13 +++
.../schemaregion/SchemaRegionMemoryImpl.java | 28 ++++++
.../schemaregion/SchemaRegionSchemaFileImpl.java | 28 ++++++
.../apache/iotdb/db/metadata/tag/TagManager.java | 39 ++++++++
.../schema/LevelTimeSeriesCountOperator.java | 28 +++++-
.../operator/schema/TimeSeriesCountOperator.java | 26 +++++-
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 44 ++++++---
.../db/mpp/plan/planner/LocalExecutionPlanner.java | 13 ++-
.../db/mpp/plan/planner/LogicalPlanBuilder.java | 21 ++++-
.../db/mpp/plan/planner/LogicalPlanVisitor.java | 11 ++-
.../metedata/read/LevelTimeSeriesCountNode.java | 41 +++++++-
.../node/metedata/read/TimeSeriesCountNode.java | 40 +++++++-
.../metadata/CountLevelTimeSeriesStatement.java | 32 +++++++
.../metadata/CountTimeSeriesStatement.java | 30 ++++++
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 6 +-
.../operator/schema/CountMergeOperatorTest.java | 21 ++++-
.../operator/schema/SchemaCountOperatorTest.java | 21 ++++-
.../metadata/read/SchemaCountNodeSerdeTest.java | 8 +-
28 files changed, 792 insertions(+), 55 deletions(-)
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 03868d644a..fadcb92542 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -261,11 +261,7 @@ showDevices
// Show Timeseries
showTimeseries
- : SHOW LATEST? TIMESERIES prefixPath? showWhereClause? limitClause?
- ;
-
-showWhereClause
- : WHERE (attributePair | containsExpression)
+ : SHOW LATEST? TIMESERIES prefixPath? tagWhereClause? limitClause?
;
// Show Child Paths
@@ -350,7 +346,7 @@ countDevices
// Count Timeseries
countTimeseries
- : COUNT TIMESERIES prefixPath? (GROUP BY LEVEL operator_eq INTEGER_LITERAL)?
+ : COUNT TIMESERIES prefixPath? tagWhereClause? (GROUP BY LEVEL operator_eq INTEGER_LITERAL)?
;
// Count Nodes
@@ -358,6 +354,10 @@ countNodes
: COUNT NODES prefixPath LEVEL operator_eq INTEGER_LITERAL
;
+tagWhereClause
+ : WHERE (attributePair | containsExpression)
+ ;
+
/**
* 3. Data Manipulation Language (DML)
diff --git a/docs/UserGuide/Operate-Metadata/Timeseries.md b/docs/UserGuide/Operate-Metadata/Timeseries.md
index c09a75cd54..a256558a8f 100644
--- a/docs/UserGuide/Operate-Metadata/Timeseries.md
+++ b/docs/UserGuide/Operate-Metadata/Timeseries.md
@@ -275,7 +275,7 @@ ALTER timeseries root.turbine.d1.s1 UPSERT ALIAS=newAlias TAGS(tag3=v3, tag4=v4)
SHOW TIMESERIES (<`PathPattern`>)? WhereClause
```
- returns all the timeseries information that satisfy the where condition and match the pathPattern. SQL statements are as follows:
+returns all the timeseries information that satisfy the where condition and match the pathPattern. SQL statements are as follows:
```
ALTER timeseries root.ln.wf02.wt02.hardware ADD TAGS unit=c
@@ -304,6 +304,52 @@ Total line number = 1
It costs 0.004s
```
+- count timeseries using tags
+
+```
+COUNT TIMESERIES (<`PathPattern`>)? WhereClause
+COUNT TIMESERIES (<`PathPattern`>)? WhereClause GROUP BY LEVEL=<INTEGER>
+```
+
+returns all the number of timeseries that satisfy the where condition and match the pathPattern. SQL statements are as follows:
+
+```
+count timeseries
+count timeseries root.** where unit = c
+count timeseries root.** where unit = c group by level = 2
+```
+
+The results are shown below respectly :
+
+```
+IoTDB> count timeseries
++-----------------+
+|count(timeseries)|
++-----------------+
+| 6|
++-----------------+
+Total line number = 1
+It costs 0.019s
+IoTDB> count timeseries root.** where unit = c
++-----------------+
+|count(timeseries)|
++-----------------+
+| 2|
++-----------------+
+Total line number = 1
+It costs 0.020s
+IoTDB> count timeseries root.** where unit = c group by level = 2
++--------------+-----------------+
+| column|count(timeseries)|
++--------------+-----------------+
+| root.ln.wf02| 2|
+| root.ln.wf01| 0|
+|root.sgcc.wf03| 0|
++--------------+-----------------+
+Total line number = 3
+It costs 0.011s
+```
+
> Notice that, we only support one condition in the where clause. Either it's an equal filter or it is an `contains` filter. In both case, the property in the where condition must be a tag.
create aligned timeseries
diff --git a/docs/zh/UserGuide/Operate-Metadata/Timeseries.md b/docs/zh/UserGuide/Operate-Metadata/Timeseries.md
index ee135da1e6..adfb2c9731 100644
--- a/docs/zh/UserGuide/Operate-Metadata/Timeseries.md
+++ b/docs/zh/UserGuide/Operate-Metadata/Timeseries.md
@@ -271,10 +271,10 @@ ALTER timeseries root.turbine.d1.s1 UPSERT ALIAS=newAlias TAGS(tag2=newV2, tag3=
* 使用标签作为过滤条件查询时间序列
```
-* SHOW TIMESERIES (<`PathPattern`>)? WhereClause
+SHOW TIMESERIES (<`PathPattern`>)? WhereClause
```
- 返回给定路径的下的所有满足条件的时间序列信息,SQL 语句如下所示:
+返回给定路径的下的所有满足条件的时间序列信息,SQL 语句如下所示:
```
ALTER timeseries root.ln.wf02.wt02.hardware ADD TAGS unit=c
@@ -303,6 +303,52 @@ Total line number = 1
It costs 0.004s
```
+- 使用标签作为过滤条件统计时间序列数量
+
+```
+COUNT TIMESERIES (<`PathPattern`>)? WhereClause
+COUNT TIMESERIES (<`PathPattern`>)? WhereClause GROUP BY LEVEL=<INTEGER>
+```
+
+返回给定路径的下的所有满足条件的时间序列的数量,SQL 语句如下所示:
+
+```
+count timeseries
+count timeseries root.** where unit = c
+count timeseries root.** where unit = c group by level = 2
+```
+
+执行结果分别为:
+
+```
+IoTDB> count timeseries
++-----------------+
+|count(timeseries)|
++-----------------+
+| 6|
++-----------------+
+Total line number = 1
+It costs 0.019s
+IoTDB> count timeseries root.** where unit = c
++-----------------+
+|count(timeseries)|
++-----------------+
+| 2|
++-----------------+
+Total line number = 1
+It costs 0.020s
+IoTDB> count timeseries root.** where unit = c group by level = 2
++--------------+-----------------+
+| column|count(timeseries)|
++--------------+-----------------+
+| root.ln.wf02| 2|
+| root.ln.wf01| 0|
+|root.sgcc.wf03| 0|
++--------------+-----------------+
+Total line number = 3
+It costs 0.011s
+```
+
> 注意,现在我们只支持一个查询条件,要么是等值条件查询,要么是包含条件查询。当然 where 子句中涉及的必须是标签值,而不能是属性值。
创建对齐时间序列
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
index 98b216e71e..5b77f67fab 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.itbase.category.LocalStandaloneIT;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
@@ -354,6 +355,45 @@ public class IoTDBMetadataFetchIT {
}
}
+ @Test
+ @Ignore(
+ value =
+ "Old IoTDB service not support 'count timeseries by tag',Waiting for the old IoTDB to be removed.")
+ public void showCountTimeSeriesWithTag() throws SQLException {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute(
+ "create timeseries root.sg.d.s1 with datatype=FLOAT, encoding=RLE, compression=SNAPPY tags('tag1'='v1', 'tag2'='v2')");
+ statement.execute(
+ "create timeseries root.sg1.d.s1 with datatype=FLOAT, encoding=RLE, compression=SNAPPY tags('tag1'='v1')");
+ String[] sqls =
+ new String[] {
+ "COUNT TIMESERIES root.sg.** where tag1 = v1",
+ "COUNT TIMESERIES where tag1 = v1",
+ "COUNT TIMESERIES where tag3 = v3"
+ };
+ String[] standards = new String[] {"1,\n", "2,\n", "0,\n"};
+ for (int n = 0; n < sqls.length; n++) {
+ String sql = sqls[n];
+ String standard = standards[n];
+ StringBuilder builder = new StringBuilder();
+ try (ResultSet resultSet = statement.executeQuery(sql)) {
+ ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+ while (resultSet.next()) {
+ for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+ builder.append(resultSet.getString(i)).append(",");
+ }
+ builder.append("\n");
+ }
+ Assert.assertEquals(standard, builder.toString());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }
+ }
+
@Test
public void showCountDevices() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -457,6 +497,70 @@ public class IoTDBMetadataFetchIT {
}
}
+ @Test
+ @Ignore(
+ value =
+ "Old IoTDB service not support 'count timeseries by tag',Waiting for the old IoTDB to be removed.")
+ public void showCountTimeSeriesGroupByWithTag() throws SQLException {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute(
+ "create timeseries root.sg.d.status with datatype=FLOAT, encoding=RLE, compression=SNAPPY tags('tag1'='v1', 'tag2'='v2')");
+ statement.execute(
+ "create timeseries root.sg1.d.status with datatype=FLOAT, encoding=RLE, compression=SNAPPY tags('tag1'='v1')");
+ String[] sqls =
+ new String[] {
+ "COUNT TIMESERIES root.** where tag1 = v1 group by level=1",
+ "COUNT TIMESERIES root.** where tag2 = v2 group by level=3",
+ "COUNT TIMESERIES root.**.status where tag1 = v1 group by level=2",
+ "COUNT TIMESERIES root.** where tag3 = v3 group by level=2"
+ };
+ Set<String>[] standards =
+ new Set[] {
+ new HashSet<>(
+ Arrays.asList(
+ "root.ln,0,", "root.ln1,0,", "root.ln2,0,", "root.sg,1,", "root.sg1,1,")),
+ new HashSet<>(
+ Arrays.asList(
+ "root.ln.wf01.wt01,0,",
+ "root.ln.wf01.wt02,0,",
+ "root.ln1.wf01.wt01,0,",
+ "root.ln2.wf01.wt01,0,",
+ "root.sg.d.status,1,",
+ "root.sg1.d.status,0,")),
+ new HashSet<>(
+ Arrays.asList(
+ "root.ln.wf01,0,",
+ "root.ln1.wf01,0,",
+ "root.ln2.wf01,0,",
+ "root.sg.d,1,",
+ "root.sg1.d,1,")),
+ new HashSet<>(
+ Arrays.asList(
+ "root.ln.wf01,0,",
+ "root.ln1.wf01,0,",
+ "root.ln2.wf01,0,",
+ "root.sg.d,0,",
+ "root.sg1.d,0,")),
+ };
+ for (int n = 0; n < sqls.length; n++) {
+ String sql = sqls[n];
+ Set<String> standard = standards[n];
+ try (ResultSet resultSet = statement.executeQuery(sql)) {
+ while (resultSet.next()) {
+ String string = resultSet.getString(1) + "," + resultSet.getInt(2) + ",";
+ Assert.assertTrue(standard.contains(string));
+ standard.remove(string);
+ }
+ assertEquals(0, standard.size());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }
+ }
+
@Test
public void showCountNodes() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getConnection();
diff --git a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
index edadd1aa02..574bd21ca6 100644
--- a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
+++ b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
@@ -856,6 +856,13 @@ public class RSchemaRegion implements ISchemaRegion {
return getCountByNodeType(new Character[] {NODE_TYPE_MEASUREMENT}, pathPattern.getNodes());
}
+ @Override
+ public int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, String key, String value, boolean isContains)
+ throws MetadataException {
+ return getMatchedMeasurementPathWithTags(pathPattern.getNodes()).size();
+ }
+
@TestOnly
public int getAllTimeseriesCount(PartialPath pathPattern) throws MetadataException {
return getAllTimeseriesCount(pathPattern, false);
@@ -933,6 +940,63 @@ public class RSchemaRegion implements ISchemaRegion {
return result;
}
+ @Override
+ public Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ String key,
+ String value,
+ boolean isContains)
+ throws MetadataException {
+ Map<PartialPath, Integer> result = new ConcurrentHashMap<>();
+ Map<MeasurementPath, Pair<Map<String, String>, Map<String, String>>> measurementPathsAndTags =
+ getMatchedMeasurementPathWithTags(pathPattern.getNodes());
+ BiFunction<byte[], byte[], Boolean> function;
+ if (!measurementPathsAndTags.isEmpty()) {
+ function =
+ (a, b) -> {
+ String k = new String(a);
+ String partialName = splitToPartialNameByLevel(k, level);
+ if (partialName != null) {
+ PartialPath path = null;
+ try {
+ path = new PartialPath(partialName);
+ } catch (IllegalPathException e) {
+ logger.warn(e.getMessage());
+ }
+ if (!measurementPathsAndTags.keySet().contains(partialName)) {
+ result.put(path, result.get(path));
+ } else {
+ result.putIfAbsent(path, 0);
+ result.put(path, result.get(path) + 1);
+ }
+ }
+ return true;
+ };
+ } else {
+ function =
+ (a, b) -> {
+ String k = new String(a);
+ String partialName = splitToPartialNameByLevel(k, level);
+ if (partialName != null) {
+ PartialPath path = null;
+ try {
+ path = new PartialPath(partialName);
+ } catch (IllegalPathException e) {
+ logger.warn(e.getMessage());
+ }
+ result.putIfAbsent(path, 0);
+ }
+ return true;
+ };
+ }
+ traverseOutcomeBasins(
+ pathPattern.getNodes(), MAX_PATH_DEPTH, function, new Character[] {NODE_TYPE_MEASUREMENT});
+
+ return result;
+ }
+
private String splitToPartialNameByLevel(String innerName, int level) {
StringBuilder stringBuilder = new StringBuilder(ROOT_STRING);
boolean currentIsFlag;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/IMTreeBelowSG.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/IMTreeBelowSG.java
index 7c4fff16bc..f1e2b8cdce 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/IMTreeBelowSG.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/IMTreeBelowSG.java
@@ -203,6 +203,15 @@ public interface IMTreeBelowSG {
*/
int getAllTimeseriesCount(PartialPath pathPattern) throws MetadataException;
+ /**
+ * Get the count of timeseries matching the given path by tag.
+ *
+ * @param pathPattern a path pattern or a full path, may contain wildcard
+ */
+ int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, List<String> timeseries, boolean hasTag)
+ throws MetadataException;
+
/**
* Get the count of devices matching the given path. If using prefix match, the path pattern is
* used to match prefix path. All timeseries start with the matched prefix path will be counted.
@@ -230,6 +239,14 @@ public interface IMTreeBelowSG {
Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
PartialPath pathPattern, int level, boolean isPrefixMatch) throws MetadataException;
+ Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ List<String> timeseries,
+ boolean hasTag)
+ throws MetadataException;
+
/**
* Get node by the path
*
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGCachedImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGCachedImpl.java
index 8d19efa765..7247047d7a 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGCachedImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGCachedImpl.java
@@ -862,6 +862,17 @@ public class MTreeBelowSGCachedImpl implements IMTreeBelowSG {
return getAllTimeseriesCount(pathPattern, false);
}
+ @Override
+ public int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, List<String> timeseries, boolean hasTag)
+ throws MetadataException {
+ CounterTraverser counter =
+ new MeasurementCounter(storageGroupMNode, pathPattern, store, timeseries, hasTag);
+ counter.setPrefixMatch(isPrefixMatch);
+ counter.traverse();
+ return counter.getCount();
+ }
+
/**
* Get the count of devices matching the given path. If using prefix match, the path pattern is
* used to match prefix path. All timeseries start with the matched prefix path will be counted.
@@ -912,6 +923,22 @@ public class MTreeBelowSGCachedImpl implements IMTreeBelowSG {
return counter.getResult();
}
+ @Override
+ public Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ List<String> timeseries,
+ boolean hasTag)
+ throws MetadataException {
+ MeasurementGroupByLevelCounter counter =
+ new MeasurementGroupByLevelCounter(
+ storageGroupMNode, pathPattern, store, level, timeseries, hasTag);
+ counter.setPrefixMatch(isPrefixMatch);
+ counter.traverse();
+ return counter.getResult();
+ }
+
// endregion
// endregion
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
index 46abb13445..67a020654b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
@@ -873,6 +873,17 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
return getAllTimeseriesCount(pathPattern, false);
}
+ @Override
+ public int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, List<String> timeseries, boolean hasTag)
+ throws MetadataException {
+ CounterTraverser counter =
+ new MeasurementCounter(storageGroupMNode, pathPattern, store, timeseries, hasTag);
+ counter.setPrefixMatch(isPrefixMatch);
+ counter.traverse();
+ return counter.getCount();
+ }
+
/**
* Get the count of devices matching the given path. If using prefix match, the path pattern is
* used to match prefix path. All timeseries start with the matched prefix path will be counted.
@@ -923,6 +934,22 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
return counter.getResult();
}
+ @Override
+ public Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ List<String> timeseries,
+ boolean hasTag)
+ throws MetadataException {
+ MeasurementGroupByLevelCounter counter =
+ new MeasurementGroupByLevelCounter(
+ storageGroupMNode, pathPattern, store, level, timeseries, hasTag);
+ counter.setPrefixMatch(isPrefixMatch);
+ counter.traverse();
+ return counter.getResult();
+ }
+
// endregion
// endregion
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
index c53afae24c..6fe05844ec 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
@@ -23,16 +23,35 @@ import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.metadata.mnode.IMNode;
import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
+import java.util.ArrayList;
+import java.util.List;
+
// This method implements the measurement count function.
// One MultiMeasurement will only be count once.
public class MeasurementCounter extends CounterTraverser {
+ private List<String> timeseries = new ArrayList<>();
+ private boolean hasTag = false;
+
public MeasurementCounter(IMNode startNode, PartialPath path, IMTreeStore store)
throws MetadataException {
super(startNode, path, store);
shouldTraverseTemplate = true;
}
+ public MeasurementCounter(
+ IMNode startNode,
+ PartialPath path,
+ IMTreeStore store,
+ List<String> timeseries,
+ boolean hasTag)
+ throws MetadataException {
+ super(startNode, path, store);
+ shouldTraverseTemplate = true;
+ this.timeseries = timeseries;
+ this.hasTag = hasTag;
+ }
+
@Override
protected boolean processInternalMatchedMNode(IMNode node, int idx, int level) {
return false;
@@ -43,6 +62,11 @@ public class MeasurementCounter extends CounterTraverser {
if (!node.isMeasurement()) {
return false;
}
+ if (hasTag) {
+ if (!timeseries.contains(node.getFullPath())) {
+ return true;
+ }
+ }
count++;
return true;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementGroupByLevelCounter.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementGroupByLevelCounter.java
index 5f58524885..55156fea9c 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementGroupByLevelCounter.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementGroupByLevelCounter.java
@@ -24,7 +24,9 @@ import org.apache.iotdb.db.metadata.mnode.IMNode;
import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
import org.apache.iotdb.db.metadata.mtree.traverser.Traverser;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
public class MeasurementGroupByLevelCounter extends Traverser {
@@ -33,6 +35,8 @@ public class MeasurementGroupByLevelCounter extends Traverser {
private int groupByLevel;
private Map<PartialPath, Integer> result = new HashMap<>();
+ private List<String> timeseries = new ArrayList<>();
+ private boolean hasTag = false;
// path representing current branch and matching the pattern and level
private PartialPath path;
@@ -45,6 +49,21 @@ public class MeasurementGroupByLevelCounter extends Traverser {
checkLevelAboveSG();
}
+ public MeasurementGroupByLevelCounter(
+ IMNode startNode,
+ PartialPath path,
+ IMTreeStore store,
+ int groupByLevel,
+ List<String> timeseries,
+ boolean hasTag)
+ throws MetadataException {
+ super(startNode, path, store);
+ this.groupByLevel = groupByLevel;
+ this.timeseries = timeseries;
+ this.hasTag = hasTag;
+ checkLevelAboveSG();
+ }
+
/**
* The traverser may start traversing from a storageGroupMNode, which is an InternalMNode of the
* whole MTree.
@@ -86,6 +105,11 @@ public class MeasurementGroupByLevelCounter extends Traverser {
if (!node.isMeasurement()) {
return false;
}
+ if (hasTag) {
+ if (!timeseries.contains(node.getFullPath())) {
+ return true;
+ }
+ }
if (level >= groupByLevel) {
result.put(path, result.get(path) + 1);
}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
index 9f07db8ec6..700eb6f4d7 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
@@ -139,10 +139,23 @@ public interface ISchemaRegion {
int getAllTimeseriesCount(PartialPath pathPattern, boolean isPrefixMatch)
throws MetadataException;
+ int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, String key, String value, boolean isContains)
+ throws MetadataException;
+
// The measurements will be grouped by the node in given level and then counted for each group.
Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
PartialPath pathPattern, int level, boolean isPrefixMatch) throws MetadataException;
+ Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ String key,
+ String value,
+ boolean isContains)
+ throws MetadataException;
+
/**
* To calculate the count of devices for given path pattern. If using prefix match, the path
* pattern is used to match prefix path. All timeseries start with the matched prefix path will be
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
index 605ed59f2e..78754414eb 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
@@ -923,6 +923,17 @@ public class SchemaRegionMemoryImpl implements ISchemaRegion {
return mtree.getAllTimeseriesCount(pathPattern, isPrefixMatch);
}
+ @Override
+ public int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, String key, String value, boolean isContains)
+ throws MetadataException {
+ return mtree.getAllTimeseriesCount(
+ pathPattern,
+ isPrefixMatch,
+ tagManager.getMatchedTimeseriesInIndex(key, value, isContains),
+ true);
+ }
+
/**
* To calculate the count of devices for given path pattern. If using prefix match, the path
* pattern is used to match prefix path. All timeseries start with the matched prefix path will be
@@ -957,6 +968,23 @@ public class SchemaRegionMemoryImpl implements ISchemaRegion {
return mtree.getMeasurementCountGroupByLevel(pathPattern, level, isPrefixMatch);
}
+ @Override
+ public Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ String key,
+ String value,
+ boolean isContains)
+ throws MetadataException {
+ return mtree.getMeasurementCountGroupByLevel(
+ pathPattern,
+ level,
+ isPrefixMatch,
+ tagManager.getMatchedTimeseriesInIndex(key, value, isContains),
+ true);
+ }
+
// endregion
// region Interfaces for level Node info Query
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
index 9a706d84b9..a49e3767de 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
@@ -866,6 +866,17 @@ public class SchemaRegionSchemaFileImpl implements ISchemaRegion {
return mtree.getAllTimeseriesCount(pathPattern, isPrefixMatch);
}
+ @Override
+ public int getAllTimeseriesCount(
+ PartialPath pathPattern, boolean isPrefixMatch, String key, String value, boolean isContains)
+ throws MetadataException {
+ return mtree.getAllTimeseriesCount(
+ pathPattern,
+ isPrefixMatch,
+ tagManager.getMatchedTimeseriesInIndex(key, value, isContains),
+ true);
+ }
+
/**
* To calculate the count of devices for given path pattern. If using prefix match, the path
* pattern is used to match prefix path. All timeseries start with the matched prefix path will be
@@ -900,6 +911,23 @@ public class SchemaRegionSchemaFileImpl implements ISchemaRegion {
return mtree.getMeasurementCountGroupByLevel(pathPattern, level, isPrefixMatch);
}
+ @Override
+ public Map<PartialPath, Integer> getMeasurementCountGroupByLevel(
+ PartialPath pathPattern,
+ int level,
+ boolean isPrefixMatch,
+ String key,
+ String value,
+ boolean isContains)
+ throws MetadataException {
+ return mtree.getMeasurementCountGroupByLevel(
+ pathPattern,
+ level,
+ isPrefixMatch,
+ tagManager.getMatchedTimeseriesInIndex(key, value, isContains),
+ true);
+ }
+
// endregion
// region Interfaces for level Node info Query
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/tag/TagManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/tag/TagManager.java
index 4dd2295431..7c6eecd1d3 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/tag/TagManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/tag/TagManager.java
@@ -161,6 +161,45 @@ public class TagManager {
}
}
+ public List<String> getMatchedTimeseriesInIndex(String key, String value, boolean isContains) {
+ if (!tagIndex.containsKey(key)) {
+ return Collections.emptyList();
+ }
+ Map<String, Set<IMeasurementMNode>> value2Node = tagIndex.get(key);
+ if (value2Node.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<String> timeseries = new ArrayList<>();
+ List<IMeasurementMNode> allMatchedNodes = new ArrayList<>();
+ if (isContains) {
+ for (Map.Entry<String, Set<IMeasurementMNode>> entry : value2Node.entrySet()) {
+ if (entry.getKey() == null || entry.getValue() == null) {
+ continue;
+ }
+ String tagValue = entry.getKey();
+ if (tagValue.contains(value)) {
+ allMatchedNodes.addAll(entry.getValue());
+ }
+ }
+ } else {
+ for (Map.Entry<String, Set<IMeasurementMNode>> entry : value2Node.entrySet()) {
+ if (entry.getKey() == null || entry.getValue() == null) {
+ continue;
+ }
+ String tagValue = entry.getKey();
+ if (value.equals(tagValue)) {
+ allMatchedNodes.addAll(entry.getValue());
+ }
+ }
+ }
+ allMatchedNodes =
+ allMatchedNodes.stream()
+ .sorted(Comparator.comparing(IMNode::getFullPath))
+ .collect(toList());
+ allMatchedNodes.forEach(measurementMNode -> timeseries.add(measurementMNode.getFullPath()));
+ return timeseries;
+ }
+
public List<IMeasurementMNode> getMatchedTimeseriesInIndex(
ShowTimeSeriesPlan plan, QueryContext context) throws MetadataException {
if (!tagIndex.containsKey(plan.getKey())) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/LevelTimeSeriesCountOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/LevelTimeSeriesCountOperator.java
index 917d0e966d..9389035065 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/LevelTimeSeriesCountOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/LevelTimeSeriesCountOperator.java
@@ -38,6 +38,9 @@ public class LevelTimeSeriesCountOperator implements SourceOperator {
private final PartialPath partialPath;
private final boolean isPrefixPath;
private final int level;
+ private final String key;
+ private final String value;
+ private final boolean isContains;
private boolean isFinished;
@@ -46,12 +49,18 @@ public class LevelTimeSeriesCountOperator implements SourceOperator {
OperatorContext operatorContext,
PartialPath partialPath,
boolean isPrefixPath,
- int level) {
+ int level,
+ String key,
+ String value,
+ boolean isContains) {
this.sourceId = sourceId;
this.operatorContext = operatorContext;
this.partialPath = partialPath;
this.isPrefixPath = isPrefixPath;
this.level = level;
+ this.key = key;
+ this.value = value;
+ this.isContains = isContains;
}
@Override
@@ -71,10 +80,19 @@ public class LevelTimeSeriesCountOperator implements SourceOperator {
new TsBlockBuilder(HeaderConstant.countLevelTimeSeriesHeader.getRespDataTypes());
Map<PartialPath, Integer> countMap;
try {
- countMap =
- ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
- .getSchemaRegion()
- .getMeasurementCountGroupByLevel(partialPath, level, isPrefixPath);
+ if (key != null && value != null) {
+ countMap =
+ ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
+ .getSchemaRegion()
+ .getMeasurementCountGroupByLevel(
+ partialPath, level, isPrefixPath, key, value, isContains);
+ } else {
+ countMap =
+ ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
+ .getSchemaRegion()
+ .getMeasurementCountGroupByLevel(partialPath, level, isPrefixPath);
+ }
+
} catch (MetadataException e) {
throw new RuntimeException(e.getMessage(), e);
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesCountOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesCountOperator.java
index e3662fc742..0fac3e052a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesCountOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesCountOperator.java
@@ -34,6 +34,9 @@ public class TimeSeriesCountOperator implements SourceOperator {
private final OperatorContext operatorContext;
private final PartialPath partialPath;
private final boolean isPrefixPath;
+ private final String key;
+ private final String value;
+ private final boolean isContains;
private boolean isFinished;
@@ -46,11 +49,17 @@ public class TimeSeriesCountOperator implements SourceOperator {
PlanNodeId sourceId,
OperatorContext operatorContext,
PartialPath partialPath,
- boolean isPrefixPath) {
+ boolean isPrefixPath,
+ String key,
+ String value,
+ boolean isContains) {
this.sourceId = sourceId;
this.operatorContext = operatorContext;
this.partialPath = partialPath;
this.isPrefixPath = isPrefixPath;
+ this.key = key;
+ this.value = value;
+ this.isContains = isContains;
}
@Override
@@ -65,10 +74,17 @@ public class TimeSeriesCountOperator implements SourceOperator {
new TsBlockBuilder(HeaderConstant.countTimeSeriesHeader.getRespDataTypes());
int count = 0;
try {
- count =
- ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
- .getSchemaRegion()
- .getAllTimeseriesCount(partialPath, isPrefixPath);
+ if (key != null && value != null) {
+ count =
+ ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
+ .getSchemaRegion()
+ .getAllTimeseriesCount(partialPath, isPrefixPath, key, value, isContains);
+ } else {
+ count =
+ ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
+ .getSchemaRegion()
+ .getAllTimeseriesCount(partialPath, isPrefixPath);
+ }
} catch (MetadataException e) {
throw new RuntimeException(e.getMessage(), e);
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 4e7d8b6899..aecf817cd5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -190,7 +190,6 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
/** Data Definition Language (DDL) */
// Create Timeseries ========================================================================
-
@Override
public Statement visitCreateNonAlignedTimeseries(
IoTDBSqlParser.CreateNonAlignedTimeseriesContext ctx) {
@@ -522,8 +521,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
new ShowTimeSeriesStatement(
new PartialPath(SQLConstant.getSingleRootArray()), orderByHeat);
}
- if (ctx.showWhereClause() != null) {
- parseShowWhereClause(ctx.showWhereClause(), showTimeSeriesStatement);
+ if (ctx.tagWhereClause() != null) {
+ parseTagWhereClause(ctx.tagWhereClause(), showTimeSeriesStatement);
}
if (ctx.limitClause() != null) {
parseLimitClause(ctx.limitClause(), showTimeSeriesStatement);
@@ -531,19 +530,34 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
return showTimeSeriesStatement;
}
- private void parseShowWhereClause(
- IoTDBSqlParser.ShowWhereClauseContext ctx, ShowTimeSeriesStatement statement) {
+ private void parseTagWhereClause(IoTDBSqlParser.TagWhereClauseContext ctx, Statement statement) {
IoTDBSqlParser.AttributeValueContext attributeValueContext;
+ String key;
+ String value;
+ boolean isContains;
if (ctx.containsExpression() != null) {
- statement.setContains(true);
+ isContains = true;
attributeValueContext = ctx.containsExpression().attributeValue();
- statement.setKey(parseAttributeKey(ctx.containsExpression().attributeKey()));
+ key = parseAttributeKey(ctx.containsExpression().attributeKey());
} else {
- statement.setContains(false);
+ isContains = false;
attributeValueContext = ctx.attributePair().attributeValue();
- statement.setKey(parseAttributeKey(ctx.attributePair().attributeKey()));
+ key = parseAttributeKey(ctx.attributePair().attributeKey());
+ }
+ value = parseAttributeValue(attributeValueContext);
+ if (statement instanceof ShowTimeSeriesStatement) {
+ ((ShowTimeSeriesStatement) statement).setContains(isContains);
+ ((ShowTimeSeriesStatement) statement).setKey(key);
+ ((ShowTimeSeriesStatement) statement).setValue(value);
+ } else if (statement instanceof CountTimeSeriesStatement) {
+ ((CountTimeSeriesStatement) statement).setContains(isContains);
+ ((CountTimeSeriesStatement) statement).setKey(key);
+ ((CountTimeSeriesStatement) statement).setValue(value);
+ } else if (statement instanceof CountLevelTimeSeriesStatement) {
+ ((CountLevelTimeSeriesStatement) statement).setContains(isContains);
+ ((CountLevelTimeSeriesStatement) statement).setKey(key);
+ ((CountLevelTimeSeriesStatement) statement).setValue(value);
}
- statement.setValue(parseAttributeValue(attributeValueContext));
}
// Show Storage Group
@@ -594,6 +608,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
// Count TimeSeries ========================================================================
@Override
public Statement visitCountTimeseries(CountTimeseriesContext ctx) {
+ Statement statement;
PartialPath path;
if (ctx.prefixPath() != null) {
path = parsePrefixPath(ctx.prefixPath());
@@ -602,9 +617,14 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
}
if (ctx.INTEGER_LITERAL() != null) {
int level = Integer.parseInt(ctx.INTEGER_LITERAL().getText());
- return new CountLevelTimeSeriesStatement(path, level);
+ statement = new CountLevelTimeSeriesStatement(path, level);
+ } else {
+ statement = new CountTimeSeriesStatement(path);
+ }
+ if (ctx.tagWhereClause() != null) {
+ parseTagWhereClause(ctx.tagWhereClause(), statement);
}
- return new CountTimeSeriesStatement(path);
+ return statement;
}
// Count Nodes ========================================================================
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
index 51d2760e72..33eb8f249c 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
@@ -513,7 +513,13 @@ public class LocalExecutionPlanner {
TimeSeriesCountOperator.class.getSimpleName());
context.getTimeSliceAllocator().recordExecutionWeight(operatorContext, 1);
return new TimeSeriesCountOperator(
- node.getPlanNodeId(), operatorContext, node.getPath(), node.isPrefixPath());
+ node.getPlanNodeId(),
+ operatorContext,
+ node.getPath(),
+ node.isPrefixPath(),
+ node.getKey(),
+ node.getValue(),
+ node.isContains());
}
@Override
@@ -530,7 +536,10 @@ public class LocalExecutionPlanner {
operatorContext,
node.getPath(),
node.isPrefixPath(),
- node.getLevel());
+ node.getLevel(),
+ node.getKey(),
+ node.getValue(),
+ node.isContains());
}
@Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
index 53cd1b10bc..eec1c6c026 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
@@ -762,17 +762,30 @@ public class LogicalPlanBuilder {
return this;
}
- public LogicalPlanBuilder planTimeSeriesCountSource(PartialPath partialPath, boolean prefixPath) {
+ public LogicalPlanBuilder planTimeSeriesCountSource(
+ PartialPath partialPath, boolean prefixPath, String key, String value, boolean isContains) {
this.root =
- new TimeSeriesCountNode(context.getQueryId().genPlanNodeId(), partialPath, prefixPath);
+ new TimeSeriesCountNode(
+ context.getQueryId().genPlanNodeId(), partialPath, prefixPath, key, value, isContains);
return this;
}
public LogicalPlanBuilder planLevelTimeSeriesCountSource(
- PartialPath partialPath, boolean prefixPath, int level) {
+ PartialPath partialPath,
+ boolean prefixPath,
+ int level,
+ String key,
+ String value,
+ boolean isContains) {
this.root =
new LevelTimeSeriesCountNode(
- context.getQueryId().genPlanNodeId(), partialPath, prefixPath, level);
+ context.getQueryId().genPlanNodeId(),
+ partialPath,
+ prefixPath,
+ level,
+ key,
+ value,
+ isContains);
return this;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
index 06bcce4417..0c9922a0f5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
@@ -538,7 +538,11 @@ public class LogicalPlanVisitor extends StatementVisitor<PlanNode, MPPQueryConte
LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(context);
return planBuilder
.planTimeSeriesCountSource(
- countTimeSeriesStatement.getPartialPath(), countTimeSeriesStatement.isPrefixPath())
+ countTimeSeriesStatement.getPartialPath(),
+ countTimeSeriesStatement.isPrefixPath(),
+ countTimeSeriesStatement.getKey(),
+ countTimeSeriesStatement.getValue(),
+ countTimeSeriesStatement.isContains())
.planCountMerge()
.getRoot();
}
@@ -551,7 +555,10 @@ public class LogicalPlanVisitor extends StatementVisitor<PlanNode, MPPQueryConte
.planLevelTimeSeriesCountSource(
countLevelTimeSeriesStatement.getPartialPath(),
countLevelTimeSeriesStatement.isPrefixPath(),
- countLevelTimeSeriesStatement.getLevel())
+ countLevelTimeSeriesStatement.getLevel(),
+ countLevelTimeSeriesStatement.getKey(),
+ countLevelTimeSeriesStatement.getValue(),
+ countLevelTimeSeriesStatement.isContains())
.planCountMerge()
.getRoot();
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
index 5b5b9856d2..d450d765b7 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
@@ -35,20 +35,45 @@ import java.util.Objects;
public class LevelTimeSeriesCountNode extends SchemaQueryScanNode {
private final int level;
+ private final String key;
+ private final String value;
+ private final boolean isContains;
public LevelTimeSeriesCountNode(
- PlanNodeId id, PartialPath partialPath, boolean isPrefixPath, int level) {
+ PlanNodeId id,
+ PartialPath partialPath,
+ boolean isPrefixPath,
+ int level,
+ String key,
+ String value,
+ boolean isContains) {
super(id, partialPath, isPrefixPath);
this.level = level;
+ this.key = key;
+ this.value = value;
+ this.isContains = isContains;
}
public int getLevel() {
return level;
}
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isContains() {
+ return isContains;
+ }
+
@Override
public PlanNode clone() {
- return new LevelTimeSeriesCountNode(getPlanNodeId(), path, isPrefixPath, level);
+ return new LevelTimeSeriesCountNode(
+ getPlanNodeId(), path, isPrefixPath, level, key, value, isContains);
}
@Override
@@ -62,6 +87,9 @@ public class LevelTimeSeriesCountNode extends SchemaQueryScanNode {
ReadWriteIOUtils.write(path.getFullPath(), byteBuffer);
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
ReadWriteIOUtils.write(level, byteBuffer);
+ ReadWriteIOUtils.write(key, byteBuffer);
+ ReadWriteIOUtils.write(value, byteBuffer);
+ ReadWriteIOUtils.write(isContains, byteBuffer);
}
@Override
@@ -70,6 +98,9 @@ public class LevelTimeSeriesCountNode extends SchemaQueryScanNode {
ReadWriteIOUtils.write(path.getFullPath(), stream);
ReadWriteIOUtils.write(isPrefixPath, stream);
ReadWriteIOUtils.write(level, stream);
+ ReadWriteIOUtils.write(key, stream);
+ ReadWriteIOUtils.write(value, stream);
+ ReadWriteIOUtils.write(isContains, stream);
}
public static PlanNode deserialize(ByteBuffer buffer) {
@@ -82,8 +113,12 @@ public class LevelTimeSeriesCountNode extends SchemaQueryScanNode {
}
boolean isPrefixPath = ReadWriteIOUtils.readBool(buffer);
int level = ReadWriteIOUtils.readInt(buffer);
+ String key = ReadWriteIOUtils.readString(buffer);
+ String value = ReadWriteIOUtils.readString(buffer);
+ boolean isContains = ReadWriteIOUtils.readBool(buffer);
PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
- return new LevelTimeSeriesCountNode(planNodeId, path, isPrefixPath, level);
+ return new LevelTimeSeriesCountNode(
+ planNodeId, path, isPrefixPath, level, key, value, isContains);
}
@Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
index b98f3447e5..34b5827412 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
@@ -34,13 +34,38 @@ import java.util.List;
public class TimeSeriesCountNode extends SchemaQueryScanNode {
- public TimeSeriesCountNode(PlanNodeId id, PartialPath partialPath, boolean isPrefixPath) {
+ private final String key;
+ private final String value;
+ private final boolean isContains;
+
+ public TimeSeriesCountNode(
+ PlanNodeId id,
+ PartialPath partialPath,
+ boolean isPrefixPath,
+ String key,
+ String value,
+ boolean isContains) {
super(id, partialPath, isPrefixPath);
+ this.key = key;
+ this.value = value;
+ this.isContains = isContains;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isContains() {
+ return isContains;
}
@Override
public PlanNode clone() {
- return new TimeSeriesCountNode(getPlanNodeId(), path, isPrefixPath);
+ return new TimeSeriesCountNode(getPlanNodeId(), path, isPrefixPath, key, value, isContains);
}
@Override
@@ -53,6 +78,9 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode {
PlanNodeType.TIME_SERIES_COUNT.serialize(byteBuffer);
ReadWriteIOUtils.write(path.getFullPath(), byteBuffer);
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
+ ReadWriteIOUtils.write(key, byteBuffer);
+ ReadWriteIOUtils.write(value, byteBuffer);
+ ReadWriteIOUtils.write(isContains, byteBuffer);
}
@Override
@@ -60,6 +88,9 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode {
PlanNodeType.TIME_SERIES_COUNT.serialize(stream);
ReadWriteIOUtils.write(path.getFullPath(), stream);
ReadWriteIOUtils.write(isPrefixPath, stream);
+ ReadWriteIOUtils.write(key, stream);
+ ReadWriteIOUtils.write(value, stream);
+ ReadWriteIOUtils.write(isContains, stream);
}
public static PlanNode deserialize(ByteBuffer buffer) {
@@ -71,7 +102,10 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode {
throw new IllegalArgumentException("Cannot deserialize DevicesSchemaScanNode", e);
}
boolean isPrefixPath = ReadWriteIOUtils.readBool(buffer);
+ String key = ReadWriteIOUtils.readString(buffer);
+ String value = ReadWriteIOUtils.readString(buffer);
+ boolean isContains = ReadWriteIOUtils.readBool(buffer);
PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
- return new TimeSeriesCountNode(planNodeId, path, isPrefixPath);
+ return new TimeSeriesCountNode(planNodeId, path, isPrefixPath, key, value, isContains);
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountLevelTimeSeriesStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountLevelTimeSeriesStatement.java
index 30e8678543..c48b32fed1 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountLevelTimeSeriesStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountLevelTimeSeriesStatement.java
@@ -24,6 +24,10 @@ import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
public class CountLevelTimeSeriesStatement extends CountStatement {
private int level;
+ private String key;
+ private String value;
+
+ private boolean isContains;
public CountLevelTimeSeriesStatement(PartialPath partialPath, int level) {
super(partialPath);
@@ -34,6 +38,34 @@ public class CountLevelTimeSeriesStatement extends CountStatement {
return level;
}
+ public void setLevel(int level) {
+ this.level = level;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public boolean isContains() {
+ return isContains;
+ }
+
+ public void setContains(boolean contains) {
+ isContains = contains;
+ }
+
@Override
public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
return visitor.visitCountLevelTimeSeries(this, context);
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountTimeSeriesStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountTimeSeriesStatement.java
index 5ba529bf82..bc643daab9 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountTimeSeriesStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/CountTimeSeriesStatement.java
@@ -23,10 +23,40 @@ import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
public class CountTimeSeriesStatement extends CountStatement {
+
+ private String key;
+ private String value;
+
+ private boolean isContains;
+
public CountTimeSeriesStatement(PartialPath partialPath) {
super(partialPath);
}
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public boolean isContains() {
+ return isContains;
+ }
+
+ public void setContains(boolean contains) {
+ isContains = contains;
+ }
+
@Override
public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
return visitor.visitCountTimeSeries(this, context);
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 af5b8ec2e8..650095f01e 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
@@ -1057,8 +1057,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
new PartialPath(SQLConstant.getSingleRootArray()),
orderByHeat);
}
- if (ctx.showWhereClause() != null) {
- parseShowWhereClause(ctx.showWhereClause(), showTimeSeriesOperator);
+ if (ctx.tagWhereClause() != null) {
+ parseShowWhereClause(ctx.tagWhereClause(), showTimeSeriesOperator);
}
if (ctx.limitClause() != null) {
parseLimitClause(ctx.limitClause(), showTimeSeriesOperator);
@@ -1067,7 +1067,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
}
private void parseShowWhereClause(
- IoTDBSqlParser.ShowWhereClauseContext ctx, ShowTimeSeriesOperator operator) {
+ IoTDBSqlParser.TagWhereClauseContext ctx, ShowTimeSeriesOperator operator) {
IoTDBSqlParser.AttributeValueContext attributeValueContext;
if (ctx.containsExpression() != null) {
operator.setContains(true);
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/CountMergeOperatorTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/CountMergeOperatorTest.java
index 8e154eddda..9264d38a9a 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/CountMergeOperatorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/CountMergeOperatorTest.java
@@ -100,7 +100,13 @@ public class CountMergeOperatorTest {
.setDriverContext(new SchemaDriverContext(fragmentInstanceContext, schemaRegion));
TimeSeriesCountOperator timeSeriesCountOperator =
new TimeSeriesCountOperator(
- planNodeId, fragmentInstanceContext.getOperatorContexts().get(0), partialPath, true);
+ planNodeId,
+ fragmentInstanceContext.getOperatorContexts().get(0),
+ partialPath,
+ true,
+ null,
+ null,
+ false);
TsBlock tsBlock = null;
while (timeSeriesCountOperator.hasNext()) {
tsBlock = timeSeriesCountOperator.next();
@@ -112,6 +118,9 @@ public class CountMergeOperatorTest {
planNodeId,
fragmentInstanceContext.getOperatorContexts().get(0),
new PartialPath(COUNT_MERGE_OPERATOR_TEST_SG + ".device1.*"),
+ false,
+ null,
+ null,
false);
tsBlock = timeSeriesCountOperator2.next();
assertFalse(timeSeriesCountOperator2.hasNext());
@@ -155,14 +164,20 @@ public class CountMergeOperatorTest {
fragmentInstanceContext.getOperatorContexts().get(0),
new PartialPath(COUNT_MERGE_OPERATOR_TEST_SG),
true,
- 2);
+ 2,
+ null,
+ null,
+ false);
LevelTimeSeriesCountOperator timeSeriesCountOperator2 =
new LevelTimeSeriesCountOperator(
planNodeId,
fragmentInstanceContext.getOperatorContexts().get(0),
new PartialPath(COUNT_MERGE_OPERATOR_TEST_SG + ".device2"),
true,
- 2);
+ 2,
+ null,
+ null,
+ false);
CountMergeOperator countMergeOperator =
new CountMergeOperator(
planNodeId,
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaCountOperatorTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaCountOperatorTest.java
index d714401d99..f664633ba7 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaCountOperatorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaCountOperatorTest.java
@@ -140,7 +140,13 @@ public class SchemaCountOperatorTest {
.setDriverContext(new SchemaDriverContext(fragmentInstanceContext, schemaRegion));
TimeSeriesCountOperator timeSeriesCountOperator =
new TimeSeriesCountOperator(
- planNodeId, fragmentInstanceContext.getOperatorContexts().get(0), partialPath, true);
+ planNodeId,
+ fragmentInstanceContext.getOperatorContexts().get(0),
+ partialPath,
+ true,
+ null,
+ null,
+ false);
TsBlock tsBlock = null;
while (timeSeriesCountOperator.hasNext()) {
tsBlock = timeSeriesCountOperator.next();
@@ -152,6 +158,9 @@ public class SchemaCountOperatorTest {
planNodeId,
fragmentInstanceContext.getOperatorContexts().get(0),
new PartialPath(SCHEMA_COUNT_OPERATOR_TEST_SG + ".device1.*"),
+ false,
+ null,
+ null,
false);
tsBlock = timeSeriesCountOperator2.next();
assertFalse(timeSeriesCountOperator2.hasNext());
@@ -195,7 +204,10 @@ public class SchemaCountOperatorTest {
fragmentInstanceContext.getOperatorContexts().get(0),
partialPath,
true,
- 2);
+ 2,
+ null,
+ null,
+ false);
TsBlock tsBlock = null;
while (timeSeriesCountOperator.hasNext()) {
tsBlock = timeSeriesCountOperator.next();
@@ -215,7 +227,10 @@ public class SchemaCountOperatorTest {
fragmentInstanceContext.getOperatorContexts().get(0),
partialPath,
true,
- 1);
+ 1,
+ null,
+ null,
+ false);
while (timeSeriesCountOperator2.hasNext()) {
tsBlock = timeSeriesCountOperator2.next();
}
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/read/SchemaCountNodeSerdeTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/read/SchemaCountNodeSerdeTest.java
index 532fe6fdf4..d79d959850 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/read/SchemaCountNodeSerdeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/read/SchemaCountNodeSerdeTest.java
@@ -70,7 +70,13 @@ public class SchemaCountNodeSerdeTest {
ExchangeNode exchangeNode = new ExchangeNode(new PlanNodeId("exchange"));
LevelTimeSeriesCountNode levelTimeSeriesCountNode =
new LevelTimeSeriesCountNode(
- new PlanNodeId("timeseriesCount"), new PartialPath("root.sg.device0"), true, 10);
+ new PlanNodeId("timeseriesCount"),
+ new PartialPath("root.sg.device0"),
+ true,
+ 10,
+ null,
+ null,
+ false);
FragmentSinkNode fragmentSinkNode = new FragmentSinkNode(new PlanNodeId("fragmentSink"));
fragmentSinkNode.addChild(levelTimeSeriesCountNode);
fragmentSinkNode.setDownStream(