flink Window使用总结

首先结合flink四大基石去理解:时间 、状态 、检查点 、 窗口

        其中窗口之所以这么重要是因为,我们知道flink是流批一体的、需要对数据进行统计计算的时候就用到了窗口。然后窗口也是一个逻辑的概念,实际上就是对数据在某个阶段做某种操作。经过规范后

窗口按时间划分:有滚动窗口和滑动窗口;

按照数量划分: 也有滚动窗口和滑动窗口;

其实还有一种就是会话窗口,但是用得不多,这边也不太了解。

(滚动窗口如果填两个参数,那么第二个参数是偏移量)

源码如下:

protected TumblingEventTimeWindows(long size, long offset, WindowStagger windowStagger) {
    if (Math.abs(offset) >= size) {
        throw new IllegalArgumentException(
                "TumblingEventTimeWindows parameters must satisfy abs(offset) < size");
    }

    this.size = size;
    this.globalOffset = offset;
    this.windowStagger = windowStagger;
}

@Override
public Collection assignWindows(
        Object element, long timestamp, WindowAssignerContext context) {
    if (timestamp > Long.MIN_VALUE) {
        if (staggerOffset == null) {
            staggerOffset =
                    windowStagger.getStaggerOffset(context.getCurrentProcessingTime(), size);
        }
        // Long.MIN_VALUE is currently assigned when no timestamp is present
        long start =
                TimeWindow.getWindowStartWithOffset(
                        timestamp, (globalOffset + staggerOffset) % size, size);
        return Collections.singletonList(new TimeWindow(start, start + size));
    } else {
        throw new RuntimeException(
                "Record has Long.MIN_VALUE timestamp (= no timestamp marker). "
                        + "Is the time characteristic set to 'ProcessingTime', or did you forget to call "
                        + "'DataStream.assignTimestampsAndWatermarks(...)'?");
    }
}

所以可以这样写就是每天凌晨八点开始计算。

windowAll(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))

另外窗口也分为 分组后的窗口 和 没有分组后使用的窗口

分别是 window 和 windowAll

有分组的话,我们可以想象就是很多个窗口分别计算结果,没有分组的话就是只有一个窗口。

根据Sql语句去理解的话就是,加和不加group by 聚合出来的结果是不一样的。

窗口组件assigner做的就是这种事情

窗口操作包含以下四个组件:

  • 1、assigner(分配器):如何将元素分配给窗口
  • 2、function(计算函数):为窗口定义的计算:其实是一个计算函数,完成窗口内容的计算。
  • 3、triger(触发器):在什么条件下触发窗口的计算
  • 4、evictor(退出器):定义从窗口中移除数据

1、assigner已经说过了。

2、function 就是窗口中具体要做的事情,常用的有:

  • ReduceFunction                   格式不变的增量聚合
  • AggregateFunction               格式可以修改的增量聚合(更灵活)
  • ProcessWindowFunction      自定义处理方案(非常灵活)

这些方法跟在定义好的window后面,比如 

 flink Window使用总结_第1张图片

前两种方法使用比较方便,但是自定义方法最灵活,使用的比较多。

自定义方法适合做一些全量操作,因为如图,他可以将输入的数据收集成一个iterable,然后就可以对其进行遍历,然后再存集合,使用集合的各种特性和方法实现需求。

3、然后是窗口的触发器triger

        触发器也分为四种:

        CONTINUE: 什么都不做

        FIRE:触发计算,

        PURGE: 清除窗口中的所有数据

        FIRE_AND_PURGE:触发计算并清除窗口中的所有数据

触发器的存在实现了窗口的按时关闭和计算。

4、最后是退出器evictor

        我们在使用Flink window时,还可以指定一个Evictor,它是一个可选组件。Evictor可以在触发器触发后,它可以在WindowFunction执行之前或者之后移除一些元素。

然后关于窗口的其他操作比如:

        1、可以通过allowedLateness延迟窗口关闭,如下能多保持五分钟

 flatMapDS
            .windowAll(TumblingEventTimeWindows.of(Time.seconds(5)))
            .allowedLateness(Time.minutes(5))

        2、通过sideOutputLateData可以获取到延迟的数据,然后我们可以使用侧输出流来获取侧输出结果数据。

        然后通过.getSideOutput("上面设置好的存入标签"),收集到最晚的数据,然后保证数据不丢失。

flatMapDS
        .windowAll(TumblingEventTimeWindows.of(Time.seconds(5)))
        .allowedLateness(Time.minutes(5))
        .sideOutputLateData(new OutputTag<>("isLate"));
        
        .getSideOutput("isLate")
        .print();

然后就是如果咱们的时间语义是“事件时间”的话 (当然一般使用的都是事件时间),那么就要在窗口操作之前先给数据加一个水位线了,其实就是打一个时间戳,使窗口的触发器能够触发计算。当然,如果时间语义是事件时间的话,不设水位线还要使用事件时间窗口操作那肯定是嘎嘎报错啊!

你可能感兴趣的:(flink,java)