xcLeigh头像
关注
90% 开发者不知道的 IoTDB 扩展技巧:UDF 从入门到落地全流程封面图

90% 开发者不知道的 IoTDB 扩展技巧:UDF 从入门到落地全流程

在这里插入图片描述在这里插入图片描述

90% 开发者不知道的 IoTDB 扩展技巧:UDF 从入门到落地全流程

本文聚焦 IoTDB 用户自定义函数(UDF)核心能力,详解 UDTF(时序生成函数)与 UDAF(聚合函数)的区别及适用场景。涵盖 UDF 注册、卸载、权限配置等管理操作,拆解从依赖配置到代码实现的完整开发流程,提供 5 个可直接复用的实战示例(含窗口计算、数据聚合等场景)。同时解答版本更新、内存优化等常见问题,帮助开发者快速掌握个性化时序数据处理能力,适配工业级场景需求。

UDF 从入门到落地全流程

1. UDF 介绍

UDF(User Defined Function,用户自定义函数)是 IoTDB 提供的灵活扩展能力——除了系统自带的时序处理函数,你还能通过自定义函数满足更多个性化计算需求。

IoTDB 支持两类核心 UDF,具体区别如下:

UDF 分类数据访问策略描述
UDTFMAPPABLE_ROW_BY_ROW、ROW_BY_ROW、SLIDING_TIME_WINDOW、SLIDING_SIZE_WINDOW、SESSION_TIME_WINDOW、STATE_WINDOW自定义时间序列生成函数,输入 k 列 m 行数据,输出 1 列 n 行数据(m 和 n 可不同),仅能用于 SELECT 子句
UDAF-自定义聚合函数,输入 k 列 m 行数据,输出 1 列 1 行数据,可用于 SELECT、HAVING 等聚合函数支持的子句

1.1 UDF 使用

UDF 的用法和内置函数差不多,直接在 SQL 里调用就行,还支持多种灵活的查询场景:

  1. 基础 SQL 语法兼容:支持 SLIMIT/SOFFSET、LIMIT/OFFSET,也能做值过滤和时间过滤,和普通查询无缝衔接。

  2. 带 * 的批量查询:如果有 root.sg.d1.s1 和 root.sg.d1.s2 两个时间序列,这些查询方式都能用:

    • SELECT example(*) from root.sg.d1:会返回 example(s1) 和 example(s2) 两个结果;
    • SELECT example(s1, *) from root.sg.d1:会生成 example(s1,s1) 和 example(s1,s2) 两个结果;
    • SELECT example(*, *) from root.sg.d1:会包含 example(s1,s1)、example(s2,s1)、example(s1,s2)、example(s2,s2) 四个结果。
  3. 自定义键值对参数:查询时能给 UDF 传任意个键值对参数,键和值都要用单引号或双引号括起来,而且要放在时间序列后面。比如:

    • 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;
  4. 嵌套查询:可以和其他表达式、函数嵌套使用,比如:

    • 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;

2. UDF 管理

2.1 UDF 注册

想使用自定义 UDF,得先完成注册,步骤很清晰:

  1. 先写好 UDF 类(比如全类名是 org.apache.iotdb.udf.UDTFExample);
  2. 把项目打成 JAR 包(用 Maven 管理的话,后面有示例可以参考);
  3. 按注册方式做准备,再执行注册 SQL:CREATE FUNCTION <UDF名称> AS <UDF全类名> (USING URI URI地址)

注册有两种方式,选一种就行:

  • 方式一:手动放 JAR 包:先把 JAR 包放到集群所有节点的 ext/udf 目录(这个目录能配置),再执行 CREATE FUNCTION example AS 'org.apache.iotdb.udf.UDTFExample'
  • 方式二:集群自动下载:先把 JAR 包传到 URI 服务器,确保 IoTDB 能访问到,再执行 CREATE FUNCTION example AS 'org.apache.iotdb.udf.UDTFExample' USING URI 'http://jar/example.jar',IoTDB 会自动下载并同步到整个集群。

这里有几个小提醒:

  • 注册时不用启停服务器,IoTDB 会通过反射动态加载 UDF;
  • UDF 名称不区分大小写,但不能和内置函数重名,否则会失败;
  • 不同 JAR 包里别放全类名相同但功能不一样的 UDF 类,不然 SQL 里同时用的时候,系统可能随机加载,导致结果出错。

2.2 UDF 卸载

