[英]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)
您當前的實現中存在兩個常見問題:
show
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
已清理數據幀的列key
和value
將用於將消息生成到 Kafka 主題中。 但是,不需要列key
,另請參見此處
此外,如果您使用檢查點(推薦),那么您需要設置兩個不同的位置:一個用於控制台 stream,另一個用於 kafka output ZF7B44CFAFD5C52223D5Z49.8E1 重要的是要記住,這些流式查詢是獨立運行的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.