Flink的Aggregate算子的用法

窗口聚合函数

如果定义了 Window Assigner 之后,下一步就可以定义窗口内数据的计算逻辑,这也就是 Window Function 的定义。

Flink 中提供了四种类型的 Window Function , 分别为ReduceFunction、AggregateFunction 以及 ProcessWindowFunction,(sum 和 max)等。

前三种类型的 Window Fucntion 按照计算原理的不同可以分为两大类:

  1. 一类是增量聚合函数:对应有 ReduceFunction、AggregateFunction;
  2. 另一类是全量窗口函数,对应有 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)

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值