文章目录
系统函数尽管庞大,也不可能涵盖所有的功能;如果有系统函数不支持的需求,我们就需要用自定义函数(User Defined Functions,UDF)来实现了。事实上,系统内置函数仍然在不断扩充,如果我们认为自己实现的自定义函数足够通用、应用非常广泛,也可以在项目跟踪工具 JIRA 上向 Flink 开发团队提出“议题”(issue),请求将新的函数添加到系统函数中。
Flink 的 Table API 和 SQL 提供了多种自定义函数的接口,以抽象类的形式定义。当前 UDF主要有以下几类:
- 标量函数(Scalar Functions):将输入的标量值转换成一个新的标量值;
- 表函数(Table Functions):将标量值转换成一个或多个新的行数据,也就是扩展成一个表;
- 聚合函数(Aggregate Functions):将多行数据里的标量值转换成一个新的标量值;
- 表聚合函数(Table Aggregate Functions):将多行数据里的标量值转换成一个或多个新的行数据。
1,整体调用流程
要想在代码中使用自定义的函数,我们需要首先自定义对应 UDF 抽象类的实现,并在表环境中注册这个函数,然后就可以在 Table API 和 SQL 中调用了。
(1)注册函数
注册函数时需要调用表环境的 createTemporarySystemFunction()方法,传入注册的函数名以及 UDF 类的 Class 对象:
// 注册函数
tableEnv.createTemporarySystemFunction("MyFunction", MyFunction.class);
我们自定义的 UDF 类叫作 MyFunction,它应该是上面四种 UDF 抽象类中某一个的具体实现;在环境中将它注册为名叫 MyFunction 的函数。
这里 createTemporarySystemFunction()方法的意思是创建了一个“临时系统函数”,所以MyFunction 函 数 名 是 全 局 的 , 可 以 当 作 系 统 函 数 来 使 用 ; 我 们 也 可 以 用createTemporaryFunction()方法,注册的函数就依赖于当前的数据库(database)和目录(catalog)了,所以这就不是系统函数,而是“目录函数”(catalog function),它的完整名称应该包括所属的 database 和 catalog。
一般情况下,我们直接用 createTemporarySystemFunction()方法将 UDF 注册为系统函数就可以了。
(2)使用 Table API 调用函数
在 Table API 中,需要使用 call()方法来调用自定义函数:
tableEnv.from("MyTable").select(call("MyFunction", $("myField")));
这里 call()方法有两个参数,一个是注册好的函数名 MyFunction,另一个则是函数调用时本身的参数。这里我们定义 MyFunction 在调用时,需要传入的参数是 myField 字段。此外,在 Table API 中也可以不注册函数,直接用“内联”(inline)的方式调用 UDF:
tableEnv.from("MyTable").select(call(SubstringFunction.class, $("myField")));
区别只是在于 call()方法第一个参数不再是注册好的函数名,而直接就是函数类的 Class对象了。
(3)在 SQL 中调用函数
当我们将函数注册为系统函数之后,在 SQL 中的调用就与内置系统函数完全一样了:
tableEnv.sqlQuery("SELECT MyFunction(myField) FROM MyTable");
可见,SQL 的调用方式更加方便,我们后续依然会以 SQL 为例介绍 UDF 的用法