You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2021/01/01 07:25:53 UTC

[iotdb] branch master updated: [IOTDB-1098] Add interface `validate` for UDF (#2406)

This is an automated email from the ASF dual-hosted git repository.

qiaojialin 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 e4ddf81  [IOTDB-1098] Add interface `validate` for UDF (#2406)
e4ddf81 is described below

commit e4ddf81ea90daec9d0df33fb6d42b679df8b09d8
Author: Steve Yurong Su <st...@outlook.com>
AuthorDate: Fri Jan 1 15:25:31 2021 +0800

    [IOTDB-1098] Add interface `validate` for UDF (#2406)
---
 .../Operation Manual/UDF User Defined Function.md  |  55 ++++--
 .../Operation Manual/UDF User Defined Function.md  |  55 ++++--
 .../org/apache/iotdb/db/query/udf/api/UDF.java     |  15 ++
 .../org/apache/iotdb/db/query/udf/api/UDTF.java    |  10 +-
 .../parameter/UDFParameterValidator.java           | 209 +++++++++++++++++++++
 .../api/customizer/parameter/UDFParameters.java    |   4 +
 .../UDFAttributeNotProvidedException.java}         |  56 +++---
 .../api/{UDF.java => exception/UDFException.java}  |  60 +++---
 .../UDFInputSeriesDataTypeNotValidException.java   |  40 ++++
 .../UDFInputSeriesIndexNotValidException.java}     |  58 +++---
 .../UDFInputSeriesNumberNotValidException.java}    |  65 ++++---
 .../UDFParameterNotValidException.java}            |  56 +++---
 .../db/query/udf/core/executor/UDTFExecutor.java   |  14 +-
 .../integration/IoTDBUDTFAlignByTimeQueryIT.java   |  44 +++++
 .../iotdb/db/query/udf/example/Accumulator.java    |   8 +
 .../apache/iotdb/db/query/udf/example/Adder.java   |  11 ++
 .../org/apache/iotdb/db/query/udf/example/Max.java |   8 +
 .../iotdb/db/query/udf/example/Multiplier.java     |   8 +
 .../SlidingSizeWindowConstructorTester1.java       |   8 +
 .../SlidingTimeWindowConstructionTester.java       |   8 +
 .../{Multiplier.java => ValidateTester.java}       | 100 +++++-----
 21 files changed, 654 insertions(+), 238 deletions(-)

diff --git a/docs/UserGuide/Operation Manual/UDF User Defined Function.md b/docs/UserGuide/Operation Manual/UDF User Defined Function.md
index 1bb4807..6678847 100644
--- a/docs/UserGuide/Operation Manual/UDF User Defined Function.md	
+++ b/docs/UserGuide/Operation Manual/UDF User Defined Function.md	
@@ -63,11 +63,20 @@ The following table shows all the interfaces available for user implementation.
 
 | Interface definition                                         | Description                                                  | Required to Implement                                 |
 | :----------------------------------------------------------- | :----------------------------------------------------------- | ----------------------------------------------------- |
+| `void validate(UDFParameterValidator validator) throws Exception` | This method is mainly used to validate `UDFParameters` and it is executed before `beforeStart(UDFParameters, UDTFConfigurations)` is called. | Optional                                              |
 | `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception` | The initialization method to call the user-defined initialization behavior before a UDTF processes the input data. Every time a user executes a UDTF query, the framework will construct a new UDF instance, and `beforeStart` will be called. | Required                                              |
