You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2023/08/03 17:17:02 UTC

[iotdb-docs] 01/01: add UDF(Python & remote) docs

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

rong pushed a commit to branch udf-docs
in repository https://gitbox.apache.org/repos/asf/iotdb-docs.git

commit 1dd34a4f0f94975da38a7795b77d587e02514991
Author: Steve Yurong Su <ro...@apache.org>
AuthorDate: Fri Aug 4 01:16:29 2023 +0800

    add UDF(Python & remote) docs
---
 .../User-Defined-Function-C_timecho.md             | 187 +++++++++++++++++++++
 .../User-Defined-Function-Python_timecho.md        | 170 +++++++++++++++++++
 2 files changed, 357 insertions(+)

diff --git a/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-C_timecho.md b/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-C_timecho.md
new file mode 100644
index 0000000..6b3c5bf
--- /dev/null
+++ b/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-C_timecho.md
@@ -0,0 +1,187 @@
+<!--
+
+    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.
+
+-->
+
+# 多语言远程 UDF(C / C++ / Java / ...)
+
+Remote UDF Service 支持通过 RPC 的方式访问用户提供的 UDF Service,以实现用户自定义函数的执行。
+相比于 Native 的 UDF 实现,Remote UDF Service 有如下优势:
+* 跨语言:可以用 Protobuf 支持的各类语言编写 UDF Service。
+* 安全:UDF 执行失败或崩溃,仅会影响 UDF Service 自身,而不会导致 IoTDB 进程崩溃。
+* 灵活:UDF Service 中可以调用任意其他服务或程序库类,以满足更多样的业务需求。
+
+## 依赖
+### protobuf 编译安装
+* 下载地址 https://github.com/protocolbuffers/protobuf/releases
+* 确认安装依赖库:automake,autoconf,libtool是否已经安装,未安装的需要安装
+* 下载 protobuf 安装文件,解压
+* 编译 (用于生成编译服务器下可执行程序): 
+```shell
+./autogen.sh
+./configure --prefix=/XX/bin/protobuflib/
+make
+make install
+```
+如果你使用的是 Java 或 C++等,完成以上步骤就已经可以使用生成的protobuf可执行程序生产protobuf相关文件了。
+
+### protobuf-c 编译安装(C 语言远程 UDF 需此步骤)
+
+* 下载地址: https://codechina.csdn.net/mirrors/protobuf-c/protobuf-c/-/releases/v1.4.0?spm=1033.2243.3001.5876
+* 确认安装依赖库:protobuf, 设置之前protobuf编译出的依赖库资源的环境变量:
+```shell
+PKG_CONFIG_PATH=/XX/bin/protobuflib/
+export PKG_CONFIG_PATH
+```
+* 下载protobuf-c,解压
+* 编译 (用于生成编译服务器下可执行程序):
+```shell
+./autogen.sh
+./configure --prefix=/XX/bin/protobufc/
+make
+make install
+```
+protobufc下生成的文件,即为编译生成的依赖库、protobuf-c可执行程序,使用protobuf-c可执行程序可以根据proto文件生成.c和.h文件
+
+## 编写 UDF 函数
+
+### 拷贝 proto 文件
+
+function_service.proto 和 types.proto 拷贝到 Rpc 服务中
+
+- function_service.proto
+    - PFunctionCallRequest
+        - function_name:函数名称,对应创建函数时指定的symbol
+        - args:方法传递的参数
+        - context:查询上下文信息
+    - PFunctionCallResponse
+        - result:结果
+        - status:状态,0代表正常
+    - PCheckFunctionRequest
+        - function:函数相关信息
+        - match_type:匹配类型
+    - PCheckFunctionResponse
+        - status:状态,0代表正常
+
+### 生成接口
+
+通过 protoc 生成代码,具体参数通过 protoc -h 查看
+
+### 实现接口
+
+共需要实现以下三个方法
+- fnCall:用于编写计算逻辑
+- checkFn:用于创建 UDF 时校验,校验函数名/参数/返回值等是否合法
+- handShake:用于接口探活
+
+## 创建 UDF
+
+```sql
+CREATE FUNCTION <UDF-NAME> AS 
+    SYMBOL = <SYMBOL>,
+    OBJECT_FILE = <OBJECT_FILE>,
+    LANGUAGE PROTOBUF
+```
+
+说明:
+1. `symbol`表示的是 rpc 调用传递的方法名,这个参数是必须设定的。
+2. `object_file`表示的 rpc 服务地址,目前支持单个地址和 brpc 兼容格式的集群地址。
+
+示例:
+```sql
+CREATE FUNCTION rpc_udf1 AS 
+    SYMBOL = "fnCall",
+    OBJECT_FILE = "127.0.0.1:9090",
+    LANGUAGE PROTOBUF;
+```
+
+## UDF 卸载
+
+卸载 UDF 的 SQL 语法如下:
+
+```sql
+DROP FUNCTION <UDF-NAME>
+```
+
+例如:
+
+```sql
+DROP FUNCTION rpc_udf1
+```
+
+## UDF 查询
+
+UDF 的使用方法与普通内建函数的类似。
+
+### 支持的基础 SQL 语法
+
+* `SLIMIT` / `SOFFSET`
+* `LIMIT` / `OFFSET`
+* 支持值过滤
+* 支持时间过滤
+
+### 带 * 查询
+
+假定现在有时间序列 `root.sg.d1.s1`和 `root.sg.d1.s2`。
+
+* **执行`SELECT example(*) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1)`和`example(root.sg.d1.s2)`的结果。
+
+* **执行`SELECT example(s1, *) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1, root.sg.d1.s1)`和`example(root.sg.d1.s1, root.sg.d1.s2)`的结果。
+
+* **执行`SELECT example(*, *) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1, root.sg.d1.s1)`,`example(root.sg.d1.s2, root.sg.d1.s1)`,`example(root.sg.d1.s1, root.sg.d1.s2)` 和 `example(root.sg.d1.s2, root.sg.d1.s2)`的结果。
+
+### 带自定义输入参数的查询
+
+您可以在进行 UDF 查询的时候,向 UDF 传入任意数量的键值对参数。键值对中的键和值都需要被单引号或者双引号引起来。注意,键值对参数只能在所有时间序列后传入。下面是一组例子:
+
+```sql
+SELECT example(s1, 'key1'='value1', 'key2'='value2'), example(*, 'key3'='value3') FROM root.sg.d1;
+SELECT example(s1, s2, 'key1'='value1', 'key2'='value2') FROM root.sg.d1;
+```
+
+### 与其他查询的嵌套查询
+
+```sql
+SELECT s1, s2, example(s1, s2) FROM root.sg.d1;
+SELECT *, example(*) FROM root.sg.d1 DISABLE ALIGN;
+SELECT s1 * example(* / s1 + s2) FROM root.sg.d1;
+SELECT s1, s2, s1 + example(s1, s2), s1 - example(s1 + example(s1, s2) / s2) FROM root.sg.d1;
+```
+
+## 查看所有注册的 UDF
+
+```sql
+SHOW FUNCTIONS
+```
+
+## 用户权限管理
+
+用户在使用 UDF 时会涉及到 3 种权限:
+
+* `CREATE_FUNCTION`:具备该权限的用户才被允许执行 UDF 注册操作
+* `DROP_FUNCTION`:具备该权限的用户才被允许执行 UDF 卸载操作
+* `READ_TIMESERIES`:具备该权限的用户才被允许使用 UDF 进行查询
+
+更多用户权限相关的内容,请参考 [权限管理语句](../Administration-Management/Administration.md)。
diff --git a/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-Python_timecho.md b/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-Python_timecho.md
new file mode 100644
index 0000000..542c34d
--- /dev/null
+++ b/src/zh/UserGuide/V1.2.x/Operators-Functions/User-Defined-Function-Python_timecho.md
@@ -0,0 +1,170 @@
+<!--
+
+    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.
+
+-->
+
+# 用户自定义函数(Python)
+
+UDF(User Defined Function)即用户自定义函数。IoTDB 提供多种 Java 内建函数来满足您的计算需求,同时您还可以通过创建自定义 Python 函数来满足更多的计算需求。
+
+根据此文档,您将会很快学会 Python UDF 的编写、注册、使用等操作。
+
+## UDF 类型
+
+IoTDB 支持两种类型的 UDF 函数,如下表所示。
+
+
+| UDF 分类                                            | 描述                                                                                                                   |
+| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
+| UDTF(User Defined Timeseries Generating Function) | 自定义时间序列生成函数。该类函数允许接收多条时间序列,最终会输出一条时间序列,生成的时间序列可以有任意多数量的数据点。 |
+| UDAF(User Defined Aggregation Function)           | 正在开发,敬请期待。                                                                                                   |
+
+## UDF 依赖
+
+* 准备好 Python 运行环境,要求 Python 版本 >= 3.7
+* 开发 UDF 需要依赖 apache-iotdb 包:`pip3 install apache-iotdb`
+
+## UDTF(User Defined Timeseries Generating Function)
+
+编写一个 UDTF 需要继承`UDTF`类,并至少实现`before_start`方法和一种`transform_row / transform_window`方法。
+
+下表是所有可供用户实现的接口说明。
+
+
+| 接口定义                                                                                   | 描述                                                                                                                                                                                                                                                                                                                     | 是否必须           |
+| :----------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
+| `def validate(self, validator: UDFParameterValidator):`                                    | 在初始化方法`before_start`调用前执行,用于检测`UDFParameters`中用户输入的参数是否合法。                                                                                                                                                                                                                                  | 否                 |
+| `def before_start( self, parameters: UDFParameters, configurations: UDTFConfigurations ):` | 初始化方法,在 UDTF 处理输入数据前,调用用户自定义的初始化行为。用户每执行一次 UDTF 查询,框架就会构造一个新的 UDF 类实例,该方法在每个 UDF 类实例被初始化时调用一次。在每一个 UDF 类实例的生命周期内,该方法只会被调用一次。                                                                                            | 是                 |
+| `def transform_row(self, row: Row, collector: PointCollector):`                            | 这个方法由框架调用。当您在`before_start`中选择以`RowByRowAccessStrategy`的策略消费原始数据时,这个数据处理方法就会被调用。输入参数以`Row`的形式传入,输出结果通过`PointCollector`输出。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。                                                     | 与下面的方法二选一 |
+| `def transform_window(self, row_window: RowWindow, collector: PointCollector):`            | 这个方法由框架调用。当您在`before_start`中选择以`SlidingSizeWindowAccessStrategy`或者`SlidingTimeWindowAccessStrategy`的策略消费原始数据时,这个数据处理方法就会被调用。输入参数以`RowWindow`的形式传入,输出结果通过`PointCollector`输出。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。 | 与上面的方法二选一 |
+| `def terminate(self, collector: PointCollector):`                                          | 这个方法由框架调用。该方法会在所有的`transform`调用执行完成后,在`before_destory`方法执行前被调用。在一个 UDF 查询过程中,该方法会且只会调用一次。您需要在该方法内自行调用`collector`提供的数据收集方法,以决定最终的输出数据。                                                                                          | 否                 |
+| `def before_destroy(self): `                                                               | UDTF 的结束方法。此方法由框架调用,并且只会被调用一次,即在处理完最后一条记录之后被调用。                                                                                                                                                                                                                                | 否                 |
+
+Python 版 UDF 接口语意和使用方式与 Java 版本 UDF 保持一致,具体可参考[Java UDF 使用方式](User-Defined-Function.md)。
+
+## 数据类型映射
+| IoTDB 中的数据类型 | Python UDF 中的数据类型 |
+|--------------|-------------------|
+| BOOLEAN      | Boolean           |
+| INT32        | Integer           |
+| INT64        | BigInteger        |
+| FLOAT        | Float             |
+| DOUBLE       | Float             |
+| TEXT         | Text              |
+| LONG         | BigInteger        |
+
+## UDF 注册
+
+注册一个 UDF 可以按如下流程进行:
+
+1. 实现一个完整的 UDF 类,假定这个类的存储在 DataNode 服务器的 `/home/iotdb/udf/udf.py` 路径下
+2. 使用以下 SQL 语句注册 UDF
+
+```sql
+CREATE FUNCTION <UDF-NAME> AS <UDF-FILE-PATH> LANGUAGE PYTHON
+```
+
+例如:
+    
+```sql  
+CREATE FUNCTION udf1 AS '/home/iotdb/udf/udf.py' LANGUAGE PYTHON
+```
+
+### 注意
+
+由于 IoTDB 的 Python UDF 是借用 Java 反射技术动态装载的,因此您在装载过程中无需启停服务器。
+
+UDF 函数名称是大小写不敏感的。
+
+请不要给 UDF 函数注册一个内置函数的名字。使用内置函数的名字给 UDF 注册会失败。
+
+## UDF 卸载
+
+卸载 UDF 的 SQL 语法如下:
+
+```sql
+DROP FUNCTION <UDF-NAME>
+```
+
+例如:
+
+```sql
+DROP FUNCTION udf1
+```
+
+## UDF 查询
+
+UDF 的使用方法与普通内建函数的类似。
+
+### 支持的基础 SQL 语法
+
+* `SLIMIT` / `SOFFSET`
+* `LIMIT` / `OFFSET`
+* 支持值过滤
+* 支持时间过滤
+
+### 带 * 查询
+
+假定现在有时间序列 `root.sg.d1.s1`和 `root.sg.d1.s2`。
+
+* **执行`SELECT example(*) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1)`和`example(root.sg.d1.s2)`的结果。
+
+* **执行`SELECT example(s1, *) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1, root.sg.d1.s1)`和`example(root.sg.d1.s1, root.sg.d1.s2)`的结果。
+
+* **执行`SELECT example(*, *) from root.sg.d1`**
+
+那么结果集中将包括`example(root.sg.d1.s1, root.sg.d1.s1)`,`example(root.sg.d1.s2, root.sg.d1.s1)`,`example(root.sg.d1.s1, root.sg.d1.s2)` 和 `example(root.sg.d1.s2, root.sg.d1.s2)`的结果。
+
+### 带自定义输入参数的查询
+
+您可以在进行 UDF 查询的时候,向 UDF 传入任意数量的键值对参数。键值对中的键和值都需要被单引号或者双引号引起来。注意,键值对参数只能在所有时间序列后传入。下面是一组例子:
+
+```sql
+SELECT example(s1, 'key1'='value1', 'key2'='value2'), example(*, 'key3'='value3') FROM root.sg.d1;
+SELECT example(s1, s2, 'key1'='value1', 'key2'='value2') FROM root.sg.d1;
+```
+
+### 与其他查询的嵌套查询
+
+```sql
+SELECT s1, s2, example(s1, s2) FROM root.sg.d1;
+SELECT *, example(*) FROM root.sg.d1 DISABLE ALIGN;
+SELECT s1 * example(* / s1 + s2) FROM root.sg.d1;
+SELECT s1, s2, s1 + example(s1, s2), s1 - example(s1 + example(s1, s2) / s2) FROM root.sg.d1;
+```
+
+## 查看所有注册的 UDF
+
+```sql
+SHOW FUNCTIONS
+```
+
+## 用户权限管理
+
+用户在使用 UDF 时会涉及到 3 种权限:
+
+* `CREATE_FUNCTION`:具备该权限的用户才被允许执行 UDF 注册操作
+* `DROP_FUNCTION`:具备该权限的用户才被允许执行 UDF 卸载操作
+* `READ_TIMESERIES`:具备该权限的用户才被允许使用 UDF 进行查询
+
+更多用户权限相关的内容,请参考 [权限管理语句](../Administration-Management/Administration.md)。