不想用某个 UDF 了,直接执行卸载 SQL 就行:DROP FUNCTION <UDF名称>。比如卸载上面注册的 example:DROP FUNCTION example

2.3 查看所有注册的 UDF

想知道当前集群注册了哪些 UDF,执行 SHOW FUNCTIONS 就能看到完整列表。

2.4 UDF 配置

可以在 iotdb-system.properties 文件里调整 UDF 的相关配置:

  1. UDF 存储目录udf_lib_dir=ext/udf(默认是这个路径,可按需修改);
  2. 内存相关配置(如果用 UDF 时提示内存不足,改这些参数后重启服务):
    • udf_initial_byte_array_length_for_memory_control=48:估算 UDF 查询中文本字段的内存占用,建议设得比所有文本的平均长度略大;
    • udf_memory_budget_in_mb=30.0:单个 UDF 查询最多能用的内存(单位 MB),上限是读取分配内存的 20%;
    • udf_reader_transformer_collector_memory_proportion=1:1:1:UDF 内存分配比例,格式是 a🅱️c(a、b、c 都是整数)。

2.5 UDF 用户权限

使用 UDF 得有 USE_UDF 权限,有了这个权限才能做注册、卸载和查询操作。具体的权限管理可以看专门的权限管理语句文档。

3. UDF 函数库

IoTDB 基于 UDF 能力,提供了一系列现成的时序数据处理函数,覆盖数据质量、数据画像、异常检测、频域分析、数据匹配、数据修复、序列发现、机器学习等场景,完全能满足工业领域的常用需求。

想使用这些函数,参考 UDF 函数库文档,按里面的安装步骤和注册语句操作,就能正确注册并使用了。

4. UDF 开发

4.1 UDF 依赖

如果用 Maven 开发,需要添加下面的依赖,注意版本要和目标 IoTDB 服务器一致:

<dependency>
  <groupId>org.apache.iotdb</groupId>
  <artifactId>udf-api</artifactId>
  <version>1.0.0</version>
  <scope>provided</scope>
</dependency>

4.2 UDTF(User Defined Timeseries Generating Function)

开发 UDTF 要继承 org.apache.iotdb.udf.api.UDTF 类,至少得实现 beforeStart 方法和一个 transform 方法。

接口说明
接口定义描述是否必须
void validate(UDFParameterValidator validator) throws Exception初始化前验证用户输入的参数是否合法
void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception初始化方法,解析参数、配置访问策略和输出类型、创建资源
Object transform(Row row) throws Exception按行处理数据(MappableRowByRow 策略),Row 输入、Object 输出四选一
void transform(Column[] columns, ColumnBuilder builder) throws Exception批量处理数据(MappableRowByRow 策略),Column[] 输入、ColumnBuilder 输出四选一
void transform(Row row, PointCollector collector) throws Exception按行处理数据(RowByRow 策略),Row 输入、PointCollector 输出四选一
void transform(RowWindow rowWindow, PointCollector collector) throws Exception按窗口处理数据(滑动时间/大小窗口等策略),RowWindow 输入、PointCollector 输出四选一
void terminate(PointCollector collector) throws Exception所有 transform 执行完后调用,输出最终结果
void beforeDestroy()结束方法,释放资源
方法调用顺序

一个 UDTF 实例的生命周期里,方法调用顺序是固定的:

  1. validate(可选)
  2. beforeStart
  3. 某个 transform 方法(根据访问策略选择)
  4. terminate(可选)
  5. beforeDestroy

这里要注意:每次执行 UDTF 查询,框架都会新建一个 UDF 实例,查询结束就销毁。所以不同查询的 UDF 实例数据是隔离的,不用担心并发影响,放心维护内部状态就行。

