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();