This is an automated email from the ASF dual-hosted git repository.
rong 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 9db5ce48d6 [IOTDB-2992] JEXL UDF (#5787)
9db5ce48d6 is described below
commit 9db5ce48d66460aeef004a58016e8b750a2fc001
Author: AACEPT <[email protected]>
AuthorDate: Wed May 4 19:08:50 2022 +0800
[IOTDB-2992] JEXL UDF (#5787)
Co-authored-by: Steve Yurong Su <[email protected]>
---
docs/UserGuide/Query-Data/Select-Expression.md | 55 ++++
docs/zh/UserGuide/Query-Data/Select-Expression.md | 52 ++++
.../db/integration/IoTDBUDTFBuiltinFunctionIT.java | 97 +++++++
pom.xml | 5 +
.../UDFOutputSeriesDataTypeNotValidException.java | 30 +++
.../db/query/udf/builtin/BuiltinFunction.java | 3 +-
.../iotdb/db/query/udf/builtin/UDTFJexl.java | 297 +++++++++++++++++++++
7 files changed, 538 insertions(+), 1 deletion(-)
diff --git a/docs/UserGuide/Query-Data/Select-Expression.md
b/docs/UserGuide/Query-Data/Select-Expression.md
index c8f9807617..7d9170750b 100644
--- a/docs/UserGuide/Query-Data/Select-Expression.md
+++ b/docs/UserGuide/Query-Data/Select-Expression.md
@@ -746,6 +746,61 @@ Total line number = 10
It costs 0.041s
```
+### JEXL Function
+
+Java Expression Language (JEXL) is an expression language engine. We use JEXL
to extend UDFs, which are implemented on the command line with simple lambda
expressions. See the link for [operators supported in jexl lambda
expressions](https://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/package-summary.html#customization).
+
+| Function Name | Allowed Input Series Data Types | Required Attributes
| Output Series Data Type | Series Data Type Description
|
+|----------|--------------------------------|---------------------------------------|------------|--------------------------------------------------|
+| JEXL | INT32 / INT64 / FLOAT / DOUBLE / TEXT / BOOLEAN | `expr` is a
standard lambda expression with only one argument, conforming to the format `x
-> {...}`, for example `x -> {x * 2}` | INT32 / INT64 / FLOAT / DOUBLE / TEXT /
BOOLEAN | Returns the input time series transformed by a lambda expression |
+
+#### Demonstrate
+Example data: `root.ln.wf01.wt01.temperature` has a total of `11` ordered data
from `0.0-10.0`.
+
+```
+IoTDB> select temperature from root.ln.wf01.wt01;
++-----------------------------+-----------------------------+
+| Time|root.ln.wf01.wt01.temperature|
++-----------------------------+-----------------------------+
+|1970-01-01T08:00:00.000+08:00| 0.0|
+|1970-01-01T08:00:00.001+08:00| 1.0|
+|1970-01-01T08:00:00.002+08:00| 2.0|
+|1970-01-01T08:00:00.003+08:00| 3.0|
+|1970-01-01T08:00:00.004+08:00| 4.0|
+|1970-01-01T08:00:00.005+08:00| 5.0|
+|1970-01-01T08:00:00.006+08:00| 6.0|
+|1970-01-01T08:00:00.007+08:00| 7.0|
+|1970-01-01T08:00:00.008+08:00| 8.0|
+|1970-01-01T08:00:00.009+08:00| 9.0|
+|1970-01-01T08:00:00.010+08:00| 10.0|
++-----------------------------+-----------------------------+
+```
+Sql:
+```sql
+select jexl(temperature, 'expr'='x -> {x + x}') as jexl1, jexl(temperature,
'expr'='x -> {x * 3}') as jexl2, jexl(temperature, 'expr'='x -> {x * x}') as
jexl3, jexl(temperature, 'expr'='x -> {multiply(x, 100)}') as jexl4 from
root.ln.wf01.wt01;```
+```
+
+Result:
+```
++-----------------------------+-----+-----+-----+------+
+| Time|jexl1|jexl2|jexl3| jexl4|
++-----------------------------+-----+-----+-----+------+
+|1970-01-01T08:00:00.000+08:00| 0.0| 0.0| 0.0| 0.0|
+|1970-01-01T08:00:00.001+08:00| 2.0| 3.0| 1.0| 100.0|
+|1970-01-01T08:00:00.002+08:00| 4.0| 6.0| 4.0| 200.0|
+|1970-01-01T08:00:00.003+08:00| 6.0| 9.0| 9.0| 300.0|
+|1970-01-01T08:00:00.004+08:00| 8.0| 12.0| 16.0| 400.0|
+|1970-01-01T08:00:00.005+08:00| 10.0| 15.0| 25.0| 500.0|
+|1970-01-01T08:00:00.006+08:00| 12.0| 18.0| 36.0| 600.0|
+|1970-01-01T08:00:00.007+08:00| 14.0| 21.0| 49.0| 700.0|
+|1970-01-01T08:00:00.008+08:00| 16.0| 24.0| 64.0| 800.0|
+|1970-01-01T08:00:00.009+08:00| 18.0| 27.0| 81.0| 900.0|
+|1970-01-01T08:00:00.010+08:00| 20.0| 30.0|100.0|1000.0|
++-----------------------------+-----+-----+-----+------+
+Total line number = 11
+It costs 0.055s
+```
+
### User Defined Timeseries Generating Functions
Please refer to [UDF (User Defined
Function)](../Process-Data/UDF-User-Defined-Function.md).
diff --git a/docs/zh/UserGuide/Query-Data/Select-Expression.md
b/docs/zh/UserGuide/Query-Data/Select-Expression.md
index d96589c761..fe6374d347 100644
--- a/docs/zh/UserGuide/Query-Data/Select-Expression.md
+++ b/docs/zh/UserGuide/Query-Data/Select-Expression.md
@@ -750,6 +750,58 @@ Total line number = 10
It costs 0.041s
```
+### JEXL自定义函数
+Java Expression Language (JEXL)
是一个表达式语言引擎。我们使用JEXL来扩展UDF,在命令行中,通过简易的lambda表达式来实现UDF。lambda表达式中支持的运算符详见链接
[JEXL中lambda表达式支持的运算符](https://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/package-summary.html#customization)
。
+
+
+| 函数名 | 可接收的输入序列类型 | 必要的属性参数
| 输出序列类型 | 功能类型 |
+|----------|--------------------------------|---------------------------------------|------------|--------------------------------------------------|
+| JEXL | INT32 / INT64 / FLOAT / DOUBLE / TEXT / BOOLEAN |
`expr`是一个标准的只有一个参数的lambda表达式,符合`x -> {...}`的格式,例如`x -> {x * 2}`| INT32 / INT64
/ FLOAT / DOUBLE / TEXT / BOOLEAN | 返回将输入的时间序列通过lambda表达式变换的序列 |
+
+#### 演示
+测试数据:`root.ln.wf01.wt01.temperature`从`0.0-10.0`共`11`条数据。
+```
+IoTDB> select temperature from root.ln.wf01.wt01;
++-----------------------------+-----------------------------+
+| Time|root.ln.wf01.wt01.temperature|
++-----------------------------+-----------------------------+
+|1970-01-01T08:00:00.000+08:00| 0.0|
+|1970-01-01T08:00:00.001+08:00| 1.0|
+|1970-01-01T08:00:00.002+08:00| 2.0|
+|1970-01-01T08:00:00.003+08:00| 3.0|
+|1970-01-01T08:00:00.004+08:00| 4.0|
+|1970-01-01T08:00:00.005+08:00| 5.0|
+|1970-01-01T08:00:00.006+08:00| 6.0|
+|1970-01-01T08:00:00.007+08:00| 7.0|
+|1970-01-01T08:00:00.008+08:00| 8.0|
+|1970-01-01T08:00:00.009+08:00| 9.0|
+|1970-01-01T08:00:00.010+08:00| 10.0|
++-----------------------------+-----------------------------+
+```
+sql:
+```sql
+select jexl(temperature, 'expr'='x -> {x + x}') as jexl1, jexl(temperature,
'expr'='x -> {x * 3}') as jexl2, jexl(temperature, 'expr'='x -> {x * x}') as
jexl3, jexl(temperature, 'expr'='x -> {multiply(x, 100)}') as jexl4 from
root.ln.wf01.wt01;```
+```
+结果:
+```
++-----------------------------+-----+-----+-----+------+
+| Time|jexl1|jexl2|jexl3| jexl4|
++-----------------------------+-----+-----+-----+------+
+|1970-01-01T08:00:00.000+08:00| 0.0| 0.0| 0.0| 0.0|
+|1970-01-01T08:00:00.001+08:00| 2.0| 3.0| 1.0| 100.0|
+|1970-01-01T08:00:00.002+08:00| 4.0| 6.0| 4.0| 200.0|
+|1970-01-01T08:00:00.003+08:00| 6.0| 9.0| 9.0| 300.0|
+|1970-01-01T08:00:00.004+08:00| 8.0| 12.0| 16.0| 400.0|
+|1970-01-01T08:00:00.005+08:00| 10.0| 15.0| 25.0| 500.0|
+|1970-01-01T08:00:00.006+08:00| 12.0| 18.0| 36.0| 600.0|
+|1970-01-01T08:00:00.007+08:00| 14.0| 21.0| 49.0| 700.0|
+|1970-01-01T08:00:00.008+08:00| 16.0| 24.0| 64.0| 800.0|
+|1970-01-01T08:00:00.009+08:00| 18.0| 27.0| 81.0| 900.0|
+|1970-01-01T08:00:00.010+08:00| 20.0| 30.0|100.0|1000.0|
++-----------------------------+-----+-----+-----+------+
+Total line number = 11
+It costs 0.055s
+```
### 自定义时间序列生成函数
diff --git
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
index b6349c914f..7b1d66f395 100644
---
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
+++
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
@@ -905,4 +905,101 @@ public class IoTDBUDTFBuiltinFunctionIT {
e.printStackTrace();
}
}
+
+ @Test
+ public void testUDTFJexl() {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute("CREATE TIMESERIES root.sg.d7.s1 with
datatype=INT32,encoding=PLAIN");
+ statement.execute("CREATE TIMESERIES root.sg.d7.s2 with
datatype=FLOAT,encoding=PLAIN");
+ statement.execute("CREATE TIMESERIES root.sg.d7.s3 with
datatype=DOUBLE,encoding=PLAIN");
+ statement.execute("CREATE TIMESERIES root.sg.d7.s4 with
datatype=TEXT,encoding=PLAIN");
+ statement.execute("CREATE TIMESERIES root.sg.d7.s5 with
datatype=BOOLEAN,encoding=PLAIN");
+ statement.execute("CREATE TIMESERIES root.sg.d7.s6 with
datatype=INT64,encoding=PLAIN");
+ } catch (SQLException throwable) {
+ fail(throwable.getMessage());
+ }
+ String[] SQL_FOR_SAMPLE_1 = new String[5];
+ String[] SQL_FOR_SAMPLE_2 = new String[5];
+ String[] SQL_FOR_SAMPLE_3 = new String[5];
+ String[] SQL_FOR_SAMPLE_4 = new String[5];
+ String[] SQL_FOR_SAMPLE_5 = new String[5];
+ String[] SQL_FOR_SAMPLE_6 = new String[5];
+ for (int i = 0; i < 5; i++) {
+ SQL_FOR_SAMPLE_1[i] =
+ String.format("insert into root.sg.d7(time, s1) values (%d, %d)", i,
i + 1);
+ SQL_FOR_SAMPLE_2[i] =
+ String.format("insert into root.sg.d7(time, s2) values (%d, %f)", i,
i + 1.0);
+ SQL_FOR_SAMPLE_3[i] =
+ String.format("insert into root.sg.d7(time, s3) values (%d, %f)", i,
i + 1.0);
+ SQL_FOR_SAMPLE_4[i] =
+ String.format("insert into root.sg.d7(time, s4) values (%d, '%s')",
i, "string");
+ SQL_FOR_SAMPLE_5[i] = String.format("insert into root.sg.d7(time, s5)
values (%d, true)", i);
+ SQL_FOR_SAMPLE_6[i] =
+ String.format("insert into root.sg.d7(time, s6) values (%d, %d)", i,
i + 8);
+ }
+ double[] ANSWER1 = new double[] {2, 4, 6, 8, 10};
+ double[] ANSWER2 = new double[] {2, 4, 6, 8, 10};
+ double[] ANSWER3 = new double[] {4, 7, 10, 13, 16};
+ String[] ANSWER4 = new String[] {"string2", "string2", "string2",
"string2", "string2"};
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ for (int i = 0; i < 5; i++) {
+ statement.execute(SQL_FOR_SAMPLE_1[i]);
+ statement.execute(SQL_FOR_SAMPLE_2[i]);
+ statement.execute(SQL_FOR_SAMPLE_3[i]);
+ statement.execute(SQL_FOR_SAMPLE_4[i]);
+ statement.execute(SQL_FOR_SAMPLE_5[i]);
+ statement.execute(SQL_FOR_SAMPLE_6[i]);
+ }
+ } catch (SQLException throwable) {
+ fail(throwable.getMessage());
+ }
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ String functionName = "JEXL";
+ String expr1 = "x -> {2 * x}";
+ String expr2 = "x -> {x + x}";
+ String expr3 = "x -> {x * 3 + 1}";
+ String expr4 = "x -> {x + 2}";
+ String expr5 = "x -> {x == true}";
+ String expr6 = "x -> {x == x}";
+ ResultSet resultSet =
+ statement.executeQuery(
+ String.format(
+ "select %s(s1, 'expr'='%s'), "
+ + "%s(s2, 'expr'='%s'), "
+ + "%s(s3, 'expr'='%s'), "
+ + "%s(s4, 'expr'='%s'), "
+ + "%s(s5, 'expr'='%s'), "
+ + "%s(s6, 'expr'='%s') "
+ + "from root.sg.d7",
+ functionName,
+ expr1,
+ functionName,
+ expr2,
+ functionName,
+ expr3,
+ functionName,
+ expr4,
+ functionName,
+ expr5,
+ functionName,
+ expr6));
+ int columnCount = resultSet.getMetaData().getColumnCount();
+ assertEquals(1 + 6, columnCount);
+ for (int i = 0; i < 5; i++) {
+ resultSet.next();
+ assertEquals(ANSWER1[i], resultSet.getDouble(2), 0.01);
+ assertEquals(ANSWER2[i], resultSet.getDouble(3), 0.01);
+ assertEquals(ANSWER3[i], resultSet.getDouble(4), 0.01);
+ assertEquals(ANSWER4[i], resultSet.getString(5));
+ assertTrue(resultSet.getBoolean(6));
+ assertTrue(resultSet.getBoolean(7));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/pom.xml b/pom.xml
index 47e150f4ae..289047b54c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -596,6 +596,11 @@
<version>1.15.2</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-jexl3</artifactId>
+ <version>3.2.1</version>
+ </dependency>
</dependencies>
<build>
<pluginManagement>
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFOutputSeriesDataTypeNotValidException.java
b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFOutputSeriesDataTypeNotValidException.java
new file mode 100644
index 0000000000..f94591d97e
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/query/udf/api/exception/UDFOutputSeriesDataTypeNotValidException.java
@@ -0,0 +1,30 @@
+/*
+ * 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 UDFOutputSeriesDataTypeNotValidException extends
UDFParameterNotValidException {
+
+ public UDFOutputSeriesDataTypeNotValidException(int index, String types) {
+ super(
+ String.format(
+ "the data type of the output series (index: %d) is not valid.
expected: %s.",
+ index, types));
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
index 999e0ea923..bf1b7031e8 100644
---
a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++
b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
@@ -65,7 +65,8 @@ public enum BuiltinFunction {
EQUAL_SIZE_BUCKET_AGG_SAMPLE("EQUAL_SIZE_BUCKET_AGG_SAMPLE",
UDTFEqualSizeBucketAggSample.class),
EQUAL_SIZE_BUCKET_M4_SAMPLE("EQUAL_SIZE_BUCKET_M4_SAMPLE",
UDTFEqualSizeBucketM4Sample.class),
EQUAL_SIZE_BUCKET_OUTLIER_SAMPLE(
- "EQUAL_SIZE_BUCKET_OUTLIER_SAMPLE",
UDTFEqualSizeBucketOutlierSample.class);
+ "EQUAL_SIZE_BUCKET_OUTLIER_SAMPLE",
UDTFEqualSizeBucketOutlierSample.class),
+ JEXL("JEXL", UDTFJexl.class);
private final String functionName;
private final Class<?> functionClass;
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFJexl.java
b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFJexl.java
new file mode 100644
index 0000000000..af05530ec0
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFJexl.java
@@ -0,0 +1,297 @@
+/*
+ * 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.builtin;
+
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+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.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.UDFOutputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlScript;
+
+import java.io.IOException;
+
+public class UDTFJexl implements UDTF {
+
+ private TSDataType outputDataType;
+ private JexlScript script;
+ private Evaluator evaluator;
+
+ @Override
+ public void validate(UDFParameterValidator validator) throws UDFException {
+ validator
+ .validateInputSeriesNumber(1)
+ .validateInputSeriesDataType(
+ 0,
+ TSDataType.INT32,
+ TSDataType.INT64,
+ TSDataType.FLOAT,
+ TSDataType.DOUBLE,
+ TSDataType.TEXT,
+ TSDataType.BOOLEAN)
+ .validateRequiredAttribute("expr");
+ }
+
+ @Override
+ public void beforeStart(UDFParameters parameters, UDTFConfigurations
configurations)
+ throws UDFInputSeriesDataTypeNotValidException,
UDFOutputSeriesDataTypeNotValidException,
+ MetadataException {
+ String expr = parameters.getString("expr");
+ JexlEngine jexl = new JexlBuilder().create();
+ script = jexl.createScript(expr);
+
+ TSDataType inputDataType = parameters.getDataType(0);
+ outputDataType = probeOutputDataType(inputDataType);
+
+ switch (inputDataType) {
+ case INT32:
+ evaluator = new EvaluatorIntInput();
+ break;
+ case INT64:
+ evaluator = new EvaluatorLongInput();
+ break;
+ case FLOAT:
+ evaluator = new EvaluatorFloatInput();
+ break;
+ case DOUBLE:
+ evaluator = new EvaluatorDoubleInput();
+ break;
+ case TEXT:
+ evaluator = new EvaluatorStringInput();
+ break;
+ case BOOLEAN:
+ evaluator = new EvaluatorBooleanInput();
+ break;
+ default:
+ throw new UDFInputSeriesDataTypeNotValidException(
+ 0,
+ inputDataType,
+ TSDataType.INT32,
+ TSDataType.INT64,
+ TSDataType.FLOAT,
+ TSDataType.DOUBLE,
+ TSDataType.TEXT,
+ TSDataType.BOOLEAN);
+ }
+
+ configurations
+ .setAccessStrategy(new RowByRowAccessStrategy())
+ .setOutputDataType(outputDataType);
+ }
+
+ private TSDataType probeOutputDataType(TSDataType inputDataType)
+ throws UDFInputSeriesDataTypeNotValidException,
UDFOutputSeriesDataTypeNotValidException {
+ Object o;
+ // 23, 23L, 23f, 23d, "string", true are hard codes for probing
+ switch (inputDataType) {
+ case INT32:
+ o = script.execute(null, 23);
+ break;
+ case INT64:
+ o = script.execute(null, 23L);
+ break;
+ case FLOAT:
+ o = script.execute(null, 23f);
+ break;
+ case DOUBLE:
+ o = script.execute(null, 23d);
+ break;
+ case TEXT:
+ o = script.execute(null, "string");
+ break;
+ case BOOLEAN:
+ o = script.execute(null, true);
+ break;
+ default:
+ // This will not happen.
+ throw new UDFInputSeriesDataTypeNotValidException(
+ 0,
+ inputDataType,
+ TSDataType.INT32,
+ TSDataType.INT64,
+ TSDataType.FLOAT,
+ TSDataType.DOUBLE,
+ TSDataType.TEXT,
+ TSDataType.BOOLEAN);
+ }
+
+ if (o instanceof Number) {
+ return TSDataType.DOUBLE;
+ } else if (o instanceof String) {
+ return TSDataType.TEXT;
+ } else if (o instanceof Boolean) {
+ return TSDataType.BOOLEAN;
+ } else {
+ throw new UDFOutputSeriesDataTypeNotValidException(0, "[Number, String,
Boolean]");
+ }
+ }
+
+ @Override
+ public void transform(Row row, PointCollector collector)
+ throws IOException, UDFOutputSeriesDataTypeNotValidException,
QueryProcessException {
+ switch (outputDataType) {
+ case DOUBLE:
+ evaluator.evaluateDouble(row, collector);
+ break;
+ case TEXT:
+ evaluator.evaluateText(row, collector);
+ break;
+ case BOOLEAN:
+ evaluator.evaluateBoolean(row, collector);
+ break;
+ default:
+ // This will not happen.
+ throw new UDFOutputSeriesDataTypeNotValidException(0, "[Number,
String, Boolean]");
+ }
+ }
+
+ private interface Evaluator {
+ void evaluateDouble(Row row, PointCollector collector) throws IOException;
+
+ void evaluateText(Row row, PointCollector collector) throws IOException,
QueryProcessException;
+
+ void evaluateBoolean(Row row, PointCollector collector) throws IOException;
+ }
+
+ private class EvaluatorIntInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getInt(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getInt(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getInt(0)));
+ }
+ }
+
+ private class EvaluatorLongInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getLong(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getLong(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getLong(0)));
+ }
+ }
+
+ private class EvaluatorFloatInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getFloat(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getFloat(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getFloat(0)));
+ }
+ }
+
+ private class EvaluatorDoubleInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getDouble(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getDouble(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getDouble(0)));
+ }
+ }
+
+ private class EvaluatorStringInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getString(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getString(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getString(0)));
+ }
+ }
+
+ private class EvaluatorBooleanInput implements Evaluator {
+ @Override
+ public void evaluateDouble(Row row, PointCollector collector) throws
IOException {
+ collector.putDouble(
+ row.getTime(), ((Number) script.execute(null,
row.getBoolean(0))).doubleValue());
+ }
+
+ @Override
+ public void evaluateText(Row row, PointCollector collector)
+ throws IOException, QueryProcessException {
+ collector.putString(row.getTime(), (String) script.execute(null,
row.getBoolean(0)));
+ }
+
+ @Override
+ public void evaluateBoolean(Row row, PointCollector collector) throws
IOException {
+ collector.putBoolean(row.getTime(), (Boolean) script.execute(null,
row.getBoolean(0)));
+ }
+ }
+}