接口详细介绍
  1. validate 方法:可以验证输入序列的数量、类型,检查用户传入的属性,或者做自定义逻辑验证。比如限制必须输入 2 个 INT64 类型的序列。

  2. beforeStart 方法:核心是解析参数和配置运行信息,还能创建外部链接、打开文件等资源。

    • UDFParameters:解析 SQL 里 UDF 的参数(包括序列和键值对属性)。比如 SELECT UDF(s1, s2, 'key1'='iotdb', 'key2'='123.45') FROM root.sg.d;,可以这样获取参数:
      void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) throws Exception {
        String stringValue = parameters.getString("key1"); // 结果是 iotdb
        Float floatValue = parameters.getFloat("key2"); // 结果是 123.45
        Double doubleValue = parameters.getDouble("key3"); // 结果是 null
        int intValue = parameters.getIntOrDefault("key4", 678); // 结果是 678
        // 后续处理...
      }
      
    • UDTFConfigurations:必须用它指定数据访问策略和输出数据类型。比如:
      configurations
        .setAccessStrategy(new RowByRowAccessStrategy()) // 设置访问策略
        .setOutputDataType(Type.INT32); // 设置输出类型为 INT32
      
  3. setAccessStrategy 策略说明:选择的策略决定了框架会调用哪个 transform 方法,也可以根据参数动态选策略,实现多个 transform 方法。

    访问策略描述对应的 transform 方法
    MappableRowByRowStrategy标量函数,一行输入对应一行输出,可用于 SELECT、WHERE 等子句Object transform(Row row) 或 void transform(Column[] columns, ColumnBuilder builder)
    RowByRowAccessStrategy逐行处理,一行输入可输出多行,多序列按时间对齐void transform(Row row, PointCollector collector)
    SlidingTimeWindowAccessStrategy滑动时间窗口处理,窗口内包含多行数据void transform(RowWindow rowWindow, PointCollector collector)
    SlidingSizeWindowAccessStrategy固定行数窗口处理(最后一个窗口可能不足行数)void transform(RowWindow rowWindow, PointCollector collector)
    SessionTimeWindowAccessStrategy会话窗口处理,时间间隔≤sessionGap 归为一组void transform(RowWindow rowWindow, PointCollector collector)
    StateWindowAccessStrategy状态窗口处理,数值变化≤delta 归为一组(仅支持单列输入)void transform(RowWindow rowWindow, PointCollector collector)
  4. setOutputDataType 类型对应:设置的输出类型要和 transform 里输出的数据类型匹配,对应关系如下:

    输出类型支持的输出数据类型
    INT32int
    INT64long
    FLOATfloat
    DOUBLEdouble
    BOOLEANboolean
    TEXTjava.lang.String、org.apache.iotdb.udf.api.type.Binary
