文章目录
- Flink 系列文章
- 7、sql clinet中应用自定义函数
- 1)、实现自定义函数
- 2)、打包并上传jar至flink的lib目录下
- 3)、验证
- 1、创建表
- 2、初始化表数据
- 3、注册函数
- 4、验证自定义函数
- 8、pojo 数据类型应用示例-表值函数
本文展示了自定义函数在Flink sql client的应用以及自定义函数中使用pojo的示例。
本文依赖flink、kafka集群能正常使用。
本文分为2个部分,即自定义函数在Flink sql client中的应用以及自定义函数中使用pojo数据类型。
本文的示例如无特殊说明则是在Flink 1.17版本中运行。
7、sql clinet中应用自定义函数
本示例将上文中自定义的函数打包后在flink sql client中进行应用。
1)、实现自定义函数
本文的所有示例需要依赖的maven见本篇的上一篇:17、Flink 之Table API: Table API 支持的操作(1) 或者引入
<!-- flink依赖引入-->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-common</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
- 示例代码
package org.table_sql;
import org.apache.flink.table.annotation.DataTypeHint;
import org.apache.flink.table.annotation.FunctionHint;
import org.apache.flink.table.functions.TableFunction;
import org.apache.flink.types.Row;
/**
* @author alanchan
*
*/
@FunctionHint(output = @DataTypeHint("ROW<id int, name String, age int, balance int, rowtime string>"))
public class Alan_SplitFunction extends TableFunction<Row> {
public void eval(String str) {
String[] row = str.split(",");
collect(Row.of(Integer.valueOf(row[0]), row[1], Integer.valueOf(row[2]), Integer.valueOf(row[3]), row[4]));
}
}
2)、打包并上传jar至flink的lib目录下
将该文件打包成jar文件,特别说明的是,注意flink运行环境与打包引入的jar文件是否冲突,推荐做法是只打包创建自定义函数所依赖的jar文件,其他jar使用flink部署环境的jar。
本示例打包后的文件名:Alan_SplitFunction.jar
上传jar文件后,并重启flink集群。
3)、验证
1、创建表
Flink SQL> SET sql-client.execution.result-mode = tableau;
[INFO] Session property has been set.
Flink SQL> CREATE TABLE alan_split_table (
> userString STRING
> ) WITH (
> 'connector' = 'kafka',
> 'topic' = 'alan_split',
> 'properties.bootstrap.servers' = '192.168.10.41:9092,192.168.10.42:9092,192.168.10.43:9092',
> 'properties.group.id' = 'testGroup',
> 'scan.startup.mode' = 'earliest-offset',
> 'format' = 'csv'
> );
[INFO] Execute statement succeed.
Flink SQL> select * from alan_split_table;
[INFO] Result retrieval cancelled.
2、初始化表数据
本示例是通过kafka队列插入的数据,前提是kafka环境好用。
[alanchan@server1 bin]$ kafka-console-producer.sh --broker-list server1:9092 --topic alan_split
>"11,alan,18,20,1699341167461"
>"12,alan,19,25,1699341168464"
>"13,alan,20,30,1699341169472"
>"14,alanchan,18,22,1699341170479"
>"15,alanchan,19,25,1699341171482"
Flink SQL> select * from alan_split_table;
+----+--------------------------------+
| op | userString |
+----+--------------------------------+
| +I | 11,alan,18,20,1699341167461 |
| +I | 12,alan,19,25,1699341168464 |
| +I | 13,alan,20,30,1699341169472 |
| +I | 14,alanchan,18,22,169934117... |
| +I | 15,alanchan,19,25,169934117... |
3、注册函数
将自定义的函数注册为flink的临时函数,临时函数只在当前的会话中起作用,如果注册成其他函数,参考如下语法
CREATE [TEMPORARY|TEMPORARY SYSTEM] FUNCTION
[IF NOT EXISTS] [[catalog_name.]db_name.]function_name
AS identifier [LANGUAGE JAVA|SCALA|PYTHON]
[USING JAR '<path_to_filename>.jar' [, JAR '<path_to_filename>.jar']* ]
# TEMPORARY
# 创建一个有 catalog 和数据库命名空间的临时 catalog function ,并覆盖原有的 catalog function 。
# TEMPORARY SYSTEM
# 创建一个没有数据库命名空间的临时系统 catalog function ,并覆盖系统内置的函数。
本示例注册为临时函数,如下
Flink SQL> CREATE TEMPORARY FUNCTION alan_split AS 'org.table_sql.Alan_SplitFunction';
[INFO] Execute statement succeed.
Flink SQL> show functions;
+-----------------------+
| function name |
+-----------------------+
| IFNULL |
| SOURCE_WATERMARK |
| TYPEOF |
| abs |
| acos |
| alan_split |
| and |
| array |
。。。。。。
4、验证自定义函数
Flink SQL> SELECT userString, t_id, t_name,t_age,t_balance,t_rowtime
> FROM alan_split_table
> LEFT JOIN LATERAL TABLE(alan_split(userString)) AS T(t_id, t_name,t_age,t_balance,t_rowtime) ON TRUE;
+----+--------------------------------+-------------+--------------------------------+-------------+-------------+--------------------------------+
| op | userString | t_id | t_name | t_age | t_balance | t_rowtime |
+----+--------------------------------+-------------+--------------------------------+-------------+-------------+--------------------------------+
| +I | 11,alan,18,20,1699341167461 | 11 | alan | 18 | 20 | 1699341167461 |
| +I | 12,alan,19,25,1699341168464 | 12 | alan | 19 | 25 | 1699341168464 |
| +I | 13,alan,20,30,1699341169472 | 13 | alan | 20 | 30 | 1699341169472 |
| +I | 14,alanchan,18,22,169934117... | 14 | alanchan | 18 | 22 | 1699341170479 |
| +I | 15,alanchan,19,25,169934117... | 15 | alanchan | 19 | 25 | 1699341171482 |
至此,完成了自定义函数注册至flink sql client的验证。
8、pojo 数据类型应用示例-表值函数
功能参考 19、Flink 的Table API 和 SQL 中的自定义函数及示例(2) 中的【4、表值函数-自定义函数说明及示例】
本示例仅仅是展示在自定义函数中使用pojo 对象。
本示例仅仅是一种实现方式,也可以覆盖getTypeInference并以编程方式提供所有组件,不再赘述。
本示例仅仅是以表值函数作为示例,其他的自定义函数类似。
import static org.apache.flink.table.api.Expressions.$;
import static org.apache.flink.table.api.Expressions.call;
import java.util.Arrays;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.annotation.DataTypeHint;
import org.apache.flink.table.annotation.FunctionHint;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.table.functions.TableFunction;
import org.apache.flink.types.Row;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author alanchan
*
*/
public class TestUDTableFunctionDemo2 {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class User {
private int id;
private String name;
private int age;
private int balance;
private String rowtime;
}
// @FunctionHint(output = @DataTypeHint("User<id int, name String, age int, balance int, rowtime string>"))
// public static class OverloadedFunction extends TableFunction<Row> {
@FunctionHint(output =@DataTypeHint(bridgedTo = User.class))
public static class OverloadedFunction extends TableFunction<User> {
public void eval(String str) {
String[] user = str.split(",");
// 使用 Row数据类型
// collect(Row.of(Integer.valueOf(user[0]), user[1], Integer.valueOf(user[2]), Integer.valueOf(user[3]), user[4]));
// 使用User pojo数据类型
collect(new User(Integer.valueOf(user[0]), user[1], Integer.valueOf(user[2]), Integer.valueOf(user[3]), user[4]));
}
}
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tenv = StreamTableEnvironment.create(env);
DataStream<String> row = env.fromCollection(
//id name age balance rowtime
Arrays.asList(
"11,alan,18,20,1699341167461",
"12,alan,19,25,1699341168464",
"13,alan,20,30,1699341169472",
"14,alanchan,18,22,1699341170479",
"15,alanchan,19,25,1699341171482"
)
);
Table usersTable2 = tenv.fromDataStream(row, $("userString"));
tenv.createTemporarySystemFunction("OverloadedFunction", OverloadedFunction.class);
Table result5 = usersTable2
.leftOuterJoinLateral(call("OverloadedFunction", $("userString")).as("t_id","t_name","t_age","t_balance","t_rowtime"))
.select($("t_id"),$("t_name"),$("t_age"),$("t_balance"),$("t_rowtime")
// .select($("userString"),$("t_id"),$("t_name"),$("t_age"),$("t_balance"),$("t_rowtime")
) ;
DataStream<Tuple2<Boolean, Row>> result5DS = tenv.toRetractStream(result5, Row.class);
result5DS.print();
// 15> (true,+I[15, alanchan, 19, 25, 1699341171482])
// 12> (true,+I[12, alan, 19, 25, 1699341168464])
// 13> (true,+I[13, alan, 20, 30, 1699341169472])
// 11> (true,+I[11, alan, 18, 20, 1699341167461])
// 14> (true,+I[14, alanchan, 18, 22, 1699341170479])
env.execute();
}
}
以上,展示了自定义函数在Flink sql client的应用以及自定义函数中使用pojo的示例。