You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2023/03/16 10:29:49 UTC
[iotdb] branch master updated: [IOTDB-5683] Support aggregation function Mode for query
This is an automated email from the ASF dual-hosted git repository.
jackietien 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 637cd48803 [IOTDB-5683] Support aggregation function Mode for query
637cd48803 is described below
commit 637cd488033762d8aa236c440f349c23da8c65e8
Author: Weihao Li <60...@users.noreply.github.com>
AuthorDate: Thu Mar 16 18:29:42 2023 +0800
[IOTDB-5683] Support aggregation function Mode for query
---
docs/UserGuide/Operators-Functions/Aggregation.md | 28 ++--
.../UserGuide/Operators-Functions/Aggregation.md | 2 +-
.../apache/iotdb/itbase/constant/TestConstant.java | 4 +
.../iotdb/db/it/aggregation/IoTDBModeIT.java | 160 ++++++++++++++++++
.../iotdb/libudf/it/dprofile/DProfileIT.java | 3 +-
library-udf/src/assembly/tools/register-UDF.bat | 1 -
library-udf/src/assembly/tools/register-UDF.sh | 1 -
.../apache/iotdb/library/dprofile/UDAFMode.java | 178 --------------------
.../resources/conf/iotdb-common.properties | 4 +
.../udf/builtin/BuiltinAggregationFunction.java | 5 +-
server/src/main/codegen/dataModel/AllDataType.tdd | 24 ++-
.../src/main/codegen/templates/ModeAccumulator.ftl | 179 +++++++++++++++++++++
.../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 10 ++
.../org/apache/iotdb/db/conf/IoTDBDescriptor.java | 9 ++
.../org/apache/iotdb/db/constant/SqlConstant.java | 3 +-
.../db/mpp/aggregation/AccumulatorFactory.java | 21 +++
.../SlidingWindowAggregatorFactory.java | 2 +
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 1 +
.../org/apache/iotdb/db/utils/SchemaUtils.java | 2 +
.../apache/iotdb/db/utils/TypeInferenceUtils.java | 3 +
thrift-commons/src/main/thrift/common.thrift | 3 +-
.../iotdb/tsfile/utils/ReadWriteIOUtils.java | 7 +
22 files changed, 444 insertions(+), 206 deletions(-)
diff --git a/docs/UserGuide/Operators-Functions/Aggregation.md b/docs/UserGuide/Operators-Functions/Aggregation.md
index 0be24a85ec..557929878a 100644
--- a/docs/UserGuide/Operators-Functions/Aggregation.md
+++ b/docs/UserGuide/Operators-Functions/Aggregation.md
@@ -27,21 +27,21 @@ All aggregate functions except `COUNT()`, `COUNT_IF()` ignore null values and re
The aggregate functions supported by IoTDB are as follows:
-| Function Name | Function Description | Allowed Input Data Types | Output Data Types [...]
-|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------| ------------------------ |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [...]
-| SUM | Summation. | INT32 INT64 FLOAT DOUBLE | DOUBLE [...]
-| COUNT | Counts the number of data points. | All types | INT [...]
-| AVG | Average. | INT32 INT64 FLOAT DOUBLE | DOUBLE [...]
-| EXTREME | Finds the value with the largest absolute value. Returns a positive value if the maximum absolute value of positive and negative values is equal. | INT32 INT64 FLOAT DOUBLE | Consistent with the input data type [...]
-| MAX_VALUE | Find the maximum value. | INT32 INT64 FLOAT DOUBLE | Consistent with the input data type [...]
-| MIN_VALUE | Find the minimum value. | INT32 INT64 FLOAT DOUBLE | Consistent with the input data type [...]
-| FIRST_VALUE | Find the value with the smallest timestamp. | All data types | Consistent with input data type [...]
-| LAST_VALUE | Find the value with the largest timestamp. | All data types | Consistent with input data type [...]
-| MAX_TIME | Find the maximum timestamp. | All data Types | Timestamp [...]
-| MIN_TIME | Find the minimum timestamp. | All data Types | Timestamp [...]
+| Function Name | Function Description | Allowed Input Data Types | required attributes [...]
+|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------| ------------------------ |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [...]
+| SUM | Summation. | INT32 INT64 FLOAT DOUBLE | No [...]
+| COUNT | Counts the number of data points. | All types | No [...]
+| AVG | Average. | INT32 INT64 FLOAT DOUBLE | No [...]
+| EXTREME | Finds the value with the largest absolute value. Returns a positive value if the maximum absolute value of positive and negative values is equal. | INT32 INT64 FLOAT DOUBLE | No [...]
+| MAX_VALUE | Find the maximum value. | INT32 INT64 FLOAT DOUBLE | No [...]
+| MIN_VALUE | Find the minimum value. | INT32 INT64 FLOAT DOUBLE | No [...]
+| FIRST_VALUE | Find the value with the smallest timestamp. | All data types | No [...]
+| LAST_VALUE | Find the value with the largest timestamp. | All data types | No [...]
+| MAX_TIME | Find the maximum timestamp. | All data Types | No [...]
+| MIN_TIME | Find the minimum timestamp. | All data Types | No [...]
| COUNT_IF | Find the number of data points that continuously meet a given condition and the number of data points that meet the condition (represented by keep) meet the specified threshold. | BOOLEAN | `[keep >=/>/=/!=/</<=]threshold`:The specified threshold or threshold condition, it is equivalent to `keep >= threshold` if `threshold` is used alone, type of `threshold` is `INT64`<br/> `ignoreNull`:Optional, default value is `true`;If the value is `true`, null valu [...]
-| TIME_DURATION | Find the difference between the timestamp of the largest non-null value and the timestamp of the smallest non-null value in a column | All data Types | INT64 [...]
-
+| TIME_DURATION | Find the difference between the timestamp of the largest non-null value and the timestamp of the smallest non-null value in a column | All data Types | No [...]
+| MODE | Find the mode. Note: Having too many different values in the input series risks a memory exception. | All data Types | No [...]
## COUNT
### example
diff --git a/docs/zh/UserGuide/Operators-Functions/Aggregation.md b/docs/zh/UserGuide/Operators-Functions/Aggregation.md
index 61fe31d916..995aef81fa 100644
--- a/docs/zh/UserGuide/Operators-Functions/Aggregation.md
+++ b/docs/zh/UserGuide/Operators-Functions/Aggregation.md
@@ -41,7 +41,7 @@ IoTDB 支持的聚合函数如下:
| MIN_TIME | 求最小时间戳。 | 所有类型 | 无 | Timestamp |
| COUNT_IF | 求数据点连续满足某一给定条件,且满足条件的数据点个数(用keep表示)满足指定阈值的次数。 | BOOLEAN | `[keep >=/>/=/!=/</<=]threshold`:被指定的阈值或阈值条件,若只使用`threshold`则等价于`keep >= threshold`,`threshold`类型为`INT64`<br/> `ignoreNull`:可选,默认为`true`;为`true`表示忽略null值,即如果中间出现null值,直接忽略,不会打断连续性;为`false`表示不忽略null值,即如果中间出现null值,会打断连续性 | INT64 |
| TIME_DURATION | 求某一列最大一个不为NULL的值所在时间戳与最小一个不为NULL的值所在时间戳的时间戳差 | 所有类型 | 无 | INT64 |
-
+| MODE | 求众数。注意:输入序列的不同值个数过多时会有内存异常风险。 | 所有类型 | 无 | INT64 |
### COUNT_IF
#### 语法
diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/TestConstant.java b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/TestConstant.java
index 1ae9ca784a..6b01463ea4 100644
--- a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/TestConstant.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/TestConstant.java
@@ -115,6 +115,10 @@ public class TestConstant {
return String.format("time_duration(%s)", path);
}
+ public static String mode(String path) {
+ return String.format("mode(%s)", path);
+ }
+
public static String recordToInsert(TSRecord record) {
StringBuilder measurements = new StringBuilder();
StringBuilder values = new StringBuilder();
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBModeIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBModeIT.java
new file mode 100644
index 0000000000..37e8883182
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBModeIT.java
@@ -0,0 +1,160 @@
+/*
+ * 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.db.it.aggregation;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import static org.apache.iotdb.db.it.utils.TestUtils.assertTestFail;
+import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.apache.iotdb.itbase.constant.TestConstant.DEVICE;
+import static org.apache.iotdb.itbase.constant.TestConstant.mode;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBModeIT {
+ protected static final String[] SQLs =
+ new String[] {
+ "CREATE DATABASE root.db",
+ "CREATE TIMESERIES root.db.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d1.s2 WITH DATATYPE=INT64, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d1.s3 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d1.s4 WITH DATATYPE=FLOAT, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d1.s5 WITH DATATYPE=DOUBLE, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d1.s6 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s2 WITH DATATYPE=INT64, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s3 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s4 WITH DATATYPE=FLOAT, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s5 WITH DATATYPE=DOUBLE, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.db.d2.s6 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(1, 1, 1, true, 1, 1, \"1\")",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(2, 2, 2, false, 2, 2, \"2\")",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(3, 2, 2, false, 2, 2, \"2\")",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(10000000000, 1, 1, true, 1, 1, \"1\")",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(10000000001, 1, 1, true, 1, 1, \"1\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(1, 1, 1, true, 1, 1, \"1\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(2, 1, 1, true, 1, 1, \"1\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(10000000000, 2, 2, false, 2, 2, \"2\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(10000000001, 2, 2, false, 2, 2, \"2\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(10000000002, 2, 2, false, 2, 2, \"2\")",
+ "INSERT INTO root.db.d2(timestamp,s1,s2,s3,s4,s5,s6) values(10000000003, 2, 2, false, 2, 2, \"2\")",
+ "flush"
+ };
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ EnvFactory.getEnv().getConfig().getCommonConfig().setPartitionInterval(1000);
+ EnvFactory.getEnv().initClusterEnvironment();
+ prepareData(SQLs);
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ EnvFactory.getEnv().cleanClusterEnvironment();
+ }
+
+ @Test
+ public void testModeWithDifferentTypes() {
+ String[] expectedHeader =
+ new String[] {
+ mode("root.db.d1.s1"),
+ mode("root.db.d1.s2"),
+ mode("root.db.d1.s3"),
+ mode("root.db.d1.s4"),
+ mode("root.db.d1.s5"),
+ mode("root.db.d1.s6"),
+ };
+ String[] retArray = new String[] {"1,1,true,1.0,1.0,1,"};
+ resultSetEqualTest(
+ "select mode(s1),mode(s2),mode(s3),mode(s4),mode(s5),mode(s6) from root.db.d1",
+ expectedHeader,
+ retArray);
+
+ retArray = new String[] {"2,2,false,2.0,2.0,2,"};
+ resultSetEqualTest(
+ "select mode(s1),mode(s2),mode(s3),mode(s4),mode(s5),mode(s6) from root.db.d1 where time < 10",
+ expectedHeader,
+ retArray);
+ }
+
+ @Test
+ public void testModeAlignByDevice() {
+ String[] expectedHeader =
+ new String[] {
+ DEVICE, mode("s1"), mode("s2"), mode("s3"), mode("s4"), mode("s5"), mode("s6"),
+ };
+ String[] retArray = new String[] {"root.db.d1,1,1,true,1.0,1.0,1,"};
+ resultSetEqualTest(
+ "select mode(s1),mode(s2),mode(s3),mode(s4),mode(s5),mode(s6) from root.db.d1 align by device",
+ expectedHeader,
+ retArray);
+
+ retArray = new String[] {"root.db.d1,2,2,false,2.0,2.0,2,"};
+ resultSetEqualTest(
+ "select mode(s1),mode(s2),mode(s3),mode(s4),mode(s5),mode(s6) from root.db.d1 where time < 10 align by device",
+ expectedHeader,
+ retArray);
+ }
+
+ @Test
+ public void testModeInHaving() {
+ String[] expectedHeader = new String[] {mode("root.db.d1.s1")};
+ String[] retArray = new String[] {"1,"};
+ resultSetEqualTest(
+ "select mode(s1) from root.db.d1 having mode(s2)>0", expectedHeader, retArray);
+ }
+
+ @Test
+ public void testModeWithGroupByLevel() {
+ String[] expectedHeader =
+ new String[] {
+ mode("root.*.*.s1"),
+ mode("root.*.*.s2"),
+ mode("root.*.*.s3"),
+ mode("root.*.*.s4"),
+ mode("root.*.*.s5"),
+ mode("root.*.*.s6"),
+ };
+ String[] retArray = new String[] {"2,2,false,2.0,2.0,2,"};
+ resultSetEqualTest(
+ "select mode(s1),mode(s2),mode(s3),mode(s4),mode(s5),mode(s6) from root.** group by level = 0",
+ expectedHeader,
+ retArray);
+ }
+
+ @Test
+ public void testModeWithSlidingWindow() {
+ assertTestFail(
+ "select mode(s1) from root.db.d1 group by time([1,10),3ms,2ms)",
+ TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()
+ + ": MODE with slidingWindow is not supported now");
+ }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/libudf/it/dprofile/DProfileIT.java b/integration-test/src/test/java/org/apache/iotdb/libudf/it/dprofile/DProfileIT.java
index 3012831226..32aff590f0 100644
--- a/integration-test/src/test/java/org/apache/iotdb/libudf/it/dprofile/DProfileIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/libudf/it/dprofile/DProfileIT.java
@@ -117,7 +117,6 @@ public class DProfileIT {
"create function integralavg as 'org.apache.iotdb.library.dprofile.UDAFIntegralAvg'");
statement.execute("create function mad as 'org.apache.iotdb.library.dprofile.UDAFMad'");
statement.execute("create function median as 'org.apache.iotdb.library.dprofile.UDAFMedian'");
- statement.execute("create function mode as 'org.apache.iotdb.library.dprofile.UDAFMode'");
statement.execute(
"create function percentile as 'org.apache.iotdb.library.dprofile.UDAFPercentile'");
statement.execute("create function period as 'org.apache.iotdb.library.dprofile.UDAFPeriod'");
@@ -258,7 +257,7 @@ public class DProfileIT {
}
@Test
- public void testMode1() {
+ public void testConsistency1() {
String sqlStr = "select consistency(d1.s1) from root.vehicle";
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
diff --git a/library-udf/src/assembly/tools/register-UDF.bat b/library-udf/src/assembly/tools/register-UDF.bat
index 41d6414e16..ca399ce8f6 100644
--- a/library-udf/src/assembly/tools/register-UDF.bat
+++ b/library-udf/src/assembly/tools/register-UDF.bat
@@ -31,7 +31,6 @@ call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "creat
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function integralavg as 'org.apache.iotdb.library.dprofile.UDAFIntegralAvg'"
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function mad as 'org.apache.iotdb.library.dprofile.UDAFMad'"
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function median as 'org.apache.iotdb.library.dprofile.UDAFMedian'"
-call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function mode as 'org.apache.iotdb.library.dprofile.UDAFMode'"
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function percentile as 'org.apache.iotdb.library.dprofile.UDAFPercentile'"
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function quantile as 'org.apache.iotdb.library.dprofile.UDAFQuantile'"
call ../sbin/start-cli.bat -h %host% -p %rpcPort% -u %user% -pw %pass% -e "create function period as 'org.apache.iotdb.library.dprofile.UDAFPeriod'"
diff --git a/library-udf/src/assembly/tools/register-UDF.sh b/library-udf/src/assembly/tools/register-UDF.sh
index d0fe1b1887..3021a766d7 100755
--- a/library-udf/src/assembly/tools/register-UDF.sh
+++ b/library-udf/src/assembly/tools/register-UDF.sh
@@ -33,7 +33,6 @@ pass=root
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function integralavg as 'org.apache.iotdb.library.dprofile.UDAFIntegralAvg'"
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function mad as 'org.apache.iotdb.library.dprofile.UDAFMad'"
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function median as 'org.apache.iotdb.library.dprofile.UDAFMedian'"
-../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function mode as 'org.apache.iotdb.library.dprofile.UDAFMode'"
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function percentile as 'org.apache.iotdb.library.dprofile.UDAFPercentile'"
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function quantile as 'org.apache.iotdb.library.dprofile.UDAFQuantile'"
../sbin/start-cli.sh -h $host -p $rpcPort -u $user -pw $pass -e "create function period as 'org.apache.iotdb.library.dprofile.UDAFPeriod'"
diff --git a/library-udf/src/main/java/org/apache/iotdb/library/dprofile/UDAFMode.java b/library-udf/src/main/java/org/apache/iotdb/library/dprofile/UDAFMode.java
deleted file mode 100644
index d23bb6415f..0000000000
--- a/library-udf/src/main/java/org/apache/iotdb/library/dprofile/UDAFMode.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.library.dprofile;
-
-import org.apache.iotdb.commons.udf.utils.UDFDataTypeTransformer;
-import org.apache.iotdb.library.dprofile.util.MaxSelector;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.udf.api.UDTF;
-import org.apache.iotdb.udf.api.access.Row;
-import org.apache.iotdb.udf.api.collector.PointCollector;
-import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.udf.api.customizer.parameter.UDFParameterValidator;
-import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.udf.api.customizer.strategy.RowByRowAccessStrategy;
-
-import org.eclipse.collections.impl.map.mutable.primitive.DoubleIntHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.DoubleLongHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.FloatIntHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.FloatLongHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.IntLongHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap;
-import org.eclipse.collections.impl.map.mutable.primitive.LongLongHashMap;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/** This function aggregates mode of input series. */
-public class UDAFMode implements UDTF {
-
- private IntIntHashMap intMap;
- private IntLongHashMap itMap;
- private LongIntHashMap longMap;
- private LongLongHashMap ltMap;
- private FloatIntHashMap floatMap;
- private FloatLongHashMap ftMap;
- private DoubleIntHashMap doubleMap;
- private DoubleLongHashMap dtMap;
- private int booleanCnt;
- private HashMap<String, Integer> stringMap;
- private HashMap<String, Long> stMap;
- private TSDataType dataType;
-
- @Override
- public void validate(UDFParameterValidator validator) throws Exception {
- validator.validateInputSeriesNumber(1);
- }
-
- @Override
- public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
- throws Exception {
- configurations
- .setAccessStrategy(new RowByRowAccessStrategy())
- .setOutputDataType(parameters.getDataType(0));
- dataType = UDFDataTypeTransformer.transformToTsDataType(parameters.getDataType(0));
- switch (dataType) {
- case INT32:
- intMap = new IntIntHashMap();
- itMap = new IntLongHashMap();
- break;
- case INT64:
- longMap = new LongIntHashMap();
- ltMap = new LongLongHashMap();
- break;
- case FLOAT:
- floatMap = new FloatIntHashMap();
- ftMap = new FloatLongHashMap();
- break;
- case DOUBLE:
- doubleMap = new DoubleIntHashMap();
- dtMap = new DoubleLongHashMap();
- break;
- case TEXT:
- stringMap = new HashMap<>();
- stMap = new HashMap<>();
- break;
- case BOOLEAN:
- booleanCnt = 0;
- }
- }
-
- @Override
- public void transform(Row row, PointCollector pc) throws Exception {
- switch (dataType) {
- case INT32:
- intMap.addToValue(row.getInt(0), 1);
- if (!itMap.containsKey(row.getInt(0))) {
- itMap.addToValue(row.getInt(0), row.getTime());
- }
- break;
- case INT64:
- longMap.addToValue(row.getLong(0), 1);
- if (!ltMap.containsKey(row.getLong(0))) {
- ltMap.addToValue(row.getLong(0), row.getTime());
- }
- break;
- case FLOAT:
- floatMap.addToValue(row.getFloat(0), 1);
- if (!ftMap.containsKey(row.getFloat(0))) {
- ftMap.addToValue(row.getFloat(0), row.getTime());
- }
- break;
- case DOUBLE:
- doubleMap.addToValue(row.getDouble(0), 1);
- if (!dtMap.containsKey(row.getDouble(0))) {
- dtMap.addToValue(row.getDouble(0), row.getTime());
- }
- break;
- case TEXT:
- stringMap.put(row.getString(0), stringMap.getOrDefault(row.getString(0), 0) + 1);
- if (!stMap.containsKey(row.getString(0))) {
- stMap.put(row.getString(0), row.getTime());
- }
- break;
- case BOOLEAN:
- boolean v = row.getBoolean(0);
- booleanCnt = v ? booleanCnt + 1 : booleanCnt - 1;
- }
- }
-
- @Override
- public void terminate(PointCollector pc) throws Exception {
- MaxSelector max = new MaxSelector();
- switch (dataType) {
- case INT32:
- intMap.forEachKeyValue(max::insert);
- int im = max.getInt();
- pc.putInt(itMap.get(im), im);
- break;
- case INT64:
- longMap.forEachKeyValue(max::insert);
- long lm = max.getLong();
- pc.putLong(ltMap.get(lm), lm);
- break;
- case FLOAT:
- floatMap.forEachKeyValue(max::insert);
- float fm = max.getFloat();
- pc.putFloat(ftMap.get(fm), fm);
- break;
- case DOUBLE:
- doubleMap.forEachKeyValue(max::insert);
- double dm = max.getDouble();
- pc.putDouble(dtMap.get(dm), dm);
- break;
- case TEXT:
- int maxTimes = 0;
- String s = null;
- for (Map.Entry<String, Integer> entry : stringMap.entrySet()) {
- String key = entry.getKey();
- Integer value = entry.getValue();
- if (value > maxTimes) {
- maxTimes = value;
- s = key;
- }
- }
- pc.putString(stMap.get(s), s);
- break;
- case BOOLEAN:
- pc.putBoolean(0, booleanCnt > 0);
- }
- }
-}
diff --git a/node-commons/src/assembly/resources/conf/iotdb-common.properties b/node-commons/src/assembly/resources/conf/iotdb-common.properties
index 5b520fb282..14ff363c31 100644
--- a/node-commons/src/assembly/resources/conf/iotdb-common.properties
+++ b/node-commons/src/assembly/resources/conf/iotdb-common.properties
@@ -418,6 +418,10 @@ cluster_name=defaultCluster
# Datatype: int
# degree_of_query_parallelism=0
+# The threshold of count map size when calculating the MODE aggregation function
+# Datatype: int
+# mode_map_size_threshold=10000
+
# The amount of data iterate each time in server (the number of data strips, that is, the number of different timestamps.)
# Datatype: int
# batch_size=100000
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
index 302750fe8f..43181be7ab 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
@@ -36,7 +36,8 @@ public enum BuiltinAggregationFunction {
AVG("avg"),
SUM("sum"),
COUNT_IF("count_if"),
- TIME_DURATION("time_duration");
+ TIME_DURATION("time_duration"),
+ MODE("mode");
private final String functionName;
@@ -75,6 +76,7 @@ public enum BuiltinAggregationFunction {
case "time_duration":
return true;
case "count_if":
+ case "mode":
return false;
default:
throw new IllegalArgumentException("Invalid Aggregation function: " + name);
@@ -98,6 +100,7 @@ public enum BuiltinAggregationFunction {
case "avg":
case "sum":
case "time_duration":
+ case "mode":
return true;
case "count_if":
return false;
diff --git a/server/src/main/codegen/dataModel/AllDataType.tdd b/server/src/main/codegen/dataModel/AllDataType.tdd
index 1089d8c534..018b24956a 100644
--- a/server/src/main/codegen/dataModel/AllDataType.tdd
+++ b/server/src/main/codegen/dataModel/AllDataType.tdd
@@ -20,27 +20,39 @@
"types": [
{
"dataType": "boolean",
- "column": "BooleanColumn"
+ "column": "BooleanColumn",
+ "javaBoxName": "Boolean",
+ "tsDataType": "TSDataType.BOOLEAN"
}
,{
"dataType": "int",
- "column": "IntColumn"
+ "column": "IntColumn",
+ "javaBoxName": "Integer",
+ "tsDataType": "TSDataType.INT32"
}
,{
"dataType": "long",
- "column": "LongColumn"
+ "column": "LongColumn",
+ "javaBoxName": "Long",
+ "tsDataType": "TSDataType.INT64"
}
,{
"dataType": "float",
- "column": "FloatColumn"
+ "column": "FloatColumn",
+ "javaBoxName": "Float",
+ "tsDataType": "TSDataType.FLOAT"
}
,{
"dataType": "double",
- "column": "DoubleColumn"
+ "column": "DoubleColumn",
+ "javaBoxName": "Double",
+ "tsDataType": "TSDataType.DOUBLE"
}
,{
"dataType": "Binary",
- "column": "BinaryColumn"
+ "column": "BinaryColumn",
+ "javaBoxName": "Binary",
+ "tsDataType": "TSDataType.TEXT"
}
]
}
diff --git a/server/src/main/codegen/templates/ModeAccumulator.ftl b/server/src/main/codegen/templates/ModeAccumulator.ftl
new file mode 100644
index 0000000000..62175bf628
--- /dev/null
+++ b/server/src/main/codegen/templates/ModeAccumulator.ftl
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+<@pp.dropOutputFile />
+
+<#list allDataTypes.types as type>
+
+ <#assign className = "${type.dataType?cap_first}ModeAccumulator">
+ <@pp.changeOutputFile name="/org/apache/iotdb/db/mpp/aggregation/${className}.java" />
+
+package org.apache.iotdb.db.mpp.aggregation;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.statistics.Statistics;
+import org.apache.iotdb.tsfile.read.common.block.column.Column;
+import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
+import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.BitMap;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/*
+* This class is generated using freemarker and the ${.template_name} template.
+*/
+@SuppressWarnings("unused")
+public class ${className} implements Accumulator {
+ private final Map<${type.javaBoxName}, Long> countMap = new HashMap<>();
+
+ <#if type.dataType != "boolean">
+ private final int MAP_SIZE_THRESHOLD = IoTDBDescriptor.getInstance().getConfig().getModeMapSizeThreshold();
+
+ </#if>
+ @Override
+ public void addInput(Column[] column, BitMap bitMap, int lastIndex) {
+ for (int i = 0; i <= lastIndex; i++) {
+ if (bitMap != null && !bitMap.isMarked(i)) {
+ continue;
+ }
+ if (!column[1].isNull(i)) {
+ countMap.compute(column[1].get${type.dataType?cap_first}(i), (k, v) -> v == null ? 1 : v + 1);
+ <#if type.dataType != "boolean">
+
+ if (countMap.size() > MAP_SIZE_THRESHOLD) {
+ throw new RuntimeException(
+ String.format(
+ "distinct values has exceeded the threshold %s when calculate Mode",
+ MAP_SIZE_THRESHOLD));
+ }
+ </#if>
+ }
+ }
+ }
+
+ @Override
+ public void addIntermediate(Column[] partialResult) {
+ checkArgument(partialResult.length == 1, "partialResult of Mode should be 1");
+ checkArgument(!partialResult[0].isNull(0), "partialResult of Mode should not be null");
+ deserializeAndMergeCountMap(partialResult[0].getBinary(0));
+ }
+
+ @Override
+ public void addStatistics(Statistics statistics) {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ @Override
+ public void setFinal(Column finalResult) {
+ if (finalResult.isNull(0)) {
+ return;
+ }
+
+ // Step of ModeAccumulator is STATIC,
+ // countMap only need to record one entry which key is finalResult
+ countMap.put(finalResult.get${type.dataType?cap_first}(0), 0L);
+ }
+
+ @Override
+ public void outputIntermediate(ColumnBuilder[] tsBlockBuilder) {
+ tsBlockBuilder[0].writeBinary(serializeCountMap());
+ }
+
+ @Override
+ public void outputFinal(ColumnBuilder tsBlockBuilder) {
+ if (countMap.isEmpty()) {
+ tsBlockBuilder.appendNull();
+ } else {
+ tsBlockBuilder.write${type.dataType?cap_first}(
+ Collections.max(countMap.entrySet(), Map.Entry.comparingByValue()).getKey());
+ }
+ }
+
+ @Override
+ public void reset() {
+ countMap.clear();
+ }
+
+ @Override
+ public boolean hasFinalResult() {
+ return false;
+ }
+
+ @Override
+ public TSDataType[] getIntermediateType() {
+ return new TSDataType[] {TSDataType.TEXT};
+ }
+
+ @Override
+ public TSDataType getFinalType() {
+ return ${type.tsDataType};
+ }
+
+ private Binary serializeCountMap() {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ try {
+ ReadWriteIOUtils.write(countMap.size(), stream);
+ for (Map.Entry<${type.javaBoxName}, Long> entry : countMap.entrySet()) {
+ ReadWriteIOUtils.write(entry.getKey(), stream);
+ ReadWriteIOUtils.write(entry.getValue(), stream);
+ }
+ } catch (IOException e) {
+ // Totally memory operation. This case won't happen.
+ }
+ return new Binary(stream.toByteArray());
+ }
+
+ private void deserializeAndMergeCountMap(Binary partialResult) {
+ InputStream stream = new ByteArrayInputStream(partialResult.getValues());
+ try {
+ int size = ReadWriteIOUtils.readInt(stream);
+ for (int i = 0; i < size; i++) {
+ countMap.compute(ReadWriteIOUtils.read${type.dataType?cap_first}(stream), (k, v) -> {
+ try {
+ return v == null ? ReadWriteIOUtils.readLong(stream) : v + ReadWriteIOUtils.readLong(stream);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ <#if type.dataType != "boolean">
+
+ if (countMap.size() > MAP_SIZE_THRESHOLD) {
+ throw new RuntimeException(
+ String.format(
+ "distinct values has exceeded the threshold %s when calculate Mode",
+ MAP_SIZE_THRESHOLD));
+ }
+ </#if>
+ }
+ } catch (IOException e) {
+ // Totally memory operation. This case won't happen.
+ }
+ }
+}
+
+</#list>
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 70a0b0f3da..47917ace72 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -318,6 +318,8 @@ public class IoTDBConfig {
private int degreeOfParallelism = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
+ private int modeMapSizeThreshold = 10000;
+
/** How many queries can be concurrently executed. When <= 0, use 1000. */
private int maxAllowedConcurrentQueries = 1000;
@@ -3627,4 +3629,12 @@ public class IoTDBConfig {
public void setEnableAuditLogForNativeInsertApi(boolean enableAuditLogForNativeInsertApi) {
this.enableAuditLogForNativeInsertApi = enableAuditLogForNativeInsertApi;
}
+
+ public void setModeMapSizeThreshold(int modeMapSizeThreshold) {
+ this.modeMapSizeThreshold = modeMapSizeThreshold;
+ }
+
+ public int getModeMapSizeThreshold() {
+ return modeMapSizeThreshold;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 29a9caf080..6bd05d6f86 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -569,6 +569,15 @@ public class IoTDBDescriptor {
conf.setDegreeOfParallelism(Runtime.getRuntime().availableProcessors() / 2);
}
+ conf.setModeMapSizeThreshold(
+ Integer.parseInt(
+ properties.getProperty(
+ "mode_map_size_threshold", Integer.toString(conf.getModeMapSizeThreshold()))));
+
+ if (conf.getModeMapSizeThreshold() <= 0) {
+ conf.setModeMapSizeThreshold(10000);
+ }
+
conf.setMaxAllowedConcurrentQueries(
Integer.parseInt(
properties.getProperty(
diff --git a/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java b/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
index 74fbbef9ab..68a3e8f145 100644
--- a/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
@@ -54,12 +54,13 @@ public class SqlConstant {
public static final String AVG = "avg";
public static final String SUM = "sum";
public static final String COUNT_IF = "count_if";
+ public static final String TIME_DURATION = "time_duration";
+ public static final String MODE = "mode";
// names of scalar functions
public static final String DIFF = "diff";
public static final String LAST = "last";
- public static final String TIME_DURATION = "time_duration";
public static final String CAST_FUNCTION = "CAST";
public static final String CAST_TYPE = "type";
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/AccumulatorFactory.java b/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/AccumulatorFactory.java
index 18e18a47b8..a7685df9fd 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/AccumulatorFactory.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/AccumulatorFactory.java
@@ -69,11 +69,32 @@ public class AccumulatorFactory {
Boolean.parseBoolean(inputAttributes.getOrDefault("ignoreNull", "true")));
case TIME_DURATION:
return new TimeDurationAccumulator();
+ case MODE:
+ return crateModeAccumulator(tsDataType);
default:
throw new IllegalArgumentException("Invalid Aggregation function: " + aggregationType);
}
}
+ private static Accumulator crateModeAccumulator(TSDataType tsDataType) {
+ switch (tsDataType) {
+ case BOOLEAN:
+ return new BooleanModeAccumulator();
+ case TEXT:
+ return new BinaryModeAccumulator();
+ case INT32:
+ return new IntModeAccumulator();
+ case INT64:
+ return new LongModeAccumulator();
+ case FLOAT:
+ return new FloatModeAccumulator();
+ case DOUBLE:
+ return new DoubleModeAccumulator();
+ default:
+ throw new IllegalArgumentException("Unknown data type: " + tsDataType);
+ }
+ }
+
public static List<Accumulator> createAccumulators(
List<TAggregationType> aggregationTypes,
TSDataType tsDataType,
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/slidingwindow/SlidingWindowAggregatorFactory.java b/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/slidingwindow/SlidingWindowAggregatorFactory.java
index 3ce57b1c1b..dc10bdee97 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/slidingwindow/SlidingWindowAggregatorFactory.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/aggregation/slidingwindow/SlidingWindowAggregatorFactory.java
@@ -154,6 +154,8 @@ public class SlidingWindowAggregatorFactory {
throw new SemanticException("COUNT_IF with slidingWindow is not supported now");
case TIME_DURATION:
throw new SemanticException("TIME_DURATION with slidingWindow is not supported now");
+ case MODE:
+ throw new SemanticException("MODE with slidingWindow is not supported now");
default:
throw new IllegalArgumentException("Invalid Aggregation Type: " + aggregationType);
}
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 c47fed94a9..463559c02c 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
@@ -2466,6 +2466,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
case SqlConstant.AVG:
case SqlConstant.SUM:
case SqlConstant.TIME_DURATION:
+ case SqlConstant.MODE:
checkFunctionExpressionInputSize(
functionExpression.getExpressionString(),
functionExpression.getExpressions().size(),
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
index ce3c341a4f..519f956f84 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
@@ -133,6 +133,7 @@ public class SchemaUtils {
case SqlConstant.FIRST_VALUE:
case SqlConstant.MIN_VALUE:
case SqlConstant.MAX_VALUE:
+ case SqlConstant.MODE:
default:
return null;
}
@@ -192,6 +193,7 @@ public class SchemaUtils {
case MIN_TIME:
case MAX_TIME:
case COUNT_IF:
+ case MODE:
return Collections.emptyList();
default:
throw new IllegalArgumentException(
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
index 36d1a076af..c9a6e3b132 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
@@ -140,6 +140,7 @@ public class TypeInferenceUtils {
case SqlConstant.FIRST_VALUE:
case SqlConstant.MAX_VALUE:
case SqlConstant.EXTREME:
+ case SqlConstant.MODE:
return dataType;
case SqlConstant.AVG:
case SqlConstant.SUM:
@@ -171,6 +172,7 @@ public class TypeInferenceUtils {
case SqlConstant.FIRST_VALUE:
case SqlConstant.LAST_VALUE:
case SqlConstant.TIME_DURATION:
+ case SqlConstant.MODE:
return;
case SqlConstant.COUNT_IF:
if (dataType != TSDataType.BOOLEAN) {
@@ -207,6 +209,7 @@ public class TypeInferenceUtils {
case SqlConstant.FIRST_VALUE:
case SqlConstant.LAST_VALUE:
case SqlConstant.TIME_DURATION:
+ case SqlConstant.MODE:
return;
case SqlConstant.COUNT_IF:
Expression keepExpression = inputExpressions.get(1);
diff --git a/thrift-commons/src/main/thrift/common.thrift b/thrift-commons/src/main/thrift/common.thrift
index 1f3e335d31..2b5001f3bd 100644
--- a/thrift-commons/src/main/thrift/common.thrift
+++ b/thrift-commons/src/main/thrift/common.thrift
@@ -140,7 +140,8 @@ enum TAggregationType {
MIN_VALUE,
EXTREME,
COUNT_IF,
- TIME_DURATION
+ TIME_DURATION,
+ MODE
}
// for MLNode
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
index f08a1fdb4a..febda38bc5 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
@@ -82,6 +82,13 @@ public class ReadWriteIOUtils {
return flag == 1;
}
+ // used by generated code
+ @SuppressWarnings("unused")
+ public static boolean readBoolean(InputStream inputStream) throws IOException {
+ int flag = inputStream.read();
+ return flag == 1;
+ }
+
/** read a bool from byteBuffer. */
public static boolean readBool(ByteBuffer buffer) {
byte a = buffer.get();