大数据实操篇 No.18-Flink 处理函数介绍和使用(ProcessFunction)

第1章 简介

 

常规的项目开发中,我们常用的API有:SQL/Table API、DataStream API。而DataStream API其实还提供了一组相对底层的转换——处理函数(ProcessFunction)

我们可以从Flink API的三层模型中看到,ProcessFunction位于最底层,它除了最基本的功能外,还可以访问记录的timestamp和watermark,并且可以注册在将来某个特定时间触发的Timer定时器。

第2章 处理函数类型

Flink目前提供了8种不同的处理函数:

ProcessFunction:处理函数

KeyedProcessFunction:键值分区的处理函数

CoProcessFunction:双流处理函数

ProcessJoinFunction:多流join处理函数

BroadcastProcessFunction:广播流处理函数

KeyedBroadcastProcessFunction:键值分区的广播流处理函数

ProcessWindowFunction:键值分区的窗口处理函数

ProcessAllWindowFunction:非键值分区的窗口处理函数

这些函数适用于不同的上下文环境,但是他们的功能都很相似。下面我们以ProcessFunction和KeyedProcessFunction为例实现几个小demo。

第3章 基本使用

3.1 ProcessFunction

定义一个继承ProcessFunction的类

private static class ConfirmIncreaseFunctoin extends ProcessFunction<Tuple3<String, Integer, Long>,String>{
	private final int threshold=100;
	private ValueState<Long> currentTime;
	private MapState<String,Integer> areaTime;
	
	//...

	@Override
	public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out) throws Exception {
		super.onTimer(timestamp, ctx, out);
		// 10秒之后,输出超过100例的城市
		Iterator<Map.Entry<String, Integer>> iterator = areaTime.iterator();
		while (iterator.hasNext()){
			Map.Entry<String, Integer> map = iterator.next();
			if(map.getValue()>threshold){
				out.collect(map.getKey());
				areaTime.remove(map.getKey());
			}
		}
		currentTime.clear();
	}

	@Override
	public void processElement(Tuple3<String, Integer, Long> tp, Context context, Collector<String> collector) throws Exception {
		// 城市
		String city = tp.f0;
		// 确诊数量
		Integer num = tp.f1;

		// 不存在计时器
		if (areaTime.contains(city)) {
			Integer times = areaTime.get(city);
			Integer currentSumTimes = (times + num) > 0 ? (times + num) : 0;
			if (currentSumTimes >= threshold) {
				// 超过100例,设置计时器,以当前processingtime+10000毫秒进行设置
				long timerTs = context.timerService().currentProcessingTime() + 10000;
				context.timerService().registerProcessingTimeTimer(timerTs);
				currentTime.update(timerTs);
			} else {
				// 小于100例
				Long value = currentTime.value();
				if(value !=null) {
					context.timerService().deleteProcessingTimeTimer(currentTime.value());
					areaTime.remove(city);
					currentTime.clear();
				}
			}
			areaTime.put(city, currentSumTimes);
		}else{
			areaTime.put(city, num > 0 ? num : 0);
		}
	}
}

 在主函数中进行调用

public static void main(String[] args) throws Exception {
	StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
	//模拟数据源:地区,核酸检测确诊人数,当前时间
	DataStream<Tuple3<String, Integer, Long>> dataStream = env.addSource(new SourceFunction<Tuple3<String, Integer, Long>>() {
		//...
	});

	//TODO 调用自定义的ProcessFunction处理函数
	dataStream.keyBy(new KeySelector<Tuple3<String, Integer, Long>, Object>() {
		@Override
		public Object getKey(Tuple3<String, Integer, Long> tp) throws Exception {
			return tp.f0;
		}
	}).process(new ConfirmIncreaseFunctoin()).print();

	env.execute("Nucleic Acid Test");//核酸检测
}

3.2 KeyedProcessFunction

定义一个继承KeyedProcessFunction的类

private static class ConfirmIncreaseFunctoin extends KeyedProcessFunction<Tuple,Tuple3<String, Integer, Long>,String> {
	private ValueState<Long> currentTime;

	//...

	@Override
	public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out) throws Exception {
		super.onTimer(timestamp, ctx, out);
		Tuple currentKey = ctx.getCurrentKey();
		out.collect(currentKey.toString());
		currentTime.clear();
	}

	@Override
	public void processElement(Tuple3<String, Integer, Long> tp, Context context, Collector<String> collector) throws Exception {
		String area = tp.f0;
		Integer num = tp.f1;

		Long value = currentTime.value();
		// 不存在计时器
		if(value == null){
			if(num>=3){
				long timerTs = context.timerService().currentProcessingTime()+10000;
				// 设置计时器,以当前processingtime+10000毫秒进行设置
				context.timerService().registerProcessingTimeTimer(timerTs);
				currentTime.update(timerTs);
			}
		}
		else {
			// 已经存在计时器
			if(num<3) {
				// 删除当前计时器
				context.timerService().deleteProcessingTimeTimer(value);
				currentTime.clear();
			}
		}
	}
}

在主函数中进行调用

public static void main(String[] args) throws Exception {
	StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
	//模拟数据源:地区,核酸检测确诊人数,当前时间
	DataStream<Tuple3<String, Integer, Long>> dataStream = env.addSource(new SourceFunction<Tuple3<String, Integer, Long>>() {
	    //...
	});

	//TODO KeyBy分区后,调用自定义的KeyedProcessFunction处理函数
	dataStream.keyBy(0)
			.process(new ConfirmIncreaseFunctoin()).print();

	env.execute("Nucleic Acid Test");//核酸检测
}

完整demo请查看github:https://github.com/zihaodeng/hellobigdata/tree/main/flink-online/flink-api


今天是建党100周年,引用今天听到的党员精神里的一句话:“敢于斗争,善于斗争,逢山开道、遇水架桥,勇于战胜一切风险挑战!”。继续奋斗吧少年!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pezynd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值