该文章会随着学习深度会不断更新,希望大家一起交流和学习
参考文章:
Flink官网
阿里云Flink官网
更新时间戳:
23-11-15 增加UDF多输入实例(聚合性UDF)
23-11-16 增加UDSF使用(目的来一条数据处理一条)
实现流程
聚合类型UDF实现
官网讲的是max函数的实现流程哈,具体如下图
我平常学的话,会先把处理逻辑理清楚,再去看具体实现的代码。
回到问题本身,首先表中的数据怎么读,读到哪里,怎么存,然后就是怎么分析了,最后输出到哪里?
读我是不知道怎么读的,后期看看那个Flink SQL解析怎么搞。
存在什么数据结构里面,自己建个类,需要什么值就写什么值。
createAccumulator() --> return 自建类
accumulator() --> 存储计算逻辑
getvalue() --> 获取最终的值
大概逻辑就是说,我先创建一个自定义的数据结构,里面的存储变量是临时存储着计算的结果(有点像状态哈,内存状态,OOM触发,啥也没了),每来一条流数据,accumulator()处理一下,更新一下数据结构里面的的值(准确的来说,它是对象,不然怎么实现持续更新嘞),水位线触发或者来一条算一条,调用getvalue()获取结果给你看。
代码细节
实现聚合函数,这里注意,不同函数是继承不一样的类的,此处是继承AggregateFunction
我只实现了基本的参数,剩下的可选的,我是直接没选的
// 官方提供的代码
import org.apache.flink.table.functions.AggregateFunction;
import java.util.Iterator;
public class ASI_UDAF {
public static class AccSum {
public long sum;
}
public static class MySum extends AggregateFunction<Long, AccSum> {
@Override
public Long getValue(AccSum acSum) {
return acSum.sum;
}
@Override
public AccSum createAccumulator() {
AccSum acCount = new AccSum();
acCount.sum = 0;
return acCount;
}
public void accumulate(AccSum acc, long num) {
acc.sum += num;
}
/**
* Support retract a msg generated by upstream operator.
* 支持回撤操作
*/
public void retract(AccSum acc, long num) {
acc.sum -= num;
}
/**
* Support local-global two stage aggregate optimization.
* 支持两阶段聚合
*/
public void merge(AccSum acc, Iterable<AccSum> it) {
Iterator<AccSum> iter = it.iterator();
while (iter.hasNext()) {
AccSum accSum = iter.next();
if (null != accSum) {
acc.sum += accSum.sum;
}
}
}
}
}
// 我瞎鼓捣实现的
import org.apache.flink.table.functions.AggregateFunction;
// 继承AggregateFunction类,
public class AggFTest01{
public static class SKTest{
public long sum1 = 0;
public long sum2 = 0;
public int count = 0;
}
public static class Test01 extends AggregateFunction<Long,SKTest>{
/**
* 获取最终结果
*/
@Override
public Long getValue(SKTest skTest) {
return skTest.sum2;
}
/**
* 创建结果集对象
*/
@Override
public SKTest createAccumulator() {
return new SKTest();
}
/**
* 创建处理逻辑
*/
public void accumulate(SKTest skTest, String value) {
String[] arr1 = value.split("_");
for (int i = 0; i < 2; i++) {
if (i != 0){
skTest.sum2 = arr1[i].length();
}
else
skTest.sum1 = arr1[i].length();
}
}
}
}
阿里云使用的话,明天上班再搞,摸鱼学习中,不能晚上加班。
UDSF类型实现
此类型主要是是一对一数据处理(聚合类型的udf引入其他字段的话,会出现非group by字段,仔细看了一下对应UDF解释实现此类型Demo)
CREATE TEMPORARY TABLE datagen_source1 (
k1 STRING NOT NULL
) WITH (
'connector' = 'datagen',
'fields.k1.length' = '10'
);
CREATE TEMPORARY TABLE datagen_source2 (
v1 STRING NOT NULL
) WITH (
'connector' = 'datagen',
'fields.v1.length' = '10'
);
CREATE TEMPORARY TABLE mid_table(
con_str BIGINT
) WITH (
'connector' = 'print'
);
CREATE TEMPORARY FUNCTION `mysum1` AS 'CreateKafkaData.UDSFDemo';
SELECT
`mysum1`(datagen_source1.k1,datagen_source2.v1)
,datagen_source1.k1
,datagen_source2.v1
FROM
datagen_source1
inner join
datagen_source2
on 1=1;
阿里云 VVP使用
(可以理解为VVP是Flink的运载Web UI,同时提供了大量的辅助组件,阿里云VVP你值得拥有)
maven建Java项目就不细讲了,需要的话,自行百度哈
首先,你得有阿里云flink实时计算平台哈,哈哈哈哈,问题不大,现在好像新用户都可以试用,有需要的可以去瞅瞅嘞。
附件形式传输
自定义UDF有两种,此处是临时使用,也可设置全局使用
CREATE TEMPORARY TABLE ASI_UDAF_Source (
a BIGINT NOT NULL
) WITH (
'connector' = 'datagen'
);
CREATE TEMPORARY TABLE ASI_UDAF_Sink (
`sum` BIGINT
) WITH (
'connector' = 'print'
);
/**
* 路径要写到继承AggregateFunction类为止
* 内部类调用 类名$内部类名
* 通常都是 package.类名$内部类名
*/
CREATE TEMPORARY FUNCTION `mysum` AS 'ASI_UDAF$MySum';
CREATE TEMPORARY FUNCTION `mysum1` AS 'AggFTest01$Test01';
SELECT `mysum`(a)
FROM ASI_UDAF_Source;
点调试哈,这项目要上线,top会把我开除的
官方给的示例过了,我自己写的也要安排一下
预期实现逻辑:拼接字符串,但约束字符串长度,输出最后字符串截取的大小。
代码实现的初步逻辑是,a_b ,看看a和b的字段长度
后来约束了二者的长度都是固定10,然后也没判断长度,分割后,固定大小都是10
flink后台直接把我任务停了,估计是不允许那种条件常为定值的作业。
CREATE TEMPORARY TABLE datagen_source1 (
k1 STRING NOT NULL,
v1 STRING NOT NULL
) WITH (
'connector' = 'datagen',
'fields.k1.length' = '10',
'fields.v1.length' = '10'
);
CREATE TEMPORARY TABLE mid_table(
con_str BIGINT
) WITH (
'connector' = 'print'
);
-- RPAD(VARCHAR str, INT len, VARCHAR pad) 如果str不满足len长度,填充pad
CREATE TEMPORARY FUNCTION `mysum1` AS 'AggFTest01$Test01';
BEGIN STATEMENT SET;
INSERT INTO mid_table
SELECT `mysum1`(t1.v2)
FROM
(select
CONCAT(k1,'_',v1) as v2
from
datagen_source1) t1
;
END;
资源上传方式
具体的内容,官网应该很清晰了,这个小标题下,会汇总一些用户使用出现的小问题
算是自己的学习小汇总嘞
VVP上传UDF(官方)
点击对应函数,可直接使用对应函数
自定义命名后报错jar存在
VVP平台上传的JAR名称也具有唯一性,可理解为UDF名称,JAR名称不是联合主键。
补充
1、UDF里面增加了日志逻辑,控制台没有日志输出
解决办法:
2、多输入