UDTF 实现示例
  • 示例 1:MappableRowByRow 策略(Row 输入):两列 INT64 序列相加,一行输入对应一行输出

    import org.apache.iotdb.udf.api.UDTF;
    import org.apache.iotdb.udf.api.access.Row;
    import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameterValidator;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
    import org.apache.iotdb.udf.api.customizer.strategy.MappableRowByRowAccessStrategy;
    import org.apache.iotdb.udf.api.type.Type;
    
    public class Adder implements UDTF {
      private Type dataType;
    
      @Override
      public void validate(UDFParameterValidator validator) throws Exception {
        validator
            .validateInputSeriesNumber(2) // 限制输入2个序列
            .validateInputSeriesDataType(0, Type.INT64) // 第一个序列是 INT64
            .validateInputSeriesDataType(1, Type.INT64); // 第二个序列是 INT64
      }
    
      @Override
      public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
        dataType = parameters.getDataType(0);
        configurations
            .setAccessStrategy(new MappableRowByRowAccessStrategy())
            .setOutputDataType(dataType);
      }
    
      @Override
      public Object transform(Row row) throws Exception {
        return row.getLong(0) + row.getLong(1); // 两列数据相加
      }
    }
    
  • 示例 2:MappableRowByRow 策略(Column 批量输入):批量处理多行数据,性能更好

    import org.apache.iotdb.tsfile.read.common.block.column.Column;
    import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
    import org.apache.iotdb.udf.api.UDTF;
    import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameterValidator;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
    import org.apache.iotdb.udf.api.customizer.strategy.MappableRowByRowAccessStrategy;
    import org.apache.iotdb.udf.api.type.Type;
    
    public class Adder implements UDTF {
      private Type type;
    
      @Override
      public void validate(UDFParameterValidator validator) throws Exception {
        validator
            .validateInputSeriesNumber(2)
            .validateInputSeriesDataType(0, Type.INT64)
            .validateInputSeriesDataType(1, Type.INT64);
      }
    
      @Override
      public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
        type = parameters.getDataType(0);
        configurations.setAccessStrategy(new MappableRowByRowAccessStrategy()).setOutputDataType(type);
      }
    
      @Override
      public void transform(Column[] columns, ColumnBuilder builder) throws Exception {
        long[] inputs1 = columns[0].getLongs();
        long[] inputs2 = columns[1].getLongs();
        int count = columns[0].getPositionCount();
        for (int i = 0; i < count; i++) {
          builder.writeLong(inputs1[i] + inputs2[i]); // 批量计算相加
        }
      }
    }
    
  • 示例 3:RowByRow 策略:两列数据非空时才输出相加结果

    import org.apache.iotdb.udf.api.UDTF;
    import org.apache.iotdb.udf.api.access.Row;
    import org.apache.iotdb.udf.api.collector.PointCollector;
    import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
    import org.apache.iotdb.udf.api.customizer.strategy.RowByRowAccessStrategy;
    import org.apache.iotdb.udf.api.type.Type;
    
    public class Adder implements UDTF {
      @Override
      public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
        configurations
            .setOutputDataType(Type.INT64)
            .setAccessStrategy(new RowByRowAccessStrategy());
      }
    
      @Override
      public void transform(Row row, PointCollector collector) throws Exception {
        if (row.isNull(0) || row.isNull(1)) {
          return; // 有一个为空就不输出
        }
        collector.putLong(row.getTime(), row.getLong(0) + row.getLong(1));
      }
    }
    
  • 示例 4:滑动时间窗口策略:统计每个时间窗口内的数据行数

    import org.apache.iotdb.udf.api.UDTF;
    import org.apache.iotdb.udf.api.access.RowWindow;
    import org.apache.iotdb.udf.api.collector.PointCollector;
    import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
    import org.apache.iotdb.udf.api.customizer.strategy.SlidingTimeWindowAccessStrategy;
    import org.apache.iotdb.udf.api.type.Type;
    
    public class Counter implements UDTF {
      @Override
      public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
        configurations
            .setOutputDataType(Type.INT32)
            .setAccessStrategy(new SlidingTimeWindowAccessStrategy(
                parameters.getLong("time_interval"),
                parameters.getLong("sliding_step"),
                parameters.getLong("display_window_begin"),
                parameters.getLong("display_window_end")));
      }
    
      @Override
      public void transform(RowWindow rowWindow, PointCollector collector) throws Exception {
        if (rowWindow.windowSize() != 0) {
          collector.putInt(rowWindow.windowStartTime(), rowWindow.windowSize()); // 输出窗口起始时间和行数
        }
      }
    }
    
  • 示例 5:terminate 方法:输出序列中的最大值点(需遍历所有数据后计算)

    import org.apache.iotdb.udf.api.UDTF;
    import org.apache.iotdb.udf.api.access.Row;
    import org.apache.iotdb.udf.api.collector.PointCollector;
    import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
    import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
    import org.apache.iotdb.udf.api.customizer.strategy.RowByRowAccessStrategy;
    import org.apache.iotdb.udf.api.type.Type;
    
    public class Max implements UDTF {
      private Long time;
      private int value;
    
      @Override
      public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
        configurations
            .setOutputDataType(Type.INT32)
            .setAccessStrategy(new RowByRowAccessStrategy());
      }
    
      @Override
      public void transform(Row row, PointCollector collector) {
        if (row.isNull(0)) {
          return;
        }
        int candidateValue = row.getInt(0);
        if (time == null || value < candidateValue) {
          time = row.getTime();
          value = candidateValue; // 记录当前最大值和对应时间
        }
      }
    
      @Override
      public void terminate(PointCollector collector) throws Exception {
        if (time != null) {
          collector.putInt(time, value); // 所有数据处理完后,输出最大值
        }
      }
    }
    

4.3 UDAF(User Defined Aggregation Function)

开发 UDAF 需要两个类:State 类(存储聚合状态)和 UDAF 类(实现聚合逻辑)。

State 类

要实现 org.apache.iotdb.udf.api.State 接口,负责状态的初始化、序列化和反序列化。

接口定义描述是否必须
void reset()重置状态为初始值(框架会复用 State 对象)
byte[] serialize()将状态序列化为二进制(用于分布式节点间传递)
void deserialize(byte[] bytes)将二进制反序列化为状态(需和序列化顺序一致)

示例:求平均数的 State 类

import java.nio.ByteBuffer;
import org.apache.iotdb.udf.api.State;

class AvgState implements State {
  double sum; // 总和
  long count; // 数据条数

  @Override
  public void reset() {
    sum = 0;
    count = 0; // 初始化为 0
  }

