簡體   English   中英

從 Kafka 主題讀取數據並使用 scala 和 spark 寫回 Kafka 主題

[英]Read from Kafka topic process the data and write back to Kafka topic using scala and spark

嗨,我正在閱讀 kafka 主題,我想處理從 kafka 接收到的數據,例如標記化、過濾掉不必要的數據、刪除停用詞,最后我想寫回另一個 Kafka 主題

// read from kafka
val readStream = existingSparkSession
      .readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", hostAddress)
      .option("subscribe", "my.raw") // Always read from offset 0, for dev/testing purpose
      .load()

val df = readStream.selectExpr("CAST(value AS STRING)" )
df.show(false)
val df_json = df.select(from_json(col("value"), mySchema.defineSchema()).alias("parsed_value"))
val df_text = df_json.withColumn("text", col("parsed_value.payload.Text"))

// perform some data processing actions such as tokenization etc and return cleanedDataframe as the final result

// write back to kafka
val writeStream = cleanedDataframe
      .writeStream
      .outputMode("append")
      .format("kafka")
      .option("kafka.bootstrap.servers", hostAddress)
      .option("topic", "writing.val")
      .start()
    writeStream.awaitTermination()

然后我收到以下錯誤

線程“主”org.apache.spark.sql.AnalysisException 中的異常:必須使用 writeStream.start() 執行帶有流源的查詢;;

然后我編輯了我的代碼如下從kafka讀取並寫入控制台

// read from kafka
val readStream = existingSparkSession
      .readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", hostAddress)
      .option("subscribe", "my.raw") // Always read from offset 0, for dev/testing purpose
      .load()

// write to console
val df = readStream.selectExpr("CAST(value AS STRING)" )
val query = df.writeStream
      .outputMode("append")
      .format("console")
      .start().awaitTermination();

// then perform the data processing part as mentioned in the first half

使用第二種方法,在控制台中連續顯示數據,但它從未運行過數據處理部分。 我能否知道如何從 kafka 主題中讀取數據,然后對接收到的數據執行一些操作(標記化、刪除停用詞)並最終寫回新的 kafka 主題?

編輯

堆棧跟蹤在錯誤期間指向上述代碼中的 df.show(false)

您當前的實現中存在兩個常見問題:

  1. 在流媒體環境中應用show
  2. awaitTermination之后的代碼不會被執行

到 1。

該方法show是對 dataframe 的操作(與轉換相反)。 當您處理流式數據幀時,這將導致錯誤,因為流式查詢需要從start (正如 Excpetion 文本告訴您的那樣)。

到 2。

awaitTermination方法是一個阻塞方法,這意味着后續代碼不會在每個微批處理中執行。

整體解決方案

如果您想讀取和寫入 Kafka 並且中間想通過在控制台中顯示數據來了解正在處理的數據,您可以執行以下操作:

// read from kafka
val readStream = existingSparkSession
      .readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", hostAddress)
      .option("subscribe", "my.raw") // Always read from offset 0, for dev/testing purpose
      .load()

// write to console
val df = readStream.selectExpr("CAST(value AS STRING)" )
df.writeStream
      .outputMode("append")
      .format("console")
      .start()

val df_json = df.select(from_json(col("value"), mySchema.defineSchema()).alias("parsed_value"))
val df_text = df_json.withColumn("text", col("parsed_value.payload.Text"))

// perform some data processing actions such as tokenization etc and return cleanedDataframe as the final result

// write back to kafka
// the columns `key` and `value` of the DataFrame `cleanedDataframe` will be used for producing the message into the Kafka topic.
val writeStreamKafka = cleanedDataframe
      .writeStream
      .outputMode("append")
      .format("kafka")
      .option("kafka.bootstrap.servers", hostAddress)
      .option("topic", "writing.val")
      .start()

existingSparkSession.awaitAnyTermination()

請注意代碼末尾的existingSparkSession.awaitAnyTermination() ,而不是在start之后直接使用awaitTermination 此外,請記住cleanedDataframe已清理數據幀的列keyvalue將用於將消息生成到 Kafka 主題中。 但是,不需要列key ,另請參見此處

此外,如果您使用檢查點(推薦),那么您需要設置兩個不同的位置:一個用於控制台 stream,另一個用於 kafka output ZF7B44CFAFD5C52223D5Z49.8E1 重要的是要記住,這些流式查詢是獨立運行的。

暫無
暫無

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

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