Apache flink APACHE FLINK AggregateFunction与tumblingWindow一起计算事件,但如果没有发生任何事件,也会发送0

Apache flink APACHE FLINK AggregateFunction与tumblingWindow一起计算事件,但如果没有发生任何事件,也会发送0,apache-flink,flink-streaming,Apache Flink,Flink Streaming,我需要在翻滚的窗口中计算事件。但如果窗口中没有事件,我还希望发送值为0的事件 差不多 窗口数:5 窗口计数:0 窗口计数:0 窗口数:3 窗口计数:0 import com.google.protobuf.Message; 导入org.apache.flink.api.common.functions.AggregateFunction; 导入org.skydivin4ng3l.cepmodemon.models.events.aggregate.aggregateOutterClass; 公

我需要在翻滚的窗口中计算事件。但如果窗口中没有事件,我还希望发送值为0的事件

差不多

  • 窗口数:5
  • 窗口计数:0
  • 窗口计数:0
  • 窗口数:3
  • 窗口计数:0
  • import com.google.protobuf.Message;
    导入org.apache.flink.api.common.functions.AggregateFunction;
    导入org.skydivin4ng3l.cepmodemon.models.events.aggregate.aggregateOutterClass;
    公共类BasicCounter实现AggregateFunction{
    @凌驾
    公共长事务累加器(){
    返回0升;
    }
    @凌驾
    公共长添加(T事件,长累加器){
    回油蓄能器+1L;
    }
    @凌驾
    公共AggregateOutterClass.Aggregate getResult(长累加器){
    返回AggregateOutterClass.Aggregate.newBuilder().setVolume(累加器).build();
    }
    @凌驾
    公共长合并(长累加器1、长累加器2){
    回流蓄能器1+蓄能器2;
    }
    }
    
    在这里使用

    DataStream<AggregateOuterClass.Aggregate> aggregatedStream = someEntryStream
    .windowAll(TumblingEventTimeWindows.of(Time.seconds(5)))
    .aggregate(new BasicCounter<MonitorOuterClass.Monitor>());
    
    datastreamaggregatedstream=someEntryStream
    .windowAll(TumblingEventTimeWindows.of(时间秒(5)))
    .合计(新基本会计科目());
    
    时间特征是摄入时间

    我读过一篇关于Tigger函数的文章,该函数可以检测聚合流是否在x时间之后接收到事件,但我不确定这样做是否正确

    即使窗口中根本没有事件,我也希望聚合会发生。也许有一个我不知道的环境


    谢谢你的任何提示

    Flink的窗口是在第一个事件分配给窗口时延迟创建的。因此,空窗口不存在,并且不能产生结果

    通常有三种方法可以解决此问题:

  • 在向流中添加事件的窗口前面放置一些内容,确保每个窗口中都包含一些内容,然后修改窗口处理以在计算结果时忽略这些特殊事件
  • 将全局窗口与使用处理时间计时器触发窗口的自定义触发器一起使用(如果没有事件流动,水印将不会前进,并且在更多事件到达之前事件时间计时器将不会触发)
  • 不要使用窗口API,而是使用
    ProcessFunction
    实现自己的窗口。但在这里,您仍将面临需要使用处理时间计时器的问题
  • 更新:

    现在,我已经努力实现了选项2的一个示例,我不能推荐它。问题是,即使使用自定义的
    触发器
    ,如果窗口为空,也不会调用
    ProcessAllWindowFunction
    ,因此必须始终在
    全局窗口
    中至少保留一个元素。这似乎需要实现一个相当粗糙的
    逐出器
    ProcessAllWindowFunction
    ,它们协作来保留和忽略窗口中的一个特殊元素——而且您还必须首先以某种方式将该元素放入窗口中


    如果你打算做一些骇客的事情,那么选项1似乎要简单得多。

    我按照@David Anderson的建议选择了选项1:

    这是我的事件生成器:

    public class EmptyEventSource implements SourceFunction<MonitorOuterClass.Monitor> {
    
        private volatile boolean isRunning = true;
    
        private final long delayPerRecordMillis;
    
        public EmptyEventSource(long delayPerRecordMillis){
            this.delayPerRecordMillis = delayPerRecordMillis;
        }
    
        @Override
        public void run(SourceContext<MonitorOuterClass.Monitor> sourceContext) throws Exception {
            while (isRunning) {
                sourceContext.collect(MonitorOuterClass.Monitor.newBuilder().build());
    
                if (delayPerRecordMillis > 0) {
                    Thread.sleep(delayPerRecordMillis);
                }
            }
        }
    
        @Override
        public void cancel() {
            isRunning = false;
        }
    }
    
    公共类EmptyEventSource实现SourceFunction{
    private volatile boolean isRunning=true;
    私人最终长延迟PerrecordMillis;
    公共EmptyEventSource(长延迟PerRecordMillis){
    this.delayPerRecordMillis=delayPerRecordMillis;
    }
    @凌驾
    公共void运行(SourceContext SourceContext)引发异常{
    同时(正在运行){
    collect(MonitorOuterClass.Monitor.newBuilder().build());
    如果(delayPerRecordMillis>0){
    睡眠(delayPerRecordMillis);
    }
    }
    }
    @凌驾
    公开作废取消(){
    isRunning=false;
    }
    }
    
    以及我的调整聚合功能:

    public class BasicCounter<T extends Message> implements AggregateFunction<T, Long, AggregateOuterClass.Aggregate> {
        @Override
        public Long createAccumulator() {
            return 0L;
        }
    
        @Override
        public Long add(T event, Long accumulator) {
            if(((MonitorOuterClass.Monitor)event).equals(MonitorOuterClass.Monitor.newBuilder().build())) {
                return accumulator;
            }
    
            return accumulator + 1L;
        }
    
        @Override
        public AggregateOuterClass.Aggregate getResult(Long accumulator) {
            AggregateOuterClass.Aggregate newAggregate = AggregateOuterClass.Aggregate.newBuilder().setVolume(accumulator).build();
            return newAggregate;
        }
    
        @Override
        public Long merge(Long accumulator1, Long accumulator2) {
            return accumulator1 + accumulator2;
        }
    }
    
    public类BasicCounter实现AggregateFunction{
    @凌驾
    公共长事务累加器(){
    返回0升;
    }
    @凌驾
    公共长添加(T事件,长累加器){
    if(((MonitorOuterClass.Monitor)事件)。等于(MonitorOuterClass.Monitor.newBuilder().build()){
    回流蓄能器;
    }
    回油蓄能器+1L;
    }
    @凌驾
    公共AggregateOutterClass.Aggregate getResult(长累加器){
    AggregateOuterClass.Aggregate newAggregate=AggregateOuterClass.Aggregate.newBuilder().setVolume(累加器).build();
    返回新集合;
    }
    @凌驾
    公共长合并(长累加器1、长累加器2){
    回流蓄能器1+蓄能器2;
    }
    }
    
    他们是这样使用的:

    DataStream<MonitorOuterClass.Monitor> someEntryStream = env.addSource(currentConsumer);
    DataStream<MonitorOuterClass.Monitor> triggerStream = env.addSource(new EmptyEventSource(delayPerRecordMillis));
    DataStream<AggregateOuterClass.Aggregate> aggregatedStream = someEntryStream
                            .union(triggerStream)
                            .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                            .aggregate(new BasicCounter<MonitorOuterClass.Monitor>());
    
    DataStream someEntryStream=env.addSource(currentConsumer);
    DataStream triggerStream=env.addSource(新的EmptyEventSource(delayPerRecordMillis));
    DataStream aggregatedStream=someEntryStream
    .union(triggerStream)
    .windowAll(TumblingProcessingTimeWindows.of(时间秒(5)))
    .合计(新基本会计科目());
    
    选择选项2。我不明白如何正确设置触发器
    DataStream aggregatedStream=someEntryStream.windowAll(GlobalWindows.create()/*TumblingEventTimeWindows.of(Time.seconds(5))*/).trigger(new PurgingTrigger(ProcessingTimeTrigger.create()).aggregate(new BasicCounter())我有点困惑如何使用这个,你能提供一个例子吗?我花了大量时间试图写一个我可以分享的好例子,但我放弃了。请看我的更新答案。我现在正在做选项1=),因为我也放弃了选项2。它可能正在工作,但现在我有一个Protobuf问题,0不能是一个值,而对象是空的。但至少它起作用了=)
    
    DataStream<MonitorOuterClass.Monitor> someEntryStream = env.addSource(currentConsumer);
    DataStream<MonitorOuterClass.Monitor> triggerStream = env.addSource(new EmptyEventSource(delayPerRecordMillis));
    DataStream<AggregateOuterClass.Aggregate> aggregatedStream = someEntryStream
                            .union(triggerStream)
                            .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                            .aggregate(new BasicCounter<MonitorOuterClass.Monitor>());