  @Override
  public byte[] serialize() {
    ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES + Long.BYTES);
    buffer.putDouble(sum);
    buffer.putLong(count);
    return buffer.array(); // 序列化 sum 和 count
  }

  @Override
  public void deserialize(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    sum = buffer.getDouble();
    count = buffer.getLong(); // 反序列化,顺序和序列化一致
  }
}
UDAF 类

要实现 org.apache.iotdb.udf.api.UDAF 接口,实现聚合的核心逻辑。

接口定义描述是否必须
void validate(UDFParameterValidator validator) throws Exception验证输入参数合法性(和 UDTF 一致)
void beforeStart(UDFParameters parameters, UDAFConfigurations configurations) throws Exception初始化方法,解析参数、设置输出类型
State createState()创建并初始化 State 对象
void addInput(State state, Column[] columns, BitMap bitMap)批量更新 State(处理输入数据)
void combineState(State state, State rhs)合并两个 State(分布式场景用)
void outputFinal(State state, ResultValue resultValue)计算最终聚合结果
void beforeDestroy()结束方法,释放资源
方法调用顺序

UDAF 实例的生命周期调用顺序:

  1. createState
  2. validate(可选)
  3. beforeStart
  4. addInput(多次调用,处理数据)
  5. combineState(分布式场景可能多次调用)
  6. outputFinal(每个组调用一次)
  7. beforeDestroy

和 UDTF 一样,每次查询都会新建 UDAF 实例,数据隔离,不用担心并发问题。

UDAF 实现示例

以求平均数(avg)为例,完整实现:

import org.apache.iotdb.udf.api.UDAF;
import org.apache.iotdb.udf.api.State;
import org.apache.iotdb.udf.api.customizer.config.UDAFConfigurations;
import org.apache.iotdb.udf.api.customizer.parameter.UDFParameterValidator;
import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
import org.apache.iotdb.udf.api.type.Type;
import org.apache.iotdb.tsfile.read.common.BitMap;
import org.apache.iotdb.tsfile.read.common.block.column.Column;
import org.apache.iotdb.udf.api.result.ResultValue;

// 状态类
class AvgState implements State {
  double sum;
  long count;

  @Override
  public void reset() {
    sum = 0;
    count = 0;
  }

  @Override
  public byte[] serialize() {
    ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES + Long.BYTES);
    buffer.putDouble(sum);
    buffer.putLong(count);
    return buffer.array();
  }

  @Override
  public void deserialize(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    sum = buffer.getDouble();
    count = buffer.getLong();
  }
}

// UDAF 主类
public class AvgUDAF implements UDAF {

  @Override
  public void validate(UDFParameterValidator validator) throws Exception {
    validator.validateInputSeriesNumber(1); // 只允许输入1个序列
  }

  @Override
  public void beforeStart(UDFParameters parameters, UDAFConfigurations configurations) {
    configurations.setOutputDataType(Type.DOUBLE); // 输出类型为 DOUBLE
  }

  @Override
  public State createState() {
    return new AvgState(); // 创建状态对象
  }

  @Override
  public void addInput(State state, Column[] columns, BitMap bitMap) {
    AvgState avgState = (AvgState) state;
    Column dataColumn = columns[0]; // 第一个列是数据列(最后一列是时间列,这里不用)
    int count = dataColumn.getPositionCount();

    for (int i = 0; i < count; i++) {
      // 跳过被过滤的数据和空值
      if (bitMap != null && !bitMap.isMarked(i)) continue;
      if (!dataColumn.isNull(i)) {
        avgState.sum += dataColumn.getDouble(i);
        avgState.count++;
      }
    }
  }

  @Override
  public void combineState(State state, State rhs) {
    AvgState avgState = (AvgState) state;
    AvgState avgRhs = (AvgState) rhs;
    avgState.sum += avgRhs.sum; // 合并总和
    avgState.count += avgRhs.count; // 合并数据条数
  }

  @Override
  public void outputFinal(State state, ResultValue resultValue) {
    AvgState avgState = (AvgState) state;
    if (avgState.count != 0) {
      resultValue.setDouble(avgState.sum / avgState.count); // 计算平均值
    } else {
      resultValue.setNull(); // 没有数据时返回空
    }
  }
}

4.4 完整 Maven 项目示例

如果用 Maven 管理项目,可以参考官方的 udf-example 示例项目,直接在 GitHub 上就能找到。

5. 为 IoTDB 贡献通用的内置 UDF 函数

