簡體   English   中英

Spark (2.2):使用結構化流從 Kafka 反序列化 Thrift 記錄

[英]Spark (2.2): deserialise Thrift records from Kafka using Structured Streaming

我是新來的火花。 我使用結構化流從 kafka 讀取數據。

我可以在 Scala 中使用此代碼讀取數據:

val data = spark.readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", brokers)
      .option("subscribe", topics)
      .option("startingOffsets", startingOffsets) 
      .load()

我在值列中的數據是 Thrift 記錄。 流式 API 以二進制格式提供數據。 我看到了將數據轉換為字符串或 json 的示例,但我找不到任何有關如何將數據反序列化為 Thrift 的示例。

我怎樣才能做到這一點?

好吧,這是后續解決方案。 我不能發布我自己的代碼,但這是您可以使用的公共代碼,歸功於所有者/編碼員。

https://github.com/airbnb/airbnb-spark-thrift/blob/master/src/main/scala/com/airbnb/spark/thrift/

首先需要調用convertObject函數將array[byte]/value轉換為Row,我們稱之為makeRow

其次,你需要通過調用convert函數來獲取你的thrift類structType/schema,讓我們調用最終結果schema

然后你需要注冊一個像這樣的UDF val deserializer = udf((bytes: Array[Byte]) => makeRow(bytes), schema)

注意:不能在不傳遞 schema 的情況下直接使用 makeRow,否則 Spark 會報錯: Schema for type org.apache.spark.sql.Row is not supported

然后你可以這樣使用它:

val stuff = kafkaStuff.withColumn("data", deserializer(kafkaStuff("value"))) val finalStuff = stuff.select("data.*")

而且……你完成了! 希望這可以幫助。

並再次感謝這篇文章Spark UDF for StructType / Row當我以前的解決方案如此接近時,它給了我最終的想法。

我在 databricks 網站上找到了這個博客。 它展示了如何利用 Spark SQL 的 API 來使用和轉換來自 Apache Kafka 的復雜數據流。

https://databricks.com/blog/2017/04/26/processing-data-in-apache-kafka-with-structured-streaming-in-apache-spark-2-2.html

有一節解釋了如何將 UDF 用於反序列化行:

object MyDeserializerWrapper {
  val deser = new MyDeserializer
}
spark.udf.register("deserialize", (topic: String, bytes: Array[Byte]) => 
  MyDeserializerWrapper.deser.deserialize(topic, bytes)
)

df.selectExpr("""deserialize("topic1", value) AS message""")

我正在使用 java,因此必須編寫以下示例 UDF,以檢查如何在 java 中調用它:

UDF1<byte[], String> mode = new UDF1<byte[], String>() {
            @Override
            public String call(byte[] bytes) throws Exception {
                String s = new String(bytes);
                return "_" + s;
            }
        };

現在我可以在結構化流字數統計示例中使用這個 UDF,如下所示:

Dataset<String> words = df
                //converted the DataFrame to a Dataset of String using .as(Encoders.STRING())
//                .selectExpr("CAST(value AS STRING)")
                .select( callUDF("mode", col("value")) )
                .as(Encoders.STRING())
                .flatMap(
                        new FlatMapFunction<String, String>() {
                            @Override
                            public Iterator<String> call(String x) {
                                return Arrays.asList(x.split(" ")).iterator();
                            }
                        }, Encoders.STRING());

我的下一步是為 thrift 反序列化編寫一個 UDF。 我會盡快發布。

暫無
暫無

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

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