簡體   English   中英

處理時間窗口不適用於 Apache Flink 中的有限數據源

[英]Processing time windows doesn't work on finite data sources in Apache Flink

我正在嘗試將一個非常簡單的窗口函數應用於 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 秒,並且任務在窗口的計時器觸發之前關閉。 調試顯示到達ProcessingTimeTrigger的定時器設置行 難道所有啟動的計時器不應該在任務關閉之前完成(至少這是我從代碼中得到的印象)?

你能幫我理解這一點並使之更具確定性嗎?

2018 年 9 月 23 日更新 #1:

我還試驗了事件時間窗口而不是處理時間窗口。 如果我這樣做:

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

除了最后一個之外,所有元素都被打印出來(每組一個元素,這是預期的)。

2018 年 9 月 23 日更新 #2:

此評論中回答了更新 #1。

當有限源到達末尾時,如果您使用事件時間,則將注入時間戳為 Long.MAX_VALUE 的水印,這將導致所有事件時間計時器觸發。 但是,隨着處理時間的增加,Flink 將等待所有當前正在觸發的計時器完成其操作,然后退出。

正如您所懷疑的,您沒有看到任何輸出,因為源代碼很快就完成了。

事件時間處理的確定性行為很簡單; 隨着處理時間,它並不是真正可以實現的。

但這里有一個或多或少有效的黑客:

val env = StreamExecutionEnvironment.getExecutionEnvironment

val s = env.fromCollection(List("a", "b", "c", "d", "e"))
val t = env.addSource((context: SourceContext[String]) => {
  while(true) {
    Thread.sleep(100)
    context.collect("dummy")
  }
})

s.union(t)
  .filter(_ != "dummy")
  .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(1)))
  .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()

大衛的回答很直接! 我嘗試過使用 ProcessTime 或 GlobalWindows 處理有限流的方法。 所有人都面臨如何正確結束這項工作的問題(源停止,操作員處理所有數據,接收器完成)。 因為處理時間和計數窗口只會像大衛的回答那樣不處理窗口/數據。 一種方法是同步源和操作員之間的通信,然后通知退出。 但這並不美麗。 所以只需簡單地選擇 EventTime 窗口,即使在第一次開始停止源后,它也會處理所有數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM