一、背景说明:
在上篇文章实现了TopN计算,但是碰到迟到数据则会无法在当前窗口计算,需要对其中的键控状态优化
本次需求是对数据进行统计,要求每隔5秒,输出最近10分钟内访问量最多的前N个URL,数据流预览如下(每次一条从端口传入):
208.115.111.72 - - 17/05/2015:10:25:49 +0000 GET /?N=A&page=21 //15:50-25:50窗口数据
208.115.111.72 - - 17/05/2015:10:25:50 +0000 GET /?N=A&page=21
208.115.111.72 - - 17/05/2015:10:25:51 +0000 GET /?N=A&page=21
208.115.111.72 - - 17/05/2015:10:25:52 +0000 GET /?N=A&page=21 //第一次触发计算,15:50-25:50窗口
208.115.111.72 - - 17/05/2015:10:25:47 +0000 GET /?N=A& //迟到数据,不同url
208.115.111.72 - - 17/05/2015:10:25:53 +0000 GET /?N=A&page=21 //第二次触发计算,15:50-25:50窗口
208.115.111.72 - - 17/05/2015:10:25:46 +0000 GET /?N=A&page=21 //迟到数据
208.115.111.72 - - 17/05/2015:10:25:54 +0000 GET /?N=A&page=21 //第三次触发计算
最后统计输出结果如下(迟到数据均在25:50窗口):
==============2015-05-17 10:25:50.0============== //第一次触发计算结果
Top1 Url:/?N=A&page=21 Counts:1
==============2015-05-17 10:25:50.0==============
==============2015-05-17 10:25:50.0============== //第二次触发计算结果
Top1 Url:/?N=A&page=21 Counts:1
Top2 Url:/?N=A& Counts:1
==============2015-05-17 10:25:50.0==============
==============2015-05-17 10:25:50.0============== //第三次触发计算结果
Top1 Url:/?N=A&page=21 Counts:2
Top2 Url:/?N=A& Counts:1
==============2015-05-17 10:25:50.0==============
二、实现过程
- 实现思路:
①建立环境,设置并行度及CK。
②定义watermark策略及事件时间,获取数据并对应到JavaBean。
③第一次聚合,按url分组开窗聚合,使用aggregate算子进行增量计算。
④第二次聚合,按窗口聚合,使用MapState存放数据,定义第一个定时器,在watermark达到后1秒触发,对窗口数据排序输出,定义第二个定时器,窗口关闭后才清楚状态。
⑤打印结果及执行。
ps:乱序数据不能使用读取本地文本文件的方式测试,文件读取加载比较快,无法观察到迟到数据处理效果,乱序数据的开发测试这里从服务器端口获取数据的方式测试
- 代码细节说明:
只针对优化部分代码说明,其他代码可以在顺序数据篇文章查看,这里提取重写KeyedProcessFunction里面方法的部分代码
@Override
public void processElement(UrlCount value, Context ctx, Collector<String> out) throws Exception {
//状态装入数据
mapState.put(value.getUrl(), value);
//定时器,窗口一秒后触发
ctx.timerService().registerEventTimeTimer(value.getWindowEnd()+1L);
//再加一个定时器来清除状态用,在窗口关闭后再清除状态,这样延迟数据到达后窗口还能做排序
ctx.timerService().registerEventTimeTimer(value.getWindowEnd()+61001L);
}
//定时器内容
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out) throws Exception {
if (timestamp == ctx.getCurrentKey()+61001L){
mapState.clear();
return;}
...
- 这里改用MapState,如若使用ListState,进来迟到数据后,则会出现同个url在同个窗口的统计出现多个计数的情况,列表状态不具备去重功能,故在这里使用map状态来实现去重。
- 这里使用定时器来清除状态,原写法是在onTimer最后排序完直接清除状态,则会导致迟到数据到达后,原窗口其他数据被清除掉无法实现排名的输出,这里定时器的时间是在61001毫秒后清除状态数据。
- 定时器61001毫秒 = 允许迟到数据1秒(forBoundedOutOfOrderness)+窗口迟到数据1分钟(allowedLateness)+第一个定时器1毫秒。
三、完整代码
package com.test.topN;
import bean.ApacheLog;
import bean.UrlCount;
import org.apache.commons.compress.utils.Lists;
import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache
Flink实时计算:处理迟到数据的TopN实现

本文介绍了如何使用Flink处理迟到数据,以实现每隔5秒输出最近10分钟内访问量最多的URL。通过设置watermark策略、使用SlidingEventTimeWindows和MapState,确保了迟到数据的正确处理。在KeyedProcessFunction中,使用两个定时器分别在窗口结束1秒后和61001毫秒后触发,以完成排序输出和清理状态。完整代码展示了这一过程。
最低0.47元/天 解锁文章
3199

被折叠的 条评论
为什么被折叠?



