我试图将一个非常简单的窗口函数应用于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中得到回答。
答案 0 :(得分:3)
当有限源到达末尾时,如果您使用事件时间,则将插入带有时间戳Long.MAX_VALUE的水印,这将导致所有事件时间计时器触发。但是,随着处理时间的推移,Flink将等待所有当前触发计时器完成其操作,然后退出。
正如您所怀疑的那样,您没有看到任何输出,因为源的完成非常快。
确定性行为在事件时间处理中很简单;处理时间确实无法实现。
但这是一个或多或少起作用的黑客:
<html>
<title>google</title>
<body>
example...
</body>
</html>
答案 1 :(得分:0)
大卫的回答很直接! 我尝试过使用 ProcessTime 或 GlobalWindows 处理有限流的方法。所有人都面临如何正确结束这项工作的问题(源停止,操作员处理所有数据,接收器完成)。因为处理时间和计数窗口只会像大卫的回答那样不处理窗口/数据。一种方法是同步源和操作员之间的通信,然后通知退出。但这并不美丽。所以只需简单地选择 EventTime 窗口,即使在第一次开始停止源后,它也会处理所有数据。