简体   繁体   English

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

[英]Using Flink window and fold function, element missing?

When I try to aggregate elements using window and fold function, some of the elements are missed from getting aggregated.当我尝试使用 window 和 fold 函数聚合元素时,某些元素在聚合时丢失了。 Consuming elements from Kafka (value:0, value:1, value:2, value:3) and aggregating them as odd and even values.使用来自 Kafka 的元素(value:0, value:1, value:2, value:3)并将它们聚合为奇数和偶数值。

Output is:输出是:

{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]}

Numbers between 10-13 is missing and this happens for a random set of numbers. 10-13 之间的数字缺失,这发生在一组随机数字上。 Can someone suggest what is missed from the code below and how can I be sure to process all elements?有人可以建议下面的代码遗漏了什么,我如何确保处理所有元素?

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

    }
}

So I started writing the first part of this before noticing your custom triggers make the fact that you are using a TumblingEventTime window sort of irrelevant, but I want to include my original thoughts anyway since I am not fully sure why you would use an EventTime window when you aren't using it.因此,在注意到您的自定义触发器使您使用 TumblingEventTime 窗口这一事实无关紧要之前,我开始编写本文的第一部分,但无论如何我想包括我的原始想法,因为我不完全确定您为什么要使用 EventTime 窗口当你不使用它时。 My response after realizing this is below the original.意识到这一点后,我的回应低于原稿。

Are you running this on a single parallelism or multiple?您是在单个并行还是多个并行上运行它? The reason why I ask is because if it is multiple parallelism (and the kafka topic is also comprised of multiple partitions), then it is possible that messages are being received and processed in a non sequential order.我问的原因是因为如果是多并行(而且kafka主题也由多个分区组成),那么消息接收和处理的顺序可能是非顺序的。 This could lead to messages with a timestamp that causes the watermark to advance, causing the window to process the messages.这可能会导致带有时间戳的消息导致水印提前,从而导致窗口处理消息。 Then the next message(s) has an event time that is before the current watermark time (aka being "late") and that will cause the message to be dropped.然后下一条消息的事件时间在当前水印时间之前(也就是“迟到”),这将导致消息被丢弃。

So for example: if you have 20 elements and the event time of each is like such:例如:如果您有 20 个元素,并且每个元素的事件时间如下:

message1: eventTime: 1000 message1: eventTime: 2000 etc...消息1:事件时间:1000 消息1:事件时间:2000 等等...

And your event-time window is 5001ms.你的事件时间窗口是 5001 毫秒。

Now messages message1 through message9 come through in order.现在消息 message1 到 message9 依次通过。 This first window will be processed and contain messages 1-5 (message6 will have caused the window to be processed).第一个窗口将被处理并包含消息 1-5(消息 6 将导致窗口被处理)。 Now if message11 comes in before message10, it will cause the window to be processed containing messages 6-9.现在,如果 message11 在 message10 之前进入,它将导致处理包含消息 6-9 的窗口。 And when message10 comes next, the watermark has already advanced past message10's event time, causing it to be dropped as a "late event".当 message10 出现时,水印已经超过 message10 的事件时间,导致它作为“延迟事件”被丢弃。

Proper Answer正确答案

Instead of using an eventTime window and a custom trigger, try using a countWindow.不要使用 eventTime 窗口和自定义触发器,而是尝试使用 countWindow。

So replace this:所以替换这个:

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

With this:有了这个:

.countWindow(5L)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM