窗口聚合函数
如果定义了 Window Assigner 之后,下一步就可以定义窗口内数据的计算逻辑,这也就是 Window Function 的定义。
Flink 中提供了四种类型的 Window Function , 分别为ReduceFunction、AggregateFunction 以及 ProcessWindowFunction,(sum 和 max)等。
前三种类型的 Window Fucntion 按照计算原理的不同可以分为两大类:
- 一类是增量聚合函数:对应有 ReduceFunction、AggregateFunction;
- 另一类是全量窗口函数,对应有 ProcessWindowFunction(还有 WindowFunction)。增量聚合函数计算性能较高,占用存储空间少,主要因为基于中间状态的计算结果,窗口中只维护中间结果状态值,不需要缓存原始数据。而全量窗口函数使用的代价相对较高, 性能比较弱,主要因为此时算子需要对所有属于该窗口的接入数据进行缓存,然后等到窗口触发的时候,对所有的原始数据进行汇总计算。
下面是AggregateFunction一种用法
package com.jh.windows
import org.apache.flink.api.common.functions.AggregateFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object TestAggregateFuntionWindow
{
def main(args: Array[String]): Unit =
{
val env = StreamExecutionEnvironment.getExecutionEnvironment
/*获取stream 读取数据源 */
val socketStream = env.socketTextStream("localhost", 9999)
val stream = socketStream.map(line =>
{
import com.jh.source.StationLog
val splited = line.split(",")
//使用样例类存储对象
StationLog(splited(0).trim, splited(1).trim, splited(2).trim, splited(3).trim, splited(4).trim.toLong, splited
(5).trim.toLong)
})
stream.map(log => (log.sid, 1.toLong))
.keyBy(_._1)//分组
.window(SlidingProcessingTimeWindows.of(Time.seconds(5), Time.seconds(3)))//开窗
.aggregate(new myAggregate, new Mywindows)//增量聚合
.print()
env.execute("Start --->")
}
/* WindowFunction 需要传入4个参数:
* IN:是输入的类型 (他的输入就是aggregate方法的输出)
* OUT:是输出的类型
* KEY:key的类型
* W <: Window :窗口的类型
* */
/*WindowFunction 输入数据来自AggregateFuntion, 在窗口结束的时候先执行Aggregate对象的getResult,然后再执行 自己的apply对象*/
class Mywindows extends WindowFunction[Long, (String, Long), String, TimeWindow]
{
override def apply(key: String, window: TimeWindow, input: Iterable[Long], out: Collector[(String, Long)]): Unit
=
{
out.collect((key,input.iterator.next()))/*next是得到第一个值 迭代器中只有一个值*/
}
}
/*aggregate(new myAggregate): 传入一个参数的时候返回值是这样为何?
1> 4
3> 3
3> 5
2> 3
1> 9
因为在aggregate的方法中
override def getResult(accumulator: Long): Long = accumulator
返回的就是一个 累加的数值。
这样我们就没法知道是哪个key的数据。
(preAggregator: AggregateFunction[T, ACC, V],windowFunction: WindowFunction[V, R, K, W])
然后我们使用windowFuntion来处理这种问题,传入两个参数 ,把Aggregate的数据给WindowFuntion处理。
*/
/*里面的add方法, 是来一条数据执行一次 ,getResult,在从窗口结束的时候执行一次*/
class myAggregate extends AggregateFunction[(String, Long), Long, Long]
{
//累加器的初始值为0
override def createAccumulator(): Long = 0
//累加器和传入的value进行累加 (传入的是元组,value为1)
override def add(value: (String, Long), accumulator: Long): Long = accumulator + value._2
override def getResult(accumulator: Long): Long = accumulator
/*如果有两个分区 合并两个分区的数据*/
override def merge(a: Long, b: Long): Long = a + b
}
}
/* sid: String : 基站的id
callOut: String 主叫号码
callIn: String 被叫号码
callType: String 呼叫类型
callTime 呼叫时间
duration 通话时长
数据的样式
station_9,18600005798,18900002238,busy,1577080455129,0
station_4,18600008825,18900008585,busy,1577080457129,0
station_6,18600005404,18900000558,success,1577080457129,5
station_2,18600002658,18900002018,busy,1577080457129,0
station_2,18600004925,18900001911,busy,1577080457129,0
station_5,18600003713,18900000824,busy,1577080457129,0
*/
case class StationLog(sid: String, callOut: String,callIn: String,callType: String,callTime:Long,duration:Long)
3379

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



