簡體   English   中英

如何在與 Spark 相同的查詢結果中使用聚合和連接?

[英]How can I use aggregate with join in the same query result with Spark?

我需要加入以使用 postgres 數據豐富我的 dataframe。 在 Spark Streaming 中我可以正常執行,因為數據是批量處理的。 但是,在結構化流中,每當我嘗試將聚合與連接一起使用時,都會出現錯誤。

例如:如果我使用聚合與 output 模式完成,作業正常工作,但是,如果我添加連接,它會返回錯誤:

Join between two streaming DataFrames/Datasets is not supported in Complete output mode, only in Append output mode;

如果我反其道而行之,也會發生同樣的情況。 當我將連接與 output 模式 append 一起使用時,作業運行正常,但是,如果我添加聚合,作業將返回錯誤:

Append output mode not supported when there are streaming aggregations on streaming DataFrames/DataSets without watermark;

最后,我想知道是否有任何方法可以將連接和聚合一起使用而不會使用火花結構化流式傳輸出現錯誤。

如果是這樣,一個不會產生那種錯誤的實現是什么樣的?

def main(args: Array[String]): Unit = {
  val ss: SparkSession = Spark.getSparkSession
  val postgresSQL = new PostgresConnection
  val dataCollector = new DataCollector(postgresSQL)
  val collector = new Collector(ss,dataCollector)
  
  import ss.implicits._
  
  val stream: DataFrame = Kafka.setStructuredStream(ss)

  val parsed: DataFrame = Stream.parseInputMessages(stream)

  val getRelation: DataFrame = collector.getLastRelation(parsed)

    getRelation
    .writeStream.format("console")
    .trigger(Trigger.ProcessingTime(5000))
      .outputMode("complete")
      .queryName("Join")
      .start()

  ss.streams.awaitAnyTermination()
}

在我的 getLastRelation 方法中,我調用了 convertData 方法和 compareData 方法。

    def getLastRelation(messageToProcess: DataFrame): DataFrame = {
    // Faz tratamentos no DF para preparar a busca
    val dss: Dataset[Message] = this.convertData(messageToProcess)
    val dsRelacaolista: Dataset[WithStructure] = this.getPersonStructure(ds)
    val compareData = this.compareData(dsRelacaolista,messageToProcess)
    compareData
}

在我的 convertData 方法中,我使用了一個 agg。

    def convertData(data: DataFrame): Dataset[Message] = {
    data.selectExpr("country","code","order")
      .groupBy($"country",$"order")
      .agg(collect_list("code")
        .as("code"))
      .as[Message]
  }

在我的 compareData 方法中,我使用了 join:

def compareData(data: Dataset[WithStructure], message: DataFrame): DataFrame = {
    val tableJoin = message.selectExpr("order","order_id","hashCompare","created_at")

    data.toDF()
      .withColumn("hashCompare",hash($"country",$"code"))
      .join(tableJoin,"hashCompare")
  }

注意:我使用 scala 作為語言(我不知道此信息對這個問題是否重要)

如果您在 stream 上進行聚合查詢,則需要指定水印和 window。

例如:

 data
     .withWatermark("created_at", "10 minutes")
     .selectExpr("country","code","order")
     .groupBy(window($"created_at", "10 minutes", "5 minutes"), $"country",$"order")
     .agg(collect_list("code")
     .as("code"))
     .as[Message]

與您的流一起到達的數據可能出於任何原因延遲(由於網絡速度變慢等)。 水印允許指定聚合應等待滯后事件多長時間。 所有延遲高於水印中指定時間的事件都將被忽略。

Append 模式不允許修改之前輸出的結果。 因此,它需要水印來確保聚合數據不會進一步更新。

您可以選擇更長的 window 進行水印處理,它將為您處理延遲數據提供更高的容忍度。 缺點是上游將被水印持續時間延遲,因為查詢必須等待水印中指定的時間通過才能完成聚合。

此外,對於流-流連接(當連接的兩邊都是流數據集時),您還需要指定 window。

來自文檔:

在兩個數據流之間生成連接結果的挑戰在於,在任何時間點,連接兩側的數據集視圖都是不完整的,這使得在輸入之間找到匹配變得更加困難。

請查看有關進行流式連接進行流式聚合的文檔。

看來你不能:(

來自結構化流編程指南(強調我的):

有關支持的聯接的其他詳細信息:

  • 連接可以級聯,也就是可以做df1.join(df2, ...).join(df3, ...).join(df4, ....)。

  • 從 Spark 2.4 開始,您只能在查詢處於 Append output 模式時使用連接。 尚不支持其他 output 模式。

  • 從 Spark 2.4 開始,您不能在連接之前使用其他非地圖類操作。 以下是一些不能使用的示例。

    • 在加入之前不能使用流式聚合。
    • 加入前不能在更新模式下使用 mapGroupsWithState 和 flatMapGroupsWithState。

建議:另一種方法可能是在單獨的 stream 中進行聚合並將其保存到接收器。 然后在新的 stream 中閱讀,加入您想要的內容。

暫無
暫無

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

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