Trigger决定了什么时候窗⼝准备就绪了,⼀旦窗⼝准备就绪就可以使⽤WindowFunction进⾏计算。每⼀个 WindowAssigner 都会有⼀个默认的Trigger。如果默认的Trigger不满⾜⽤户的需求⽤户可以⾃定义Trigger。
触发器接⼝具有五种⽅法,这些⽅法允许触发器对不同事件做出反应:
public abstract class Trigger<T, W extends Window> implements Serializable {
/**
只要有元素落⼊到当前窗⼝, 就会调⽤该⽅法
* @param element 收到的元素
* @param timestamp 元素抵达时间.
* @param window 元素所属的window窗⼝.
* @param ctx ⼀个上下⽂对象,通常⽤该对象注册 timer(ProcessingTime/EventTime) 回调.
*/
public abstract TriggerResult onElement(T element, long timestamp, W window,
TriggerContext ctx) throws Exception;
/**
* processing-time 定时器回调函数
*
* @param time 定时器触发的时间.
* @param window 定时器触发的窗⼝对象.
* @param ctx ⼀个上下⽂对象,通常⽤该对象注册 timer(ProcessingTime/EventTime) 回调.
*/
public abstract TriggerResult onProcessingTime(long time, W window, TriggerContext
ctx) throws Exception;
/**
* event-time 定时器回调函数
*
* @param time 定时器触发的时间.
* @param window 定时器触发的窗⼝对象.
* @param ctx ⼀个上下⽂对象,通常⽤该对象注册 timer(ProcessingTime/EventTime) 回调.
*/
public abstract TriggerResult onEventTime(long time, W window, TriggerContext ctx)
throws Exception;
/**
* 当 多个窗⼝合并到⼀个窗⼝的时候,调⽤该⽅法,例如系统SessionWindow
* {@link org.apache.flink.streaming.api.windowing.assigners.WindowAssigner}.
*
* @param window 合并后的新窗⼝对象
* @param ctx ⼀个上下⽂对象,通常⽤该对象注册 timer(ProcessingTime/EventTime)回调以及访问
状态
*/
public void onMerge(W window, OnMergeContext ctx) throws Exception {
throw new UnsupportedOperationException("This trigger does not support merging.");
}
/**
* 当窗⼝被删除后执⾏所需的任何操作。例如:可以清除定时器或者删除状态数据
*/
public abstract void clear(W window, TriggerContext ctx) throws Exception;
}
关于上述⽅法,需要注意两件事:
1)前三个⽅法决定如何通过返回TriggerResult来决定窗⼝是否就绪。
public enum TriggerResult {
/**
* 不触发,也不删除元素
*/
CONTINUE(false, false),
/**
* 触发窗⼝,窗⼝出发后删除窗⼝中的元素
*/
FIRE_AND_PURGE(true, true),
/**
* 触发窗⼝,但是保留窗⼝元素
*/
FIRE(true, false),
/**
* 不触发窗⼝,丢弃窗⼝,并且删除窗⼝的元素
*/
PURGE(false, true);
private final boolean fire;//是否触发窗⼝
private final boolean purge;//是否清除窗⼝元素
...
}
2)这些⽅法中的任何⼀种都可以⽤于注册处理或事件时间计时器以⽤于将来的操作.
案例使⽤
class UserDefineCountTrigger(maxCount:Long) extends Trigger[String,TimeWindow]{
var rsd:ReducingStateDescriptor[Long]= new ReducingStateDescriptor[Long]("rsd",new
ReduceFunction[Long] {
override def reduce(value1: Long, value2: Long): Long = value1+value2
},createTypeInformation[Long])
override def onElement(element: String, timestamp: Long, window: TimeWindow, ctx:
Trigger.TriggerContext): TriggerResult = {
val state: ReducingState[Long] = ctx.getPartitionedState(rsd)
state.add(1L)
if(state.get() >= maxCount){
state.clear()
return TriggerResult.FIRE_AND_PURGE
}else{
return TriggerResult.CONTINUE
}
}
override def onProcessingTime(time: Long, window: TimeWindow, ctx:
Trigger.TriggerContext): TriggerResult = TriggerResult.CONTINUE
override def onEventTime(time: Long, window: TimeWindow, ctx:
Trigger.TriggerContext): TriggerResult =TriggerResult.CONTINUE
override def clear(window: TimeWindow, ctx: Trigger.TriggerContext): Unit = {
println("==clear==")
ctx.getPartitionedState(rsd).clear()
}
}
object FlinkTumblingWindowWithCountTrigger {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
val text = env.socketTextStream("CentOS", 9999)
//3.执⾏DataStream的转换算⼦
val counts = text.flatMap(line=>line.split("\\s+"))
.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))
.trigger(new UserDefineCountTrigger(4L))
.apply(new UserDefineGlobalWindowFunction)
.print()
//5.执⾏流计算任务
env.execute("Global Window Stream WordCount")
}
}