乐趣区

关于tdengine:TDengine-30-中如何编译创建和使用自定义函数

小 T 导读:尽管 TDengine 曾经提供了十分多的罕用计算函数,然而在具体实际中,企业的开发团队往往会因为本人非凡的业务需要,须要特有的计算函数,这时候,反对自定义函数性能就特地重要了。本文将介绍 TDengine 3.0 反对的 UDF 机制。

在应用 TDengine 这款时序数据库(Time Series Database, TSDB)的时候,咱们常常会用到各种内置函数,通过在数据库中实现很多计算,能够大大简化数据库应用层的开发工作。

TDengine 提供了大量的内置函数,能够分为几个大类:

单行函数:单行函数为查问后果中的每一行返回一个后果行

  • 数学函数:如 ABS、SIN、COS、LOG、POW 等
  • 字符串函数:如 CHAR_LENGTH、CONCAT、LOWER、SUBSTR、UPPER 等
  • 转换函数:如 CAST、TO_JSON、TO_UNIXTIMESTAMP 等
  • 工夫和日期函数:NOW、TIMEDIFF、TIMEZONE、TODAY 等

聚合函数:聚合函数为查问后果集的每一个分组返回单个后果行

  • 如 AVG、COUNT、STDDEV、SUM 等

选择函数
时序数据特有函数
零碎信息函数

尽管 TDengine 曾经提供了这么多罕用的计算函数,然而在具体实际中,企业的开发团队往往会因为本人非凡的业务需要,须要特有的计算函数,这时候,反对自定义函数性能就特地重要了。

本文将具体介绍如何在 TDengine 中定义并应用自定义函数。

利用 UDF(User Defined Function) 性能,TDengine 能够插入用户编写的解决代码并在查问中应用它们,这样就能很不便地解决非凡利用场景中的应用需要。UDF 通常以数据表中的一列数据做为输出,同时反对以嵌套子查问的后果作为输出。

TDengine 反对通过 C/C++ 语言来定义 UDF。TDengine 3.0 优化了相干机制,所以本文形容的个性实用于 3.0 及以上版本。

基本概念

用户能够通过 UDF 实现两类函数:标量函数和聚合函数。标量函数对每行数据输入一个值,如求绝对值 abs,正弦函数 sin,字符串拼接函数 concat 等。聚合函数对多行数据进行输入一个值,如求平均数 avg,最大值 max 等。

实现 UDF 时,须要实现规定的接口函数

  • 标量函数须要实现标量接口函数 scalarfn
  • 聚合函数须要实现聚合接口函数 aggfn_start、aggfn、aggfn_finish
  • 如果须要初始化,实现 udf_init;如果须要清理工作,实现 udf_destroy

接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(_start, _finish, _init, _destroy)的连贯。列表中的 scalarfn、aggfn、udf 须要替换成 udf 函数名。

标量接口函数

int32_t scalarfn(SUdfDataBlock inputDataBlock, SUdfColumn resultColumn)

其中 scalarFn 是函数名的占位符。这个函数对数据块进行标量计算,通过设置 resultColumn 构造体中的变量设置值。

参数的具体含意是:

  • inputDataBlock: 输出的数据块
  • resultColumn: 输入列

聚合接口函数

int32_t aggfn_start(SUdfInterBuf *interBuf)

int32_t aggfn(SUdfDataBlock inputBlock, SUdfInterBuf interBuf, SUdfInterBuf *newInterBuf)

int32_t aggfn_finish(SUdfInterBuf interBuf, SUdfInterBuf result)

其中 aggfn 是函数名的占位符。首先调用 aggfn_start 生成后果 buffer,而后相干的数据会被分为多个行数据块,对每个数据块调用 aggfn 用数据块更新两头后果,最初再调用 aggfn_finish 从两头后果产生最终后果,最终后果只能含 0 或 1 条后果数据。

参数的具体含意是:

  • interBuf:两头后果 buffer。
  • inputBlock:输出的数据块。
  • newInterBuf:新的两头后果 buffer。
  • result:最终后果。

UDF 初始化和销毁

int32_t udf_init()

int32_t udf_destroy()

其中 udf 是函数名的占位符。udf_init 实现初始化工作。udf_destroy 实现清理工作。如果没有初始化工作,无需定义 udf_init 函数。

如果没有清理工作,无需定义 udf_destroy 函数。篇幅所限,相干数据结构的定义能够参考 UDF 文档。

编译 UDF

用户定义函数的 C 语言源代码无奈间接被 TDengine 零碎所应用,而是须要先编译为 动态链接库,之后能力载入 TDengine 零碎。

假如咱们编写了自定义函数,保留在 add_one.c 文件中,在 Linux 上能够这样编译:

gcc -g -O0 -fPIC -shared add_one.c -o add_one.so

创立 UDF

用户能够通过 SQL 指令在零碎中加载客户端所在主机上的 UDF 函数库。一旦创立胜利,则以后 TDengine 集群的所有用户都能够在 SQL 指令中应用这些函数。UDF 存储在零碎的 MNode 节点上,因而即便重启 TDengine 零碎,曾经创立的 UDF 也依然可用。

在创立 UDF 时,须要辨别标量函数和聚合函数。

  • 创立标量函数
CREATE FUNCTION function_name AS library_path OUTPUTTYPE output_type;

例如,如下语句能够把 libbitand.so 创立为零碎中可用的 UDF:

CREATE FUNCTION bit_and AS "/home/taos/udf_example/libbitand.so" OUTPUTTYPE INT;
  • 创立聚合函数:
CREATE AGGREGATE FUNCTION function_name AS library_path OUTPUTTYPE output_type [BUFSIZE buffer_size];

例如,如下语句能够把 libl2norm.so 创立为零碎中可用的 UDF:

CREATE AGGREGATE FUNCTION l2norm AS "/home/taos/udf_example/libl2norm.so" OUTPUTTYPE DOUBLE bufsize 8;

如果不再须要,能够通过 DROP 指令删除所创立的 UDF。

DROP FUNCTION function_name;

应用 UDF

在 SQL 指令中,能够间接以在零碎中创立 UDF 时赋予的函数名来调用用户定义函数。例如:
SELECT X(c1,c2) FROM table/stable;

示意对名为 c1、c2 的数据列调用名为 X 的用户定义函数。SQL 指令中用户定义函数能够配合 WHERE 等查问个性来应用。

欢送下载试用 TDengine 3.0,并尝试编写一个自定义函数。

欢送增加小 T:tdengine,退出物联网技术探讨群,第一工夫理解 TDengine 官网信息,与关注前沿技术的同学们独特探讨新技术、新玩法。


想理解更多 TDengine Database 的具体细节,欢送大家在 GitHub 上查看相干源代码。

退出移动版