Java 使用Flink窗口和折叠功能,元素丢失?

Java 使用Flink窗口和折叠功能,元素丢失?,java,apache-flink,flink-streaming,flink-cep,flinkml,Java,Apache Flink,Flink Streaming,Flink Cep,Flinkml,当我尝试使用window和fold函数聚合元素时,有些 在进行聚合时,缺少元素的个数。消费要素 来自卡夫卡(值:0,值:1,值:2,值:3)并聚合它们 作为奇数和偶数值 输出为: {even=[0, 2, 4], odd=[1, 3]} {even=[6, 8], odd=[5, 7, 9]} {even=[14, 16, 18], odd=[15, 17]} {even=[20, 22], odd=[19, 21, 23]} {even=[24, 26, 28], odd=[25, 27]}

当我尝试使用window和fold函数聚合元素时,有些 在进行聚合时,缺少元素的个数。消费要素 来自卡夫卡
(值:0,值:1,值:2,值:3)
并聚合它们 作为奇数和偶数值

输出为:

{even=[0, 2, 4], odd=[1, 3]}
{even=[6, 8], odd=[5, 7, 9]}
{even=[14, 16, 18], odd=[15, 17]}
{even=[20, 22], odd=[19, 21, 23]}
{even=[24, 26, 28], odd=[25, 27]}
10-13之间的数字缺失,这发生在一组随机的 数字。有人能建议下面的代码中遗漏了什么吗 如何确保处理所有元素

public static class Splitter implements FlatMapFunction<String, 
    Tuple3<String, String, List<String>>{
    private static final long serialVersionUID = 1L;

    @Override
    public void flatMap(String value, Collector<Tuple3<String, String, 
        List<String>>out) throws Exception {
        String[] vals = value.split(":");

        if(vals.length 1 && Integer.parseInt(vals[1]) % 2 == 0){
            out.collect(new Tuple3<String, String, List<String>>
             ("test","even", Arrays.asList(vals[1])));
        }else{
            out.collect(new Tuple3<String, String, List<String>>
            ("test","odd", Arrays.asList(vals[1])));
        }
    }
}


    DataStream<Map<String, List<String>>streamValue = 
    kafkaStream.flatMap(new Splitter()).keyBy(0)
    .window(TumblingEventTimeWindows.of(Time.milliseconds(3000))).
    trigger(CustomizedCountTrigger.of(5L))//.trigger(CountTrigger.of(2))
    .fold(new HashMap<String, List<String>>(), new 
    FoldFunction<Tuple3<String, String, List<String>>, Map<String, 
    List<String>>>() {
        private static final long serialVersionUID = 1L;

        @Override
        public Map<String, List<String>fold(Map<String, 
        List<String>accumulator,
        Tuple3<String, String, List<String>value) throws 
        Exception {
            if(accumulator.get(value.f1) != null){
                List<Stringlist = new ArrayList<>();
                list.addAll(accumulator.get(value.f1));
                list.addAll(value.f2);
                accumulator.put(value.f1, list);
            }else{
                accumulator.put(value.f1, value.f2);
            }
            return accumulator;
        }
    });

    streamValue.print();
    env.execute("window test");
}


