簡體   English   中英

DataFlow (Apache Beam) 中發布/訂閱的自定義時間戳和窗口

[英]Custom timestamp and windowing for Pub/Sub in DataFlow (Apache Beam)

我想在 Apache Beam 中使用流式管道實現以下場景(並在 Google DataFlow 上運行它):

  1. 從 Pub/Sub 讀取消息(JSON 字符串)
  2. 反序列化 JSON
  3. 使用自定義字段(比如timeStamp )作為處理元素的時間戳值
  4. 應用60 seconds固定窗口
  5. 從元素中提取鍵並按鍵分組
  6. << 進行進一步處理 >>

我嘗試使用 Java(Scala) 和 Python 解決這個問題,但沒有一個解決方案有效。

  1. Python解決方案
# p is beam.Pipeline()
_ = (p | beam.io.ReadFromPubSub(subscription="my_sub")
        | beam.Map(add_timestamping)
        | beam.WindowInto(window.FixedWindows(60))
        | beam.Map(lambda elem: elem) # exracting the key somehow, not relevant here
        | beam.GroupByKey()
        # (...)
        | beam.io.WriteToPubSub("output_topic")
        )
p.run()

add_timestamping函數根據文檔

def add_timestamping(elem):
    import json
    import apache_beam as beam
    msg = json.loads(elem)
    unix_timestamp = msg['timeStamp'] / 1000
    return beam.window.TimestampedValue(msg, unix_timestamp)

Python 解決方案的輸出

  1. 使用DirectRunner ,會發出窗口,並且窗口本身或多或少是合適的,具體取決於延遲。
  2. 使用DataFlowRunner所有消息都會被跳過,計數器出現在 DataFlow UI 中: droppedDueToLateness

  1. Java / Scala 解決方案(我使用過Scio,但這也發生在 Java 中的 Clean Beam SDK 中)
sc.pubsubSubscription[String]("my_sub")
    .applyTransform(ParDo.of(new CustomTs()))
    .withFixedWindows(Duration.standardSeconds(60))
    .map(x => x) // exracting the key somehow, not relevant here
    .groupByKey
    // (...)
    .saveAsPubsub("output_topic")

根據文檔添加自定義時間戳:

import io.circe.parser._
class CustomTs extends DoFn[String, String] {
  @ProcessElement
  def processElement(@Element element: String, out: DoFn.OutputReceiver[String]): Unit = {
    val json = parse(element).right.get
    val timestampMillis: Long = json.hcursor.downField("timeStamp").as[Long].getOrElse(0)
    out.outputWithTimestamp(element, new Instant(timestampMillis))
  }
}

Java / Scala 解決方案的輸出

Exception in thread "main" org.apache.beam.sdk.Pipeline$PipelineExecutionException: 
java.lang.IllegalArgumentException:
 Cannot output with timestamp 2019-03-02T00:51:39.124Z. 
 Output timestamps must be no earlier than the timestamp of the current input
 (2019-03-28T14:57:53.195Z) minus the allowed skew (0 milliseconds).

我不能在這里使用DoFn.getAllowedTimestampSkew ,因為它已被棄用,我不知道將發送哪些范圍的歷史數據。


具有處理歷史數據的能力對我的項目至關重要(這些數據將從某個商店發送到 Pub/Sub)。 管道必須同時處理當前數據和歷史數據。

我的問題是:如何使用自定義時間戳處理數據並能夠在使用 Beam API 定義的窗口上進行操作?

如果您能夠將插入點的時間戳提取到 PubSub,您將能夠使用用戶指定的時間戳作為元數據。 有關如何操作的信息記錄在 1.9 SDK 下。

https://cloud.google.com/dataflow/model/pubsub-io#timestamps-and-record-ids

“您可以使用用戶指定的時間戳來精確控制從 Cloud Pub/Sub 讀取的元素如何分配給 Dataflow 管道中的窗口。”

由於 1.9 已棄用,因此在 2.11 中您將需要https://beam.apache.org/releases/javadoc/2.11.0/org/apache/beam/sdk/io/gcp/pubsub/PubsubIO.Read.html#withTimestampAttribute- java.lang.String-

暫無
暫無

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

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