处理时间窗口不适用于Apache Flink中的有限数据源

时间:2018-09-23 15:07:32

标签: apache-flink flink-streaming

我试图将一个非常简单的窗口函数应用于Apache Flink中的有限数据流(本地,无群集)。这是示例:

val env = StreamExecutionEnvironment.getExecutionEnvironment
env
  .fromCollection(List("a", "b", "c", "d", "e"))

  .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(1)))
  .trigger(ProcessingTimeTrigger.create)
  .process(new ProcessAllWindowFunction[String, String, TimeWindow] {
    override def process(context: Context, elements: Iterable[String], out: Collector[String]): Unit = {
      out.collect(elements.toList.sorted.toString())
    }
  })

  .print()

env.execute()

在这里,我尝试在一秒钟内将到达窗口的所有元素分组,然后仅打印这些组。

我假设所有元素将在不到一秒钟的时间内产生并进入一个窗口,因此print()中将有一个传入元素。但是,运行此命令时,什么都不会打印

如果我删除所有窗口内容,例如

val env = StreamExecutionEnvironment.getExecutionEnvironment
env
  .fromCollection(List("a", "b", "c", "d", "e"))
  .print()

运行后我看到了打印的元素。我也尝试过使用文件源,没有区别。

计算机上的默认并行度为6。如果我尝试并行度和延迟级别,就像这样

val env = StreamExecutionEnvironment.createLocalEnvironment(2)
env
  .fromCollection(List("a", "b", "c", "d", "e"))
  .map { x => Thread.sleep(1500); x }

我能够将一些(而不是全部)元素分组,然后打印出来。

我的第一个假设是,源完成的速度比1秒要快得多,并且在窗口的计时器触发之前,任务已关闭。调试显示已达到the timer setting line in ProcessingTimeTrigger。所有启动的计时器都应该在任务关闭之前完成(至少这是我从the code得到的印象)?

能否请您帮助我理解这一点并使其更具确定性?

更新#1,23.09.2018:

我还尝试了事件时间窗口而不是处理时间窗口。如果我这样做:

val env = StreamExecutionEnvironment.getExecutionEnvironment
env
  .fromCollection(List("a", "b", "c", "d", "e"))
  .assignTimestampsAndWatermarks(new AscendingTimestampExtractor[String] {
    override def extractAscendingTimestamp(element: String): Long = {
      element.charAt(0).toInt
    }
  })

  .windowAll(TumblingEventTimeWindows.of(Time.seconds(1)))
  .trigger(EventTimeTrigger.create)
  .process(new ProcessAllWindowFunction[String, String, TimeWindow] {
    override def process(context: Context, elements: Iterable[String], out: Collector[String]): Unit = {
      out.collect(elements.toList.toString())
    }
  })

  .print()

env.execute()

然后再次不打印任何内容。调试器显示,为每个元素调用了触发器的onElement,但从未调用过onEventTime

此外,如果我修改时间戳提取器以进行更大的操作,

element.charAt(0).toInt * 1000

除了最后一个元素外,所有元素都被打印出来(每组一个元素,这是预期的)。

更新#2,23.09.2018:

更新#1在this comment中得到回答。

2 个答案:

答案 0 :(得分:3)

当有限源到达末尾时,如果您使用事件时间,则将插入带有时间戳Long.MAX_VALUE的水印,这将导致所有事件时间计时器触发。但是,随着处理时间的推移,Flink将等待所有当前触发计时器完成其操作,然后退出。

正如您所怀疑的那样,您没有看到任何输出,因为源的完成非常快。

确定性行为在事件时间处理中很简单;处理时间确实无法实现。

但这是一个或多或少起作用的黑客:

  <html>
  <title>google</title>
  <body>
  example...
  </body>
  </html>

答案 1 :(得分:0)

大卫的回答很直接! 我尝试过使用 ProcessTime 或 GlobalWindows 处理有限流的方法。所有人都面临如何正确结束这项工作的问题(源停止,操作员处理所有数据,接收器完成)。因为处理时间和计数窗口只会像大卫的回答那样不处理窗口/数据。一种方法是同步源和操作员之间的通信,然后通知退出。但这并不美丽。所以只需简单地选择 EventTime 窗口,即使在第一次开始停止源后,它也会处理所有数据。