如果你的 UDF 很通用,想分享给社区其他用户,可以按下面的步骤贡献:

5.1 前提条件

  1. 通用性:你的 UDF 要能在多个业务场景中被广泛使用,有复用价值;
  2. 可用性:已经完成测试,能在生产环境正常运行。

不确定是否符合通用性?可以发邮件到 [email protected],或者在 GitHub 上创建 ISSUE 讨论。

5.2 贡献清单

要准备三样东西:UDF 源代码、测试用例、使用说明。

5.3 贡献内容

  1. 源代码

    • iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin 下创建 UDF 主类和辅助类;
    • iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinTimeSeriesGeneratingFunction.java 中注册你的 UDF。
  2. 测试用例:至少要写集成测试,在 integration-test/src/test/java/org/apache/iotdb/db/it/udf 下新增测试类。

  3. 使用说明

    • 要包含 UDF 名称、作用、必填参数、适用场景、使用示例;
    • 需准备中英文两个版本,分别添加到 docs/zh/UserGuide/Operation Manual/DML Data Manipulation Language.mddocs/UserGuide/Operation Manual/DML Data Manipulation Language.md 中。
  4. 提交 PR:准备好后,在 GitHub 上提交 Pull Request,具体流程看 IoTDB 的贡献指南。PR 评审通过并合并后,你的 UDF 就正式加入 IoTDB 社区了!

6. 常见问题

问:怎么修改已经注册的 UDF?
答:假设 UDF 名称是 example,全类名是 org.apache.iotdb.udf.UDTFExample,由 example.jar 引入,步骤如下:

  1. 先卸载:DROP FUNCTION example
  2. 删除集群所有节点 ext/udf 目录下的 example.jar;
  3. 修改 UDF 代码后重新打包(JAR 名可不变);
  4. 把新 JAR 包放到所有节点的 ext/udf 目录;
  5. 重新注册:CREATE FUNCTION example AS "org.apache.iotdb.udf.UDTFExample"

🌐 附:IoTDB的各大版本

📄 Apache IoTDB 是一款工业物联网时序数据库管理系统,采用端边云协同的轻量化架构,支持一体化的物联网时序数据收集、存储、管理与分析 ,具有多协议兼容、超高压缩比、高通量读写、工业级稳定、极简运维等特点。

版本IoTDB 二进制包IoTDB 源代码发布说明
2.0.5- All-in-one
- AINode
- SHA512
- ASC
- 源代码
- SHA512
- ASC
release notes
1.3.5- All-in-one
- AINode
- SHA512
- ASC
- 源代码
- SHA512
- ASC
release notes
0.13.4- All-in-one
- Grafana 连接器
- Grafana 插件
- SHA512
- ASC
- 源代码
- SHA512
- ASC
release notes

✨ 去获取:https://archive.apache.org/dist/iotdb/

联系博主

    xcLeigh 博主全栈领域优质创作者,博客专家,目前,活跃在CSDN、微信公众号、小红书、知乎、掘金、快手、思否、微博、51CTO、B站、腾讯云开发者社区、阿里云开发者社区等平台,全网拥有几十万的粉丝,全网统一IP为 xcLeigh。希望通过我的分享,让大家能在喜悦的情况下收获到有用的知识。主要分享编程、开发工具、算法、技术学习心得等内容。很多读者评价他的文章简洁易懂,尤其对于一些复杂的技术话题,他能通过通俗的语言来解释,帮助初学者更好地理解。博客通常也会涉及一些实践经验,项目分享以及解决实际开发中遇到的问题。如果你是开发领域的初学者,或者在学习一些新的编程语言或框架,关注他的文章对你有很大帮助。

    亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。

     愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。

    至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。


     💞 关注博主 🌀 带你实现畅游前后端!

     🏰 大屏可视化 🌀 带你体验酷炫大屏!

     💯 神秘个人简介 🌀 带你体验不一样得介绍!

     🥇 从零到一学习Python 🌀 带你玩转Python技术流!

     🏆 前沿应用深度测评 🌀 前沿AI产品热门应用在线等你来发掘!

     💦 :本文撰写于CSDN平台,作者:xcLeigh所有权归作者所有)https://xcleigh.blog.csdn.net/,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。


在这里插入图片描述

     📣 亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(或者关注下方公众号,看见后第一时间回复,还有海量编程资料等你来领!),博主看见后一定及时给您答复 💌💌💌

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_43151418/article/details/155187851

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--