public class CustomizedCountTrigger<W extends Windowextends 
Trigger<Object, W{

    private static final long serialVersionUID = 1L;
    private final long maxCount;

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

    private CustomizedCountTrigger(long maxCount) {
        this.maxCount = maxCount;
    }

    @Override
    public TriggerResult onElement(Object element, long timestamp, W window,
    TriggerContext ctx) throws Exception {
        ReducingState<Longcount = ctx.getPartitionedState(stateDesc);
        count.add(1L);
        if (count.get() >= maxCount) {
            count.clear();
            return TriggerResult.FIRE_AND_PURGE;
        }
        return TriggerResult.CONTINUE;
    }

    @Override
    public TriggerResult onProcessingTime(long time, W window,

    org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext

    ctx) throws Exception {
        return TriggerResult.CONTINUE;
    }

    @Override
    public TriggerResult onEventTime(long time, W window,

    org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext

    ctx) throws Exception {
        return TriggerResult.CONTINUE;
    }

    @Override
    public void clear(W window, 
    org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext

    ctx)
    throws Exception {
        ctx.getPartitionedState(stateDesc).clear();
    }

    @Override
    public String toString() {
        return "CountTrigger(" +  maxCount + ")";
    }

    public static <W extends WindowCustomizedCountTrigger<Wof(long 
    maxCount) {
        return new CustomizedCountTrigger<>(maxCount);
    }

    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;
        }

    }
}
公共静态类拆分器实现FlatMapFunction,因此我开始编写本文的第一部分,之前我注意到您的自定义触发器使您使用的TumblingEventTime窗口有点不相关,但我还是想包括我的原始想法,因为我不能完全确定为什么在不使用EventTime窗口的情况下使用它。意识到这一点后,我的反应低于原来的水平

您是在单并行还是多并行上运行此操作?我之所以问这个问题,是因为如果它是多重并行的(而且卡夫卡主题也由多个分区组成),那么消息的接收和处理可能是以非顺序的顺序进行的。这可能导致带有时间戳的消息导致水印前进,从而导致窗口处理消息。然后,下一条消息的事件时间早于当前水印时间(也称为“延迟”),这将导致消息被丢弃

例如:如果有20个元素,每个元素的事件时间如下:

message1:eventTime:1000 信息1:eventTime:2000 等等

您的活动时间窗口为5001ms

现在消息message1到message9按顺序发送。将处理第一个窗口并包含消息1-5(消息6将导致处理该窗口)。现在,如果message11在message10之前出现,它将导致处理包含消息6-9的窗口。当message10下一个出现时,水印已经超过了message10的事件时间,导致它作为“延迟事件”被删除

正确答案

尝试使用countWindow,而不是使用eventTime窗口和自定义触发器

因此,请将其替换为:

.window(TumblingEventTimeWindows.of(Time.milliseconds(3000))).
trigger(CustomizedCountTrigger.of(5L))//.trigger(CountTrigger.of(2))
为此:

.countWindow(5L)

非常感谢您的时间和解释。我同意使用eventTimeWindow并导致邮件被丢弃。但我的用例如下所示。在此之前,我想澄清一下,我尝试使用并行(1)和并行(2),但问题仍然是一样的,有些事件被丢弃了。我的用例是在一个业务逻辑被评估为true时处理一组事件。e、 例如,如果事件总数大于3,或偶数事件总数大于5,或预定义的时间窗口交叉(例如,2秒)。另外,我理解如果你用我们自己的一个来覆盖窗口触发器,那么实际的触发器将不再被考虑。在这种情况下,窗口的时间流逝。环境设置流时间特征(时间特征、摄取时间);环境(一)@我很欣赏你的观点。包括一个自定义触发器会覆盖默认触发器。但是触发自定义触发器的内容仍然处于活动状态。因此,当3000ms的TumblingEventTime窗口完成时,它将触发自定义触发器中的自定义OneEventTime方法。但是您将onEventTime方法设置为仅继续,而不触发和/或清除(而默认触发器将返回fire_和_purge),从我所知,这使得事件时间窗口基本上毫无意义。此外,我看不到您在计算事件的事件时间,所以我猜您的意思是使用处理时间来代替?但是,即使您是,也会被告知在您拥有的自定义触发器中继续,因此不会发生任何事情。但是如果您确实想使用eventTime,那么在自定义触发器返回TriggerResult.FIRE\u和\u PURGE中使用onEventTime方法。如果要使用处理时间,请在自定义触发器return TriggerResult.FIRE\u和\u PURGE中使用onProcessingTime方法,并将TumblingEventTimeWindows.of()更改为TumblingProcessingTimeWindows.of(),非常感谢@Jicaar。这有助于更好地理解它。