Flink:如何仅在第一个元素上在CustomTrigger中启动处理时间计时器?

时间:2019-01-29 12:44:40

标签: java apache-flink flink-streaming

我正在为自己的应用程序使用具有自定义Trigger的GlobalWindow。根据要求,在“触发”功能中,我只需要在窗口的第一个元素上启动一个处理时间计时器。

我尝试使用变量firstEventflag实现它。像这样。

.window(GlobalWindows.create())
.trigger(new Trigger<ImpactEventObject, GlobalWindow>() {
    Boolean firstEventflag = false;

    @Override
    public TriggerResult onElement(ImpactEventObject impactEventObject, long l, GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
        if (!firstEventflag) {
            firstEventflag = true;
            triggerContext.registerProcessingTimeTimer(
                triggerContext.getCurrentProcessingTime() + 20000);
        }
        return TriggerResult.CONTINUE;
    }

    @Override
    public TriggerResult onProcessingTime(long l, GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
    return TriggerResult.FIRE;
}

但这失败了,因为今天我发现变量firstEventflag并非在每次创建新窗口时都初始化,它取决于正在处理该窗口的子任务,这意味着不同的窗口可以共享相同的变量{{ 1}}有效地使这种逻辑无用。有了这个,我该如何解决我的问题?

1 个答案:

答案 0 :(得分:1)

通过查看CountTrigger here的源代码来找出实现此目的的方法。

我们可以用GlobalWindow来保存ReducingStateDescriptor中元素的数量。并在此计数为1时启动计时器,这意味着-仅在第一个元素上启动计时器。

public class CustomTrigger extends Trigger<GenericObject, GlobalWindow> {

private final ReducingStateDescriptor<Long> stateDesc = new ReducingStateDescriptor<>("count", new Sum(), LongSerializer.INSTANCE);

@Override
public TriggerResult onElement(ImpactEventObject impactEventObject, long l, GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
    ReducingState<Long> count = triggerContext.getPartitionedState(stateDesc);
    count.add(1L);

    if (count.get() == 1) {
        triggerContext.registerProcessingTimeTimer(
            triggerContext.getCurrentProcessingTime() + 20000);
    }
    return TriggerResult.CONTINUE;
}

@Override
public TriggerResult onProcessingTime(long l, GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
    return TriggerResult.FIRE;
}

@Override
public TriggerResult onEventTime(long l, GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
    return null;
}

@Override
public void clear(GlobalWindow globalWindow, TriggerContext triggerContext) throws Exception {
    triggerContext.deleteProcessingTimeTimer(triggerContext.getCurrentProcessingTime());
}

private static class Sum implements ReduceFunction<Long> {
    private static final long serialVersionUID = 1L;
    @Override
    public Long reduce(Long value1, Long value2) throws Exception {
        return value1 + value2;
    }

}
}