Flink自定义Trigger

1. 介绍

本文主要介绍开窗后自定义窗口触发器,触发器触发包括两部分:
1.当窗口内的数据量达到一定数量后触发
2.当事件事件达到窗口最大时间戳后触发

2. 环境

Flink: 1.13.1
java:1.8.251
scala:2.11.12

3.Trigger类中主要方法

1)onElement() 为添加到窗格中的每个元素调用。此方法的结果将决定是否对窗格进行触发。
2)onProcessingTime() Flink使用的是处理时间语义时使用,该方法用来以时间作为条件触发窗口。
3)onEventTime() Flink使用的是事件时间语义时使用,该方法用来以时间作为条件触发窗口。
4)onMerge() 当多个窗口合并为一个窗口时调用(没用过)。
3)clear() 对当前窗口进行一些清理操作,比如状态值,定时器。

4.TriggerResult

1)CONTINUE:跳过,什么操作都不执行
2)FIRE:触发窗口并保留窗口内的数据
3)PURGE:简单地删除窗口的内容,并保留关于窗口和任何触发器状态的任何潜在元信息。
4)FIRE_AND_PURGE:触发计算,然后清除窗口中的元素。(默认情况下,预先实现的触发器只触发而不清除窗口状态。)

5.代码实现

注册水位线及开窗

val env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI()
    //此处是加载自己生成的数据源
    val dataSource = env.addSource(new MyTradingSource)
    //注册水位线:以交易时间作为事件时间
    //注意:水位线的时间戳要求是毫秒级的,常见时间戳为秒级,需要乘1000
    val keyedStream = dataSource
      .assignTimestampsAndWatermarks(
        WatermarkStrategy
          .forBoundedOutOfOrderness(Duration.ofSeconds(0))
          .withTimestampAssigner(new SerializableTimestampAssigner[TradingObject] {
            override def extractTimestamp(element: TradingObject, recordTimestamp: Long): Long = {
              element.tradingTime
            }
          })
      )//按照订单货物的类型进行分组
      .keyBy(_.name)
    //使用基于EventTime的滚动窗口,窗口间隔为5s
    keyedStream.window(TumblingEventTimeWindows.of(Time.seconds(5)))
      .trigger(new CustomTrigger)
      .process(new MyProcessWindowFunc)
      .print()
    env.execute()

自定义Trigger及Process

class CustomTrigger extends Trigger[TradingObject, Window] {
  //状态值:聚合状态,用来统计创久内的数据量
  private val number = new ReducingStateDescriptor[Long]("number", new reduceFunc, classOf[Long])

  override def onElement(element: TradingObject, timestamp: Long, window: Window, ctx: Trigger.TriggerContext): TriggerResult = {
    //获取状态
    val count = ctx.getPartitionedState(number)
    //每条数据进来后状态值+1
    count.add(1l)
    ctx.registerEventTimeTimer(window.maxTimestamp())
    //如果该窗口内的数据量>=5 则触发该窗口,状态值清空
    if (count.get() >= 5) {
      count.clear()
      TriggerResult.FIRE_AND_PURGE
    }else{
      TriggerResult.CONTINUE
    }
  }
   
  override def onProcessingTime(time: Long, window: Window, ctx: Trigger.TriggerContext): TriggerResult = {
    //因为使用的语义时事件时间,所以处理时间语义不做任何处理
    TriggerResult.CONTINUE
  }

  override def onEventTime(time: Long, window: Window, ctx: Trigger.TriggerContext): TriggerResult = {
    //当达到窗口最大值时则触发窗口计算
    if (time ==window.maxTimestamp()) TriggerResult.FIRE_AND_PURGE else TriggerResult.CONTINUE
  }

  override def clear(window: Window, ctx: Trigger.TriggerContext): Unit = {
    //清除操作
    ctx.deleteEventTimeTimer(window.maxTimestamp())
    ctx.getPartitionedState(number).clear()
  }
}
 //聚合状态计算方式
class reduceFunc extends ReduceFunction[Long] {
  override def reduce(value1: Long, value2: Long): Long = value1 + value2
}
//自定义Process,对该窗口内的数据按照货物类型进行聚合操作
class MyProcessWindowFunc extends ProcessWindowFunction[TradingObject, String, String, TimeWindow] {
  override def process(key: String, context: Context, elements: Iterable[TradingObject], out: Collector[String]): Unit = {
    val iterator = elements.iterator
    var sumPrice = 0.0
    while (iterator.hasNext) {
      val tradingObject = iterator.next()
      sumPrice = sumPrice + tradingObject.price
      //println(key, sumPrice)
    }
    out.collect("商品名称:" + key + "  " + "总价格:" + sumPrice)
    //out.collect("1111")
  }
}

你可能感兴趣的:(技术收藏,flink)