FLink迟到数据的处理之三

Flink迟到的数据更新窗口计算结果,窗口销毁后的迟到数据输出到测输出流

主程序:

//TODO 使用迟到的数据更新窗口的计算结果
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
Properties properties = new Properties();
properties.setProperty(“bootstrap.servers”, “hadoop106:9092”);
SingleOutputStreamOperator<String> result = env.addSource(new FlinkKafkaConsumer<String>
(“Tuple2”, new SimpleStringSchema(), properties))
.map(new MapFunction<String, Tuple2<String, Long>>() {
@Override
public Tuple2<String, Long> map(String value) throws Exception {
return Tuple2.of(value.split(” “)[0], Long.parseLong(value.split(” “)[1]) * 1000L);
}
}).assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple2<String, Long>>forMonotonousTimestamps()
.withTimestampAssigner(new SerializableTimestampAssigner<Tuple2<String, Long>>() {
@Override
public long extractTimestamp(Tuple2<String, Long> element, long recordTimestamp) {
return element.f1;
}
})).keyBy(r -> r.f0)
.window(TumblingEventTimeWindows.of(Time.seconds(5)))
.allowedLateness(Time.seconds(5))//允许迟到时间为5秒 窗口闭合触发计算 但是窗口不销毁 5秒内 迟到的数据如果
// 到来的话 更新窗口的计算结果 允许迟到时间和最大延迟时间的区别是 设置允许迟到时间可以提前看到窗口的聚合结果 虽然不准确
// 但是后面迟到的数据到来的话会更新窗口的计算结果 如果时间超过了允许迟到时间 那么可以将迟到的数据发送到侧输出流中
.sideOutputLateData(new OutputTag<Tuple2<String, Long>>(“lateStream”) {
})
.process(new ProcessWindowFunction<Tuple2<String, Long>, String, String, TimeWindow>() {
@Override
public void process(String s, Context context, Iterable<Tuple2<String, Long>> elements, Collector<String> out) throws Exception {
// out.collect(“key:”+s+”窗口的时间范围是:“+new Timestamp(context.window().getStart())+
// “-“+new Timestamp(context.window().getEnd())+”元素的个数是:“+elements.spliterator().
// getExactSizeIfKnown());
// 窗口闭合的时候,触发窗口的第一次计算
ValueState<Boolean> firstCalculate = context.windowState().getState(new
ValueStateDescriptor<Boolean>(“firstCalculate”, Types
.BOOLEAN));
if (firstCalculate.value() == null) {
out.collect(窗口第一次触发计算,窗口中的元素个数是:” + elements.spliterator().
getExactSizeIfKnown() + 窗口的时间范围是:” + new Timestamp(context.window().getStart()) + “-” +
new Timestamp(context.window().getEnd()));
firstCalculate.update(true);
} else {
out.collect(迟到的元素触发计算了,更新后的元素的个数是:” + elements.spliterator()
.getExactSizeIfKnown());
}
}
});
result.printToErr(主流输出“);
result.getSideOutput(new OutputTag<Tuple2<String, Long>>(“lateStream”) {
}).print(测输出流“);
env.execute();
}

程序分析:

通过kafka生产者往Tuple2 topic中生产数据,当输入a 1的时候,此时开启一个0-5s钟的窗口,当输入a 5的时候,0-5s的窗口第一次触发计算,此时窗口闭合,触发窗口函数process的执行,由于是窗口

的第一次计算,将状态变量置为true,后续迟到的数据在允许等待迟到时间内到达将触发窗口的第2/3/4次计算等等,更新计算结果,当输入a 10的时候,此时的水位线为9999,到达了0-5s的窗口销毁的时间,

0-5s的窗口在窗口结束时间+允许等待迟到时间也就是10s的时候销毁。后续如果0-5s窗口的数据到来,通过sideOutPutLateData窗口函数将会被发送到侧输出流。