原理:结合Flink源码中的CountTrigger和EventTimeTrigger逻辑即可。
package net.ben.flink.hbase.function.trigger;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.state.ReducingState;
import org.apache.flink.api.common.state.ReducingStateDescriptor;
import org.apache.flink.api.common.typeutils.base.LongSerializer;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.triggers.TriggerResult;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CustomCountTriggerWithEventTime<T> extends Trigger<T, TimeWindow> {
/**
*
*/
private static final long serialVersionUID = 6021946857731563476L;
private static final Logger LOG = LoggerFactory.getLogger(CustomCountTriggerWithEventTime.class);
private final long maxCount;
private final ReducingStateDescriptor<Long> countStateDescriptor;
public CustomCountTriggerWithEventTime(long maxCount) {
this.maxCount = maxCount;
countStateDescriptor = new ReducingStateDescriptor<>("countState", new ReduceSum(), LongSerializer.INSTANCE);
}
private TriggerResult fireAndPurge(long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
clear(window, ctx);
return TriggerResult.FIRE_AND_PURGE;
}
@Override
public TriggerResult onElement(T element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
if (window.maxTimestamp() > ctx.getCurrentWatermark()) {
ctx.registerEventTimeTimer(window.maxTimestamp());
}
ReducingState<Long> countState = ctx.getPartitionedState(countStateDescriptor);
// 新的element进来,总数需要加1
countState.add(1L);
if (countState.get() >= maxCount) {
LOG.info("Count Trigger triggered on count exceed. count {}", countState.get());
return fireAndPurge(timestamp, window, ctx);
}
return TriggerResult.CONTINUE;
}
@Override
public TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {
// 窗口结束触发
return TriggerResult.CONTINUE;
}
@Override
public TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {
LOG.info("Count Trigger triggered on time reached time {} window end {} window max {}", time, window.getEnd(), window.maxTimestamp());
if (time == window.maxTimestamp()) {
return fireAndPurge(time, window, ctx);
} else {
return TriggerResult.CONTINUE;
}
}
@Override
public void clear(TimeWindow window, TriggerContext ctx) throws Exception {
ctx.deleteEventTimeTimer(window.maxTimestamp());
ReducingState<Long> countState = ctx.getPartitionedState(countStateDescriptor);
countState.clear();
}
@Override
public boolean canMerge() {
return true;
}
@Override
public void onMerge(TimeWindow window,
OnMergeContext ctx) {
// only register a timer if the watermark is not yet past the end of the merged window
// this is in line with the logic in onElement(). If the watermark is past the end of
// the window onElement() will fire and setting a timer here would fire the window twice.
long windowMaxTimestamp = window.maxTimestamp();
if (windowMaxTimestamp > ctx.getCurrentWatermark()) {
ctx.registerEventTimeTimer(windowMaxTimestamp);
}
}
/**
* 计数方法
*/
class ReduceSum implements ReduceFunction<Long> {
@Override
public Long reduce(Long value1, Long value2) throws Exception {
return value1 + value2;
}
}
}
参考: