Flink滑动计数窗口行为

时间:2018-08-25 06:11:14

标签: apache-flink flink-streaming

假设我们有这样的数据结构:

Tuple2<ArryaList<Long>, Integer>

第一个字段是一个长度为ArrayList的包含时间戳记,而Integer字段是一个介于1到40之间的数字,名为channel。目标是使用相同的密钥(channel)汇总每400条消息,并在其上应用ReduceFunction(它只是在元组的第一个字段中合并400条消息的时间戳)。  我将channel字段设置为消息的键,并创建一个400的计数窗口。例如,如果我们有 160000 消息作为输入,则它应该输出160000/400 = 400行然后“计数”窗口将按需工作。问题是当我使用“滑动计数”窗口时,我的预期行为是:

Flink为每个channel号创建逻辑窗口,并首次应用ReduceFunction ,如果逻辑窗口的长度达到400,则每100个输入数据与逻辑窗口的密钥相同的密钥,也会在窗口中的最后400条消息中调用ReduceFunction,所以我们应该:

  • 160000 - 400 = 159600 // 前400个输入将首次调用reduce函数
  • 159600 / 100 = 1596 // 在前400个输入之后,对于每100个输入Flink调用最后400个输入的reduce函数
  • 1 + 1596 = 1597 //输出的行数

但是在运行“滑动计数”窗口时,它将输出1600行,行的长度可变。 (我预计输出的长度只有400)

要点: length 我的意思是ArrayList的大小(Tuple2的第一个字段)

  • 前40个频道-> 100个长度
  • 第二个40个频道->长度为299
  • 第三个40个频道->长度为598
  • 第40个频道-> 997长度
  • 剩余的40个频道->长度为400

我如何证明这种行为并实现所需的“滑动计数”窗口?

这是源代码:

DataStream<Tuple2<ArrayList<Long>, Integer>> data ;
data.keyBy(1).countWindow(400, 100)
                 .reduce(new ReduceFunction<Tuple2<ArrayList<Long>, Integer>>() {
             @Override
             public Tuple2<ArrayList<Long>, Integer> reduce(Tuple2<ArrayList<Long>, Integer> t0, Tuple2<ArrayList<Long>, Integer> t1) throws Exception {
                 t0.f0.add(t1.f0.get(0));
                 return t0;
             }
         }).writeAsText("results400").setParallelism(1);

更新:根据@DavidAnderson的建议,我还尝试在ReduceFunstion中创建一个新的元组,而不是修改t0,但结果是相同的。 / p>

public Tuple2<ArrayList<Long>, Integer> reduce(Tuple2<ArrayList<Long>, Integer> t0, Tuple2<ArrayList<Long>, Integer> t1) throws Exception {
                         ArrayList<Long> times = t0.f0;

                         times.addAll(t1.f0);

                         return new Tuple2<>(times, t0.f1) ;
                     }

2 个答案:

答案 0 :(得分:1)

感谢 David Anderson 的建议,将ReduceFunction修改为以下内容可以解决此问题。我们应该在ReduceFunction中创建一个新对象:

public Tuple2<ArrayList<Long>, Integer> reduce(Tuple2<ArrayList<Long>, Integer> t0, Tuple2<ArrayList<Long>, Integer> t1) throws Exception {
                         ArrayList<Long> times = new ArrayList<>();

                         times.addAll(t0.f0);
                         times.addAll(t1.f0);


                         return new Tuple2<>(times, t0.f1) ;
                     }

请注意,问题中的两种减少方法都会导致输出错误。 现在输出如下:

  • 前40个频道-> 100个长度
  • 第二个40个频道-> 200个长度
  • 第三个40频道-> 300的长度
  • 每40个通道遗骸-> 400个长度

因此Flink滑动计数窗口的行为是它在每个滑动计数输入消息中调用ReduceFunction。因此,如果我们有160000条输入消息,则结果编号应为: 160000/100 = 1600

答案 1 :(得分:1)

这是countWindow的实现

public WindowedStream<T, KEY, GlobalWindow> countWindow(long size, long slide) {
    return window(GlobalWindows.create())
            .evictor(CountEvictor.of(size))
            .trigger(CountTrigger.of(slide));
}

的行为与您预期的不太一样。该窗口每100个元素(幻灯片)触发一次,无论它是否包含400个元素(大小)。大小控制着最多保留多少个元素。