flink window函数

window类型

时间窗口(time window)

        滚动时间窗口

        滑动时间窗口

        会话窗口

计数窗口(count window)

        滚动计数窗口

        滑动计数窗口

滚动窗口(tumbling window)

         将数据依据固定的窗口长度对数据进行切分

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

滑动窗口(sliding window)

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

        窗口长度固定,可以有重叠

会话窗口(session window)

由一系列事件组合一个指定时间长度的timeout间隙组成,也就是一段时间没有接收到新数据就会生成新的窗口

特点:时间无对齐

 window API

窗口分配器--window()方法

我们可以通过用.window()来定义一个窗口,然后基于这个window去做一些聚合或者其他处理操作。注意:window()方法必须在keyby之后才能用。

flink提供了更加简单的.timeWindow和.countWindow方法,用于定义时间窗口和技术窗口

 窗口分配器(window assigner)

window()方法接收的输入参数是一个windowAssigner

windowAssigner负责将每条输入的数据分发到正确的window中

flink提供了通用的WindowAssigner

        滚动窗口(tumbling window)

        滑动窗口(sliding window)

        会话窗口(session window)

        全局窗口(global window)

创建不同类型的窗口

滚动窗口  .timeWindow(Time.seconds(10))

滑动窗口.timeWindow(Time.seconds(15),Time.seconds(5))

会话窗口  .window(EventTimeSessionWindows.withGap(Time.minutes(10))

滚动计数窗口 .countWindow(5)

滑动计数窗口.countWindow(10,2)

窗口函数(window function)

Flink中提供了四种类型的Window Function,分别为ReduceFunction、AggregateFuture(新版本废弃)、FoldFunction、ProcessWindowFunction,按照计算原理不同又分为两大类。

1,增量聚合函数,对应ReduceFunction、AggregateFunction、FoldFunction

  • 该类型函数计算性能较高,占用存储空间少,因为窗口中只维护中间结果状态值,不需要缓存原始数据。

2,全量窗口函数:对应ProcessWindowFunction。

  • 该类型函数使用代价较高,性能较弱,因为算子需要对所有属于该窗口的接入数据进行缓存,等到窗口触发时,对所有的原始数据进行汇总计算。
  • 如果接入数据量较大或窗口时间较长,大概率会导致计算性能下降

ReduceFunction

  • 该函数对输入的两个相同类型的数据元素按照指定的计算方法进行聚合逻辑,最终输出类型相同的结果元素。
  • 实例代码如下:
val inputStream:DataStream[(Int,Long)]=...;
val reduceWindowStream = inputStream
    .keyBy(_._0)
    //指定窗口类型
    .window(SlidingEventTimeWindows.of(Time.hours(1),Time.minutes(10)))
    //指定聚合函数逻辑,将根据ID将第二个字段求和
    .reduce{(v1,v2) => (v1._1,v1._2 + v2._2)}

  • 除了直接使用表达式方式实现ReduceFunction逻辑定义,也可以创建Class实现ReduceFunction接口来定义聚合逻辑,实例如下:
 
val reduceWindowStream = inputStream.keyBy(_._1)
    //指定窗口类型
    .window(SlidingEventTimeWindows.of(Time.hours(1),Time.minutes(10)))
    //定义ReduceFunction实现类定义聚合函数逻辑,将根据ID将第二个字段求和
    .reduce(new ReduceFunction[(Int,Long)]){
        override def reduce(t1:(Int,Long),t2:(Int,Long)):(Int,Long) = {(t1._1,t1._2+t2._2)}
    }


AggregateFunction

与ReduceFunction相似,AggregateFunction同样基于中间状态计算结果的增量计算函数,但它更通用和灵活,实现复杂度更高。
AggregateFunction接口中定义了三个需要复写的方法
        add()定义数据的添加逻辑
        getResult()定义根据accumulator计算结果逻辑
        merge()定义合并accumulator逻辑
实例代码如下

//定义求取均值的AggregateFunction
class MyAverageAggregate extends AggregateFunction[(String,Long),(Long,Long),Double]{
    //定义createAccumulator为两个参数的元祖
    override def createAccumulator() = (0L,0L)
    //定义输入数据累加到accumulator的逻辑
    override def add(input:(String,Long),acc:(Long,Long)) = (acc._1+input._2,acc._2+1L)

    //更加累加器得出结果
    override def getResult(acc:(Long,Long))= acc._1 / acc._2
    //定义累加器合并的逻辑
    override def merge(acc:(Long,Long),acc2:(Long,Long))=(acc1._1+acc2._1,acc1._2+acc2._2)
}
//在DataStream API使用定义好的AggregateFunction
val inputStream:DataStream[(String,Long)] = ...
val aggregateWindowStream = inputStream.keyBy(_._1)
    //指定窗口类型
    .window(SlidingEventTimeWindows.of(Time.hours(1),Time.minutes(10)))
    //指定聚合函数逻辑,根据ID将第二个字段求平均值
    .aggregate(new MyAverageAggregate)


FoldFunction(新版本废弃)


该函数定义了如何将窗口中的输入元素与外部元素合并的逻辑,实例如下,将"flink"字符串添加到inputStream数据集中所有元素第二个字段上。代码如下:

val inputStream:DataStream[(String,Long)] = ...
val foldWindowStream = inputStream.keyBy(_._1)
    //指定窗口类型
    .window(SlidingEventTimeWindows.of(Time.hours(1),Time.minutes(10)))
    //指定聚合函数逻辑,将flink字符串和第二个字段相连接并输出
    .fold("flink"){(acc,v) => acc+v._2}


ProcessWindowFunction


统计复杂指标时,可能需要依赖整个窗口中所有的数据元素,或操作窗口中状态数据和窗口元数据,此时需要ProcessWindowFunction函数,完成基于窗口全部数据元素的结果计算。
例如统计窗口数据元素中某一字段的中位数和众数,实例代码如下,其中Context抽象类完整定义了Window的元数据以及可操作Window的状态数据,包括GlobalState以及WindowState。
Flink中ProcessWindowsFunction抽象类定义

public abstract class ProcessWindowFunction<IN,OUT,KEY,W extends Window> extends AbstractRichFunction{
    //评估窗口并定义输出的元素
    void process(KEY key ,Context ctx,Interable<IN> vals,Collector<OUT> out) throws Exception;
    //定义清除每个窗口计算结束后中间状态的逻辑
    public void clear(Context ctx)throws Exception{}
    //定义包含窗口元数据的上下文
    public abstract class Context implements Serializable{
        //返回窗口的元数据
        public abstract W window();
        //返回窗口当前的处理时间
        public abstract long currentProcessingTime();
        //返回窗口当前的event-time的Watermark
        public abstract long currentWatermark();
        //返回每个窗口的中间状态
        public abstract KeyedStateStore windowState();
        //返回每个key对应的中间状态
        public abstract KeyedStateStore globalState();
        //根据OutputTag输出数据
        public abstract <X> void output(OutputTag<X> outputTag,x value);
    }
}


在实现ProcessWindowFunction接口时,如果不操作状态数据,仅实现proce()方法即可,该方法中定义了评估窗口和具体数据输出的逻辑。如下代码通过自定义实现ProcessWindowFunction完成基于窗口上的Key统计包括求和、最小值、最大值,以及平均值的聚合指标,并获取窗口结束时间等元数据信息。

val inputStream:DataStream[(String,Long)]=...;
//向DataStream数据集指定StaticProcessFunction
val staticStream = inputStream.keyBy(_._1).timeWindow(Time.seconds(10)).process(new StaticProcessFunction)

//定义StaticProcessFunction根据窗口中的数据统计指标
class StaticProcessFunction extend是 ProcessWindowFunction[(String,Long,Int),(String,Long,Long,Long,Long,Long),String,TimeWindow]{
    override def process(
        key:String,
        ctx:Context,
        vals:Interable[(String,Long,Int)],
        out:Collector[(String,Long,Long,Long,Long,Long)]):Unit = {
            //定义求和、最大值、最小值、均值、窗口时间戳
            val sum=vals.map(_._2).sum
            val min=vals.map(_._2).min
            val max=vals.map(_._2).max
            val savg=sum / vals.size
            val windowEnd = ctx.window.getEnd
            //通过out.collect返回计算结果
            out.collect((key,min,max,sum,avg,windowEnd))
        }
}


Incremental Aggregation和ProcessWindowFunction整合


ReduceFunction和AggregateFunction等增量聚合函数一定程度上能提升窗口计算性能,但灵活性不如ProcessWindowFunction。但ProcessWindowFunction更消耗资源。
此时可以将Incremental Aggregation Function和ProcessWindowFunction进行整合,充分利用两种函数各自的优势。
将增量的ReduceFunction和ProcessWindowFunction整合,求取窗口中指标最大值以及对应窗口的终止时间,实例如下:
 

val inputStream:DataStream[(String,Long)]=...;
val result = inputStream.keyBy(_._1)
    .timeWindow(Time.seconds(10))
    .reduce(
        //定义ReduceFunction完成求值最小值的逻辑
        (r1:(String,Long,Int),r2:(String,Long,Int)) =>{
            if(r1._2 >r2._2) r2 else r1
        },
        //定义ProcessWindowFunction,完成窗口元数据的采集
        (
            key:String,
            window:TimeWindow,
            minReadings: Interable[(String,Long,Int)],
            out: Collector[(Long,(String,Long,Int))]
        ) => {
            val min=minReadings.iterator.next()
            //采集窗口结束时间和最小值赌赢的数据元素
            out.collect((window.getEnd,min))
        }
    )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Flink中的窗口(window)是在流处理过程中对数据进行分组和聚合的一种机制。窗口将流数据划分为有限大小的数据块,然后对每个窗口中的数据进行处理和计算。 在Flink中,窗口有两种类型:时间窗口和计数窗口。时间窗口根据事件发生的时间范围对数据进行划分,而计数窗口根据事件发生的次数对数据进行划分。 根据时间的划分方式,时间窗口可以分为滚动窗口和滑动窗口。滚动窗口将数据按照固定长度的时间间隔进行划分,比如每5分钟划分一个窗口。滑动窗口则以固定的时间间隔进行滑动,比如每隔1分钟滑动一次窗口。 对于计数窗口,可以定义固定数量的事件来进行划分,比如每10个事件划分一个窗口。 窗口操作可以包括聚合、计数、求和、最大值、最小值等操作。在窗口操作中,Flink提供了丰富的函数和操作符来实现不同的聚合和计算需求。 窗口操作可以通过窗口函数window function)实现,窗口函数定义了对窗口中的数据进行聚合和处理的逻辑。 使用窗口操作可以提高流处理的性能和效率,通过将连续的数据划分为有限的窗口,可以减少计算的复杂性。同时,窗口操作也可以使得流处理应用更具可控性和灵活性。 在Flink中,窗口操作广泛应用于各种实时数据分析、实时计算和数据流处理的场景,如实时监测、实时查询、实时报警等。通过合理设置窗口大小和窗口滑动间隔,可以根据实际需求来进行数据处理和聚合,以满足不同的业务需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

YiRan_Zhao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值