FLink学习笔记:06-Flink 的Window

Window

Window的作用

Flink Streaming 流式计算是一种被设计用于处理无限数据集的数据处理引擎,而无线数据集是一种不断增长的本质上无限的数据集,Window这是用于一种切割无限数据为有限块进行处理的手段

Window是无限数据流处理的核心,将无限的Stream,拆分成有限大小的“buckets”,我们可以在这些buckets中对数据做计算处理。

用 Flink 计算窗口分析取决于两个主要的抽象操作:Window Assigners,将事件分配给窗口(根据需要创建新的窗口对象),以及 Window Functions,处理窗口内的数据。

Flink 的窗口 API 还具有 Triggers 和 Evictors 的概念,Triggers 确定何时调用窗口函数,而 Evictors 则可以删除在窗口中收集的元素。

举一个简单的例子,我们一般这样使用键控事件流(基于 key 分组的输入事件流):

stream.
    .keyBy(<key selector>)
    .window(<window assigner>)
    .reduce|aggregate|process(<window function>)

您不是必须使用键控事件流(keyed stream),但是值得注意的是,如果不使用键控事件流,我们的程序就不能 并行 处理。

stream.
    .windowAll(<window assigner>)
    .reduce|aggregate|process(<window function>)

Window的类型

从数据的角度上,Window 可以分为两大类:

  • CountWindow:按照指定的数据条数生成一个Window,与时间无关。
  • TimeWindow:按照时间切割成一个个Window

从实现原理上又可以分为两类:

  • Tumbling Window 滚动窗口
  • Sliding Window 滑动窗口

滚动窗口(Tumbling Window)

将数据依据固定的窗口长度对数据进行切片.
特点:

  • 时间对齐
  • 窗口长度固定
  • 没有重叠

滑动窗口SlidingWindow

滑动窗口是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成。
特点:

  • 时间对齐
  • 窗口长度固定
  • 窗口和窗口之间可以有重叠
  • 有一个移动步长

会话窗口SessionWindow

由一系列事件组合一个指定长度的timeout的间隙组成,类似于WEB应用中的Session,也就是一段时间没有接收到新的数据就会生成新的窗口。
特点:

  • 时间无对齐
  • 窗口大小不固定,只有在时间窗口类型中才有会话窗口。
  • 和滑动窗口、滚动窗口相比,不会有重叠和固定的开始时间和结束时间。相反,在一个固定的时间间隔内收不到新的数据,那么这个窗口就会关闭。

Flink的内置窗口分配器

Window分配器.png

Tumbling time windows 滚动时间窗口

例如每隔15秒统计一次最小温度

val minTempPerWindow = dataStream
.map( data => (data.id,data.temperature))
.keyBy(_._1)
.timeWindow(Time.seconds(15))
.reduce((r1,r2) => (r1._1,r1._2.min(r2._2)))

或者使用原始写法:

val minTempPerWindow = dataStream
.map( data => (data.id,data.temperature))
.keyBy(_._1)
.window(TumblingEventTimeWindows.of(Time.seconds(15)))
.reduce((r1,r2) => (r1._1,r1._2.min(r2._2)))

时间窗口的时间间隔可以通过Time.milliseconds(X),Time.seconds(X),Time.minutes(X)等指定。

Sliding time windows 滑动时间窗口

滑动时间窗口由一个窗口大小和时间间隔组成。

如每隔5秒钟统计一次最近15秒内的每一组的最低温度:

val minTempPerWindow = dataStream
.map( data => (data.id,data.temperature))
.keyBy(_._1)
.timeWindow(Time.seconds(15),Time.seconds(5))
.reduce((r1,r2) => (r1._1,r1._2.min(r2._2)))

或者使用原始写法:

val minTempPerWindow = dataStream
.map( data => (data.id,data.temperature))
.keyBy(_._1)
.window(SlidingEventTimeWindows.of(Time.seconds(15),Time.sec onds(5))
.reduce((r1,r2) => (r1._1,r1._2.min(r2._2)))

Tumbling count windows 滚动窗口

如每5条数据就统计一次最小的温度,计算的范围是5条数据

val minTempPerWindow: DataStream[(String, Double)] = dataStream 
.map(r => (r.id, r.temperature)) 
.keyBy(_._1)
.countWindow(5) 
.reduce((r1, r2) => (r1._1, r1._2.max(r2._2)))

Sliding count windows 滑动窗口

滑动窗口和滚动窗口的函数名是完全一致的,只是在传参数时需要传入两个参 数,一个是 window_size,一个是 sliding_size。 下面代码中的 sliding_size 设置为了 2,也就是说,每收到两个相同 key 的数据 就计算一次,每一次计算的 window 范围是 10 个元素。

val keyedStream: KeyedStream[(String, Int), Tuple] = dataStream
.map(r => (r.id, r.temperature))
.keyBy(0)
val windowedStream: WindowedStream[(String, Int), Tuple, GlobalWindow] = keyedStream.countWindow(10,2) 
val sumDstream: DataStream[(String, Int)] = windowedStream.sum(1)

Session windows 会话窗口

.window(EventTimeSessionWindows.withGap(Time.seconds(15)))

Global window 全局窗口

.window(GlobalWindows.create())

窗口应用函数

window function 定义了要对窗口中收集的数据做的计算操作,主要可以分为两 类:

增量聚合函数(incremental aggregation functions)

每条数据到来就进行计算,保持一个简单的状态。典型的增量聚合函数有 ReduceFunction, AggregateFunction。

DataStream<SensorReading> input = ...

input
    .keyBy(x -> x.key)
    .window(TumblingEventTimeWindows.of(Time.minutes(1)))
    .reduce(new MyReducingMax(), new MyWindowFunction());

private static class MyReducingMax implements ReduceFunction<SensorReading> {
    public SensorReading reduce(SensorReading r1, SensorReading r2) {
        return r1.value() > r2.value() ? r1 : r2;
    }
}

private static class MyWindowFunction extends ProcessWindowFunction<
    SensorReading, Tuple3<String, Long, SensorReading>, String, TimeWindow> {

    @Override
    public void process(
            String key,
            Context context,
            Iterable<SensorReading> maxReading,
            Collector<Tuple3<String, Long, SensorReading>> out) {

        SensorReading max = maxReading.iterator().next();
        out.collect(Tuple3.of(key, context.window().getEnd(), max));
    }
}

全窗口函数(full window functions)

先把窗口所有数据收集起来,等到计算的时候会遍历所有数据。 ProcessWindowFunction 就是一个全窗口函数。

DataStream<SensorReading> input = ...

input
    .keyBy(x -> x.key)
    .window(TumblingEventTimeWindows.of(Time.minutes(1)))
    .process(new MyWastefulMax());

public static class MyWastefulMax extends ProcessWindowFunction<
        SensorReading,                  // 输入类型
        Tuple3<String, Long, Integer>,  // 输出类型
        String,                         // 键类型
        TimeWindow> {                   // 窗口类型

    @Override
    public void process(
            String key,
            Context context,
            Iterable<SensorReading> events,
            Collector<Tuple3<String, Long, Integer>> out) {

        int max = 0;
        for (SensorReading event : events) {
            max = Math.max(event.value, max);
        }
        out.collect(Tuple3.of(key, context.window().getEnd(), max));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值