我是新来的火花。我使用结构化流来从kafka读取数据。
我可以在Scala中使用此代码读取数据:
val data = spark.readStream
.format("kafka")
.option("kafka.bootstrap.servers", brokers)
.option("subscribe", topics)
.option("startingOffsets", startingOffsets)
.load()
我在价值列中的数据是Thrift记录。 Streaming api以二进制格式提供数据。我看到将数据转换为字符串或json的示例,但我无法找到有关如何将数据反序列化为Thrift的任何示例。
我怎样才能做到这一点?
答案 0 :(得分:1)
嗯,这是后续解决方案。我无法发布自己的代码,但这里是您可以使用的公共代码,信用给所有者/编码员。
https://github.com/airbnb/airbnb-spark-thrift/blob/master/src/main/scala/com/airbnb/spark/thrift/
首先,你需要通过调用convertObject
函数将数组[byte] / value转换为Row,让我们称之为makeRow
其次,您需要通过调用convert
函数来获取您的thrift类structType / schema,让我们调用最终结果schema
然后你需要注册一个像这样的val deserializer = udf((bytes: Array[Byte]) => makeRow(bytes), 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 当我以前的解决方案如此接近时,这给了我最后的想法。
答案 1 :(得分:0)
我在databricks网站上找到了这个博客。它展示了如何利用Spark SQL的API来使用和转换来自Apache Kafka的复杂数据流。
有一节解释了如何将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。我会在完成后立即发布。