-| `void beforeDestroy() `                                      | This method is called by the framework after the last input data is processed, and will only be called once in the life cycle of each UDF instance. | Optional                                              |
 | `void transform(Row row, PointCollector collector) throws Exception` | This method is called by the framework. This data processing method will be called when you choose to use the `RowByRowAccessStrategy` strategy (set in `beforeStart`) to consume raw data. Input data is passed in by `Row`, and the transformation result should be output by `PointCollector`. You need to call the data collection method provided by `collector`  to determine the output data. | Required to implement at lea [...]
 | `void transform(RowWindow rowWindow, PointCollector collector) throws Exception` | This method is called by the framework. This data processing method will be called when you choose to use the `SlidingSizeWindowAccessStrategy` or `SlidingTimeWindowAccessStrategy` strategy (set in `beforeStart`) to consume raw data. Input data is passed in by `RowWindow`, and the transformation result should be output by `PointCollector`. You need to call the data collection method provided by `collecto [...]
 | `void terminate(PointCollector collector) throws Exception`  | This method is called by the framework. This method will be called once after all `transform` calls have been executed. In a single UDF query, this method will and will only be called once. You need to call the data collection method provided by `collector`  to determine the output data. | Optional                                              |
+| `void beforeDestroy() `                                      | This method is called by the framework after the last input data is processed, and will only be called once in the life cycle of each UDF instance. | Optional                                              |
+
+In the life cycle of a UDTF instance, the calling sequence of each method is as follows:
+
+1. `void validate(UDFParameterValidator validator) throws Exception`
+2. `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception`
+3. `void transform(Row row, PointCollector collector) throws Exception` or `void transform(RowWindow rowWindow, PointCollector collector) throws Exception`
+4. `void terminate(PointCollector collector) throws Exception`
+5. `void beforeDestroy() `
 
 Note that every time the framework executes a UDTF query, a new UDF instance will be constructed. When the query ends, the corresponding instance will be destroyed. Therefore, the internal data of the instances in different UDTF queries (even in the same SQL statement) are isolated. You can maintain some state data in the UDTF without considering the influence of concurrency and other factors.
 
@@ -75,7 +84,17 @@ The usage of each interface will be described in detail below.
 
 
 
-### `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception`
+### void validate(UDFParameterValidator validator) throws Exception
+
+The `validate` method is used to validate the parameters entered by the user.
+
+In this method, you can limit the number and types of input time series, check the attributes of user input, or perform any custom verification.
+
+Please refer to the Javadoc for the usage of `UDFParameterValidator`.
+
+
+
+### void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception
 
 This method is mainly used to customize UDTF. In this method, the user can do the following things:
 
@@ -86,7 +105,7 @@ This method is mainly used to customize UDTF. In this method, the user can do th
 
 
 
-#### `UDFParameters`
+#### UDFParameters
 
 `UDFParameters` is used to parse UDF parameters in SQL statements (the part in parentheses after the UDF function name in SQL). The input parameters have two parts. The first part is the paths (measurements) and their data types of the time series that the UDF needs to process, and the second part is the key-value pair attributes for customization. Only the second part can be empty.
 
@@ -119,7 +138,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-####  `UDTFConfigurations`
+####  UDTFConfigurations
 
 You must use `UDTFConfigurations` to specify the strategy used by UDF to access raw data and the type of output sequence.
 
@@ -141,7 +160,7 @@ The `setAccessStrategy` method is used to set the UDF's strategy for accessing t
 
 
 
-##### `setAccessStrategy`
+##### setAccessStrategy
 
 Note that the raw data access strategy you set here determines which `transform` method the framework will call. Please implement the `transform` method corresponding to the raw data access strategy. Of course, you can also dynamically decide which strategy to set based on the attribute parameters parsed by `UDFParameters`. Therefore, two `transform` methods are also allowed to be implemented in one UDF.
 
@@ -188,7 +207,7 @@ Please see the Javadoc for more details.
 
 
 
-##### `setOutputDataType`
+##### setOutputDataType
 
 Note that the type of output sequence you set here determines the type of data that the `PointCollector` can actually receive in the `transform` method. The relationship between the output data type set in `setOutputDataType` and the actual data output type that `PointCollector` can receive is as follows:
 
@@ -217,15 +236,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-### `void beforeDestroy() `
-
-The method for terminating a UDF.
-
-This method is called by the framework. For a UDF instance, `beforeDestroy` will be called after the last record is processed. In the entire life cycle of the instance, `beforeDestroy` will only be called once.
-
-
-
-### `void transform(Row row, PointCollector collector) throws Exception`
+### void transform(Row row, PointCollector collector) throws Exception
 
 You need to implement this method when you specify the strategy of UDF to read the original data as `RowByRowAccessStrategy`.
 
@@ -263,7 +274,7 @@ public class Adder implements UDTF {
 
 
 
-### `void transform(RowWindow rowWindow, PointCollector collector) throws Exception`
+### void transform(RowWindow rowWindow, PointCollector collector) throws Exception
 
 You need to implement this method when you specify the strategy of UDF to read the original data as `SlidingTimeWindowAccessStrategy` or `SlidingSizeWindowAccessStrategy`.
 
@@ -305,7 +316,7 @@ public class Counter implements UDTF {
 
 
 
-### `void terminate(PointCollector collector) throws Exception`
+### void terminate(PointCollector collector) throws Exception
 
 In some scenarios, a UDF needs to traverse all the original data to calculate the final output data points. The `terminate` interface provides support for those scenarios.
 
@@ -357,6 +368,14 @@ public class Max implements UDTF {
 
 
 
+### void beforeDestroy() 
+
+The method for terminating a UDF.
+
+This method is called by the framework. For a UDF instance, `beforeDestroy` will be called after the last record is processed. In the entire life cycle of the instance, `beforeDestroy` will only be called once.
+
+
+
 ## Maven Project Example
 
 If you use Maven, you can build your own UDF project referring to our **udf-example** module. You can find the project [here](https://github.com/apache/iotdb/tree/master/example/udf).
@@ -424,7 +443,7 @@ The usage of UDF is similar to that of built-in aggregation functions.
 
 
 
-### Queries with `*` in `SELECT` Clauses
+### Queries with * in SELECT Clauses
 
 Assume that there are 2 time series (`root.sg.d1.s1` and `root.sg.d1.s2`)  in the system.
 
diff --git a/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md b/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md
index cd8cd60..8e860ab 100644
--- a/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md	
+++ b/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md	
@@ -63,11 +63,20 @@ IoTDB 支持两种类型的 UDF 函数,如下表所示。
 
 | 接口定义                                                     | 描述                                                         | 是否必须           |
 | :----------------------------------------------------------- | :----------------------------------------------------------- | ------------------ |
+| `void validate(UDFParameterValidator validator) throws Exception` | 在初始化方法`beforeStart`调用前执行,用于检测`UDFParameters`中用户输入的参数是否合法。 | 否                 |
 | `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception` | 初始化方法,在UDTF处理输入数据前,调用用户自定义的初始化行为。用户每执行一次UDTF查询,框架就会构造一个新的UDF类实例,该方法在每个UDF类实例被初始化时调用一次。在每一个UDF类实例的生命周期内,该方法只会被调用一次。 | 是                 |
-| `void beforeDestroy() `                                      | UDTF的结束方法。此方法由框架调用,并且只会被调用一次,即在处理完最后一条记录之后被调用。 | 否                 |
 | `void transform(Row row, PointCollector collector) throws Exception` | 这个方法由框架调用。当您在`beforeStart`中选择以`RowByRowAccessStrategy`的策略消费原始数据时,这个数据处理方法就会被调用。输入参数以`Row`的形式传入,输出结果通过`PointCollector`输出。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。 | 与下面的方法二选一 |
 | `void transform(RowWindow rowWindow, PointCollector collector) throws Exception` | 这个方法由框架调用。当您在`beforeStart`中选择以`SlidingSizeWindowAccessStrategy`或者`SlidingTimeWindowAccessStrategy`的策略消费原始数据时,这个数据处理方法就会被调用。输入参数以`RowWindow`的形式传入,输出结果通过`PointCollector`输出。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。 | 与上面的方法二选一 |
 | `void terminate(PointCollector collector) throws Exception`  | 这个方法由框架调用。该方法会在所有的`transform`调用执行完成后,在`beforeDestory`方法执行前被调用。在一个UDF查询过程中,该方法会且只会调用一次。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。 | 否                 |
+| `void beforeDestroy() `                                      | UDTF的结束方法。此方法由框架调用,并且只会被调用一次,即在处理完最后一条记录之后被调用。 | 否                 |
+
+在一个完整的UDTF实例生命周期中,各个方法的调用顺序如下:
+
+1. `void validate(UDFParameterValidator validator) throws Exception`
+2. `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception`
+3. `void transform(Row row, PointCollector collector) throws Exception`或者`void transform(RowWindow rowWindow, PointCollector collector) throws Exception`
+4. `void terminate(PointCollector collector) throws Exception`
+5. `void beforeDestroy() `
 
 注意,框架每执行一次UDTF查询,都会构造一个全新的UDF类实例,查询结束时,对应的UDF类实例即被销毁,因此不同UDTF查询(即使是在同一个SQL语句中)UDF类实例内部的数据都是隔离的。您可以放心地在UDTF中维护一些状态数据,无需考虑并发对UDF类实例内部状态数据的影响。
 
@@ -75,7 +84,17 @@ IoTDB 支持两种类型的 UDF 函数,如下表所示。
 
 
 
-### `void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception`
+### void validate(UDFParameterValidator validator) throws Exception
+
+`validate`方法能够对用户输入的参数进行验证。
+
+您可以在该方法中限制输入序列的数量和类型,检查用户输入的属性或者进行自定义逻辑的验证。
+
+`UDFParameterValidator`的使用方法请见Javadoc。
+
+
+
+### void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception
 
 `beforeStart`方法有两个作用:
 
@@ -85,7 +104,7 @@ IoTDB 支持两种类型的 UDF 函数,如下表所示。
 
 
 
-#### `UDFParameters`
+#### UDFParameters
 
 `UDFParameters`的作用是解析SQL语句中的UDF参数(SQL中UDF函数名称后括号中的部分)。参数包括路径(及其序列类型)参数和字符串key-value对形式输入的属性参数。
 
@@ -117,7 +136,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-####  `UDTFConfigurations`
+####  UDTFConfigurations
 
 您必须使用 `UDTFConfigurations` 指定UDF访问原始数据时采取的策略和输出结果序列的类型。
 
@@ -139,7 +158,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-##### `setAccessStrategy`
+##### setAccessStrategy
 
 注意,您在此处设定的原始数据访问策略决定了框架会调用哪一种`transform`方法 ,请实现与原始数据访问策略对应的`transform`方法。当然,您也可以根据`UDFParameters`解析出来的属性参数,动态决定设定哪一种策略,因此,实现两种`transform`方法也是被允许的。
 
@@ -186,7 +205,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-##### `setOutputDataType`
+##### setOutputDataType
 
 注意,您在此处设定的输出结果序列的类型,决定了`transform`方法中`PointCollector`实际能够接收的数据类型。`setOutputDataType`中设定的输出类型和`PointCollector`实际能够接收的数据输出类型关系如下:
 
@@ -216,15 +235,7 @@ void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) th
 
 
 
-### `void beforeDestroy() `
-
-UDTF的结束方法,您可以在此方法中进行一些资源释放等的操作。
-
-此方法由框架调用。对于一个UDF类实例而言,生命周期中会且只会被调用一次,即在处理完最后一条记录之后被调用。
-
-
-
-### `void transform(Row row, PointCollector collector) throws Exception`
+### void transform(Row row, PointCollector collector) throws Exception
 
 当您在`beforeStart`方法中指定UDF读取原始数据的策略为 `RowByRowAccessStrategy`,您就需要实现该方法,在该方法中增加对原始数据处理的逻辑。
 
@@ -262,7 +273,7 @@ public class Adder implements UDTF {
 
 
 
-### `void transform(RowWindow rowWindow, PointCollector collector) throws Exception`
+### void transform(RowWindow rowWindow, PointCollector collector) throws Exception
 
 当您在`beforeStart`方法中指定UDF读取原始数据的策略为 `SlidingTimeWindowAccessStrategy`或者`SlidingSizeWindowAccessStrategy`时,您就需要实现该方法,在该方法中增加对原始数据处理的逻辑。
 
@@ -304,7 +315,7 @@ public class Counter implements UDTF {
 
 
 
-### `void terminate(PointCollector collector) throws Exception`
+### void terminate(PointCollector collector) throws Exception
 
 在一些场景下,UDF需要遍历完所有的原始数据后才能得到最后的输出结果。`terminate`接口为这类UDF提供了支持。
 
@@ -356,6 +367,14 @@ public class Max implements UDTF {
 
 
 
+### void beforeDestroy()
+
+UDTF的结束方法,您可以在此方法中进行一些资源释放等的操作。
+
+此方法由框架调用。对于一个UDF类实例而言,生命周期中会且只会被调用一次,即在处理完最后一条记录之后被调用。
+
+
+
 ## 完整Maven项目示例
 
 如果您使用[Maven](http://search.maven.org/),可以参考我们编写的示例项目**udf-example**。您可以在[这里](https://github.com/apache/iotdb/tree/master/example/udf)找到它。
@@ -423,7 +442,7 @@ UDF的使用方法与普通内建函数的类似。
 
 
 
-### 带`*`查询
+### 带 * 查询
 
 假定现在有时间序列 `root.sg.d1.s1`和 `root.sg.d1.s2`。
 
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
index 095505e..337976b 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
@@ -19,9 +19,24 @@
 
 package org.apache.iotdb.db.query.udf.api;
 
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+
 public interface UDF {
 
   /**
+   * This method is mainly used to validate {@link UDFParameters} and it is executed before {@link
+   * UDTF#beforeStart(UDFParameters, UDTFConfigurations)} is called.
+   *
+   * @param validator the validator used to validate {@link UDFParameters}
+   * @throws Exception if any parameter is not valid
+   */
+  @SuppressWarnings("squid:S112")
+  default void validate(UDFParameterValidator validator) throws Exception {
+  }
+
+  /**
    * This method is mainly used to release the resources used in the UDF.
    */
   default void beforeDestroy() {
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDTF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDTF.java
index a106d5e..c4b2b11 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDTF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDTF.java
@@ -23,10 +23,11 @@ import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.access.RowWindow;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingTimeWindowAccessStrategy;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingSizeWindowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingTimeWindowAccessStrategy;
 
 /**
  * User-defined Time-series Generating Function (UDTF)
@@ -42,6 +43,13 @@ import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingSizeWindowAc
  * <li>{@link UDTF#transform(RowWindow, PointCollector)} or {@link UDTF#transform(Row,
  * PointCollector)}
  * </ul>
+ * In the life cycle of a UDTF instance, the calling sequence of each method is as follows:
+ * <p>
+ * 1. {@link UDTF#validate(UDFParameterValidator)}
+ * 2. {@link UDTF#beforeStart(UDFParameters, UDTFConfigurations)}
+ * 3. {@link UDTF#transform(RowWindow, PointCollector)} or {@link UDTF#transform(Row, PointCollector)}
+ * 4. {@link UDTF#terminate(PointCollector)}
+ * 5. {@link UDTF#beforeDestroy()}
  * <p>
  * The query engine will instantiate an independent UDTF instance for each udf query column, and
  * different UDTF instances will not affect each other.
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameterValidator.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameterValidator.java
new file mode 100644
index 0000000..9fbd49f
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameterValidator.java
@@ -0,0 +1,209 @@
+/*
+ * 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.query.udf.api.customizer.parameter;
+
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFAttributeNotProvidedException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesIndexNotValidException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesNumberNotValidException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFParameterNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDFParameterValidator {
+
+  private final UDFParameters parameters;
+
+  public UDFParameterValidator(UDFParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  public UDFParameters getParameters() {
+    return parameters;
+  }
+
+  /**
+   * Validates whether the attributes entered by the user contain an attribute whose key is
+   * attributeKey.
+   *
+   * @param attributeKey key of the attribute
+   * @throws UDFAttributeNotProvidedException if the attribute is not provided
+   */
+  public UDFParameterValidator validateRequiredAttribute(String attributeKey)
+      throws UDFAttributeNotProvidedException {
+    if (!parameters.hasAttribute(attributeKey)) {
+      throw new UDFAttributeNotProvidedException(attributeKey);
+    }
+    return this;
+  }
+
+  /**
+   * Validates whether the data type of the input series at the specified column is as expected.
+   *
+   * @param index            index of the specified column
+   * @param expectedDataType the expected data type
+   * @throws UDFInputSeriesIndexNotValidException    if the index of the specified column is out of
+   *                                                 bound
+   * @throws UDFInputSeriesDataTypeNotValidException if the data type of the input series at the
+   *                                                 specified column is not as expected
+   */
+  public UDFParameterValidator validateInputSeriesDataType(int index, TSDataType expectedDataType)
+      throws UDFException {
+    validateInputSeriesIndex(index);
+
+    TSDataType actualDataType;
+    try {
+      actualDataType = parameters.getDataType(index);
+    } catch (MetadataException e) {
+      throw new UDFException("error occurred when getting the data type of the input series");
+    }
+
+    if (!expectedDataType.equals(actualDataType)) {
+      throw new UDFInputSeriesDataTypeNotValidException(index, actualDataType, expectedDataType);
+    }
+    return this;
+  }
+
+  /**
+   * Validates whether the data type of the input series at the specified column is as expected.
+   *
+   * @param index             index of the specified column
+   * @param expectedDataTypes the expected data types
+   * @throws UDFInputSeriesIndexNotValidException    if the index of the specified column is out of
+   *                                                 bound
+   * @throws UDFInputSeriesDataTypeNotValidException if the data type of the input series at the
+   *                                                 specified column is not as expected
+   */
+  public UDFParameterValidator validateInputSeriesDataType(int index,
+      TSDataType... expectedDataTypes) throws UDFException {
+    validateInputSeriesIndex(index);
+
+    TSDataType actualDataType;
+    try {
+      actualDataType = parameters.getDataType(index);
+    } catch (MetadataException e) {
+      throw new UDFException("error occurred when getting the data type of the input series");
+    }
+
+    for (TSDataType expectedDataType : expectedDataTypes) {
+      if (expectedDataType.equals(actualDataType)) {
+        return this;
+      }
+    }
+
+    throw new UDFInputSeriesDataTypeNotValidException(index, actualDataType, expectedDataTypes);
+  }
+
+  /**
+   * Validates whether the number of the input series is as expected.
+   *
+   * @param expectedSeriesNumber the expected number of the input series
+   * @throws UDFInputSeriesNumberNotValidException if the number of the input series is not as
+   *                                               expected
+   */
+  public UDFParameterValidator validateInputSeriesNumber(int expectedSeriesNumber)
+      throws UDFInputSeriesNumberNotValidException {
+    int actualSeriesNumber = parameters.getPaths().size();
+    if (actualSeriesNumber != expectedSeriesNumber) {
+      throw new UDFInputSeriesNumberNotValidException(actualSeriesNumber, expectedSeriesNumber);
+    }
+    return this;
+  }
+
+  /**
+   * Validates whether the number of the input series is as expected.
+   *
+   * @param expectedSeriesNumberLowerBound the number of the input series must be greater than or
+   *                                       equal to the expectedSeriesNumberLowerBound
+   * @param expectedSeriesNumberUpperBound the number of the input series must be less than or equal
+   *                                       to the expectedSeriesNumberUpperBound
+   * @throws UDFInputSeriesNumberNotValidException if the number of the input series is not as
+   *                                               expected
+   */
+  public UDFParameterValidator validateInputSeriesNumber(int expectedSeriesNumberLowerBound,
+      int expectedSeriesNumberUpperBound) throws UDFInputSeriesNumberNotValidException {
+    int actualSeriesNumber = parameters.getPaths().size();
+    if (actualSeriesNumber < expectedSeriesNumberLowerBound
+        || expectedSeriesNumberUpperBound < actualSeriesNumber) {
+      throw new UDFInputSeriesNumberNotValidException(actualSeriesNumber,
+          expectedSeriesNumberLowerBound, expectedSeriesNumberUpperBound);
+    }
+    return this;
+  }
+
+  /**
+   * Validates the input parameters according to the validation rule given by the user.
+   *
+   * @param validationRule the validation rule, which can be a lambda expression
+   * @param messageToThrow the message to throw when the given argument is not valid
+   * @param argument       the given argument
+   * @throws UDFParameterNotValidException if the given argument is not valid
+   */
+  public UDFParameterValidator validate(SingleObjectValidationRule validationRule,
+      String messageToThrow, Object argument) throws UDFParameterNotValidException {
+    if (!validationRule.validate(argument)) {
+      throw new UDFParameterNotValidException(messageToThrow);
+    }
+    return this;
+  }
+
+  public interface SingleObjectValidationRule {
+
+    boolean validate(Object arg);
+  }
+
+  /**
+   * Validates the input parameters according to the validation rule given by the user.
+   *
+   * @param validationRule the validation rule, which can be a lambda expression
+   * @param messageToThrow the message to throw when the given arguments are not valid
+   * @param arguments      the given arguments
+   * @throws UDFParameterNotValidException if the given arguments are not valid
+   */
+  public UDFParameterValidator validate(MultipleObjectsValidationRule validationRule,
+      String messageToThrow, Object... arguments) throws UDFParameterNotValidException {
+    if (!validationRule.validate(arguments)) {
+      throw new UDFParameterNotValidException(messageToThrow);
+    }
+    return this;
+  }
+
+  public interface MultipleObjectsValidationRule {
+
+    boolean validate(Object... args);
+  }
+
+  /**
+   * Validates whether the index of the specified column is out of bound.
+   * </p>
+   * bound: [0, parameters.getPaths().size())
+   *
+   * @param index the index of the specified column
+   * @throws UDFInputSeriesIndexNotValidException if the index of the specified column is out of
+   *                                              bound
+   */
+  private void validateInputSeriesIndex(int index) throws UDFInputSeriesIndexNotValidException {
+    int actualSeriesNumber = parameters.getPaths().size();
+    if (index < 0 || actualSeriesNumber <= index) {
+      throw new UDFInputSeriesIndexNotValidException(index, actualSeriesNumber);
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
index 2320468..da35cbf 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
@@ -84,6 +84,10 @@ public class UDFParameters {
     return SchemaUtils.getSeriesTypeByPath(path);
   }
 
+  public boolean hasAttribute(String attributeKey) {
+    return attributes.containsKey(attributeKey);
+  }
+
   public String getString(String key) {
     return attributes.get(key);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFAttributeNotProvidedException.java
similarity index 72%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFAttributeNotProvidedException.java
index 095505e..0ff2a12 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFAttributeNotProvidedException.java
@@ -1,29 +1,27 @@
-/*
- * 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.query.udf.api;
-
-public interface UDF {
-
-  /**
-   * This method is mainly used to release the resources used in the UDF.
-   */
-  default void beforeDestroy() {
-  }
-}
+/*
+ * 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.query.udf.api.exception;
+
+public class UDFAttributeNotProvidedException extends UDFParameterNotValidException {
+
+  public UDFAttributeNotProvidedException(String requiredAttribute) {
+    super(String.format("attribute \"%s\" is required but was not provided.", requiredAttribute));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFException.java
similarity index 76%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFException.java
index 095505e..b2dcd90 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFException.java
@@ -1,29 +1,31 @@
-/*
- * 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.query.udf.api;
-
-public interface UDF {
-
-  /**
-   * This method is mainly used to release the resources used in the UDF.
-   */
-  default void beforeDestroy() {
-  }
-}
+/*
+ * 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.query.udf.api.exception;
+
+public class UDFException extends Exception {
+
+  public UDFException(String message) {
+    super(message);
+  }
+
+  public UDFException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesDataTypeNotValidException.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesDataTypeNotValidException.java
new file mode 100644
index 0000000..c98e7ec
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesDataTypeNotValidException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.query.udf.api.exception;
+
+import java.util.Arrays;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDFInputSeriesDataTypeNotValidException extends UDFParameterNotValidException {
+
+  public UDFInputSeriesDataTypeNotValidException(int index, TSDataType actual,
+      TSDataType expected) {
+    super(String.format(
+        "the data type of the input series (index: %d) is not valid. expected: %s. actual: %s.",
+        index, expected.toString(), actual.toString()));
+  }
+
+  public UDFInputSeriesDataTypeNotValidException(int index, TSDataType actual,
+      TSDataType... expected) {
+    super(String.format(
+        "the data type of the input series (index: %d) is not valid. expected: %s. actual: %s.",
+        index, Arrays.toString(expected), actual.toString()));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesIndexNotValidException.java
similarity index 67%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesIndexNotValidException.java
index 095505e..7c10040 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesIndexNotValidException.java
@@ -1,29 +1,29 @@
-/*
- * 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.query.udf.api;
-
-public interface UDF {
-
-  /**
-   * This method is mainly used to release the resources used in the UDF.
-   */
-  default void beforeDestroy() {
-  }
-}
+/*
+ * 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.query.udf.api.exception;
+
+public class UDFInputSeriesIndexNotValidException extends UDFParameterNotValidException {
+
+  public UDFInputSeriesIndexNotValidException(int providedIndex, int validIndexUpperBound) {
+    super(String
+        .format("the index (%d) of the input series is not valid. valid index range: [0, %d).",
+            providedIndex, validIndexUpperBound));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesNumberNotValidException.java
similarity index 55%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesNumberNotValidException.java
index 095505e..4b8a707 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFInputSeriesNumberNotValidException.java
@@ -1,29 +1,36 @@
-/*
- * 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.query.udf.api;
-
-public interface UDF {
-
-  /**
-   * This method is mainly used to release the resources used in the UDF.
-   */
-  default void beforeDestroy() {
-  }
-}
+/*
+ * 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.query.udf.api.exception;
+
+public class UDFInputSeriesNumberNotValidException extends UDFParameterNotValidException {
+
+  public UDFInputSeriesNumberNotValidException(int actual, int expected) {
+    super(String
+        .format("the number of the input series is not valid. expected: %d. actual: %d.", expected,
+            actual));
+  }
+
+  public UDFInputSeriesNumberNotValidException(int actual, int expectedLowerBound,
+      int expectedUpperBound) {
+    super(String
+        .format("the number of the input series is not valid. expected: [%d, %d]. actual: %d.",
+            expectedLowerBound, expectedUpperBound, actual));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFParameterNotValidException.java
similarity index 79%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFParameterNotValidException.java
index 095505e..0951c35 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/UDF.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFParameterNotValidException.java
@@ -1,29 +1,27 @@
-/*
- * 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.query.udf.api;
-
-public interface UDF {
-
-  /**
-   * This method is mainly used to release the resources used in the UDF.
-   */
-  default void beforeDestroy() {
-  }
-}
+/*
+ * 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.query.udf.api.exception;
+
+public class UDFParameterNotValidException extends UDFException {
+
+  public UDFParameterNotValidException(String message) {
+    super(message);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java
index e582bb2..60c9b28 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.access.RowWindow;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.core.context.UDFContext;
 import org.apache.iotdb.db.query.udf.datastructure.tv.ElasticSerializableTVList;
@@ -45,13 +46,22 @@ public class UDTFExecutor {
   public void beforeStart(long queryId, float collectorMemoryBudgetInMB)
       throws QueryProcessException {
     udtf = (UDTF) UDFRegistrationService.getInstance().reflect(context);
+
+    UDFParameters parameters = new UDFParameters(context.getPaths(), context.getAttributes());
+
     try {
-      udtf.beforeStart(new UDFParameters(context.getPaths(), context.getAttributes()),
-          configurations);
+      udtf.validate(new UDFParameterValidator(parameters));
+    } catch (Exception e) {
+      onError("validate(UDFParameterValidator)", e);
+    }
+
+    try {
+      udtf.beforeStart(parameters, configurations);
     } catch (Exception e) {
       onError("beforeStart(UDFParameters, UDTFConfigurations)", e);
     }
     configurations.check();
+
     collector = ElasticSerializableTVList
         .newElasticSerializableTVList(configurations.getOutputDataType(), queryId,
             collectorMemoryBudgetInMB, 1);
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFAlignByTimeQueryIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFAlignByTimeQueryIT.java
index e130fd3..6d57904 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFAlignByTimeQueryIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFAlignByTimeQueryIT.java
@@ -127,6 +127,8 @@ public class IoTDBUDTFAlignByTimeQueryIT {
       statement.execute("create function max as \"org.apache.iotdb.db.query.udf.example.Max\"");
       statement.execute(
           "create function terminate as \"org.apache.iotdb.db.query.udf.example.TerminateTester\"");
+      statement.execute(
+          "create function validate as \"org.apache.iotdb.db.query.udf.example.ValidateTester\"");
     } catch (SQLException throwable) {
       fail(throwable.getMessage());
     }
@@ -361,6 +363,48 @@ public class IoTDBUDTFAlignByTimeQueryIT {
   }
 
   @Test
+  public void queryWithoutValueFilter8() {
+    String sqlStr = "select validate(s1, s2, 'k'='') from root.vehicle.d3";
+
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      statement.executeQuery(sqlStr);
+      fail();
+    } catch (SQLException throwable) {
+      assertTrue(throwable.getMessage().contains(
+          "the data type of the input series (index: 0) is not valid. expected: [INT32, INT64]. actual: FLOAT."));
+    }
+  }
+
+  @Test
+  public void queryWithoutValueFilter9() {
+    String sqlStr = "select validate(s1, s2, s1, 'k'=''), * from root.vehicle.d1";
+
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      statement.executeQuery(sqlStr);
+      fail();
+    } catch (SQLException throwable) {
+      assertTrue(throwable.getMessage().contains(
+          "the number of the input series is not valid. expected: 2. actual: 3."));
+    }
+  }
+
+  @Test
+  public void queryWithoutValueFilter10() {
+    String sqlStr = "select validate(s1, s2), * from root.vehicle.d1";
+
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      statement.executeQuery(sqlStr);
+      fail();
+    } catch (SQLException throwable) {
+      assertTrue(
+          throwable.getMessage().contains("attribute \"k\" is required but was not provided."));
+    }
+  }
+
+  @Test
   public void queryWithValueFilter1() {
     String sqlStr =
         "select udf(d2.s2, d2.s1), udf(d2.s1, d2.s2), d2.s1, d2.s2, udf(d2.s1, d2.s2), udf(d2.s2, d2.s1), d2.s1, d2.s2 from root.vehicle"
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
index 036b2cd..b892e15 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.db.query.udf.api.access.RowIterator;
 import org.apache.iotdb.db.query.udf.api.access.RowWindow;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingTimeWindowAccessStrategy;
@@ -37,6 +38,13 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 public class Accumulator implements UDTF {
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("Accumulator#beforeStart");
     configurations.setOutputDataType(TSDataType.INT32);
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
index 83a8d7a..4b46425 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
@@ -33,6 +34,16 @@ public class Adder implements UDTF {
   private double addend;
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(2)
+        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
+            TSDataType.DOUBLE)
+        .validateInputSeriesDataType(1, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
+            TSDataType.DOUBLE);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("Adder#beforeStart");
     addend = parameters.getFloatOrDefault("addend", 0);
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
index e545151..eea5abb 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -34,6 +35,13 @@ public class Max implements UDTF {
   private int value;
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("Max#beforeStart");
     configurations
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
index 8f8db29..75b9e21 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -33,6 +34,13 @@ public class Multiplier implements UDTF {
   private long b;
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT64);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("Multiplier#beforeStart");
     a = parameters.getLongOrDefault("a", 0);
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
index 936bdc2..0ec5e3e 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -32,6 +33,13 @@ public class SlidingSizeWindowConstructorTester1 implements UDTF {
   private int consumptionPoint;
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("SlidingSizeWindowConstructorTester1#beforeStart");
     consumptionPoint = parameters.getInt("consumptionPoint");
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
index 8726215..49ed420 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.db.query.udf.api.access.RowIterator;
 import org.apache.iotdb.db.query.udf.api.access.RowWindow;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.SlidingTimeWindowAccessStrategy;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -34,6 +35,13 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 public class SlidingTimeWindowConstructionTester implements UDTF {
 
   @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32);
+  }
+
+  @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
     System.out.println("SlidingTimeWindowConstructionTester#beforeStart");
     long timeInterval = parameters.getLong(TIME_INTERVAL_KEY);
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/ValidateTester.java
similarity index 64%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
copy to server/src/test/java/org/apache/iotdb/db/query/udf/example/ValidateTester.java
index 8f8db29..b5c0dea 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/ValidateTester.java
@@ -1,54 +1,46 @@
-/*
- * 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.query.udf.example;
-
-import org.apache.iotdb.db.query.udf.api.UDTF;
-import org.apache.iotdb.db.query.udf.api.access.Row;
-import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
-import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-
-public class Multiplier implements UDTF {
-
-  private long a;
-  private long b;
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Multiplier#beforeStart");
-    a = parameters.getLongOrDefault("a", 0);
-    b = parameters.getLongOrDefault("b", 0);
-    configurations
-        .setOutputDataType(TSDataType.INT64)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-  }
-
-  @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    collector.putLong(row.getTime(), row.getLong(0) * a * b);
-  }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Multiplier#beforeDestroy");
-  }
-}
+/*
+ * 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.query.udf.example;
+
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class ValidateTester implements UDTF {
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws Exception {
+    validator
+        .validateRequiredAttribute("k")
+        .validateInputSeriesNumber(2)
+        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64)
+        .validateInputSeriesDataType(1, TSDataType.INT32, TSDataType.INT64);
+  }
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
+    configurations
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.INT32);
+  }
+}