在Spark结构化流中反序列化自引用原始协议

时间:2018-07-18 15:22:53

标签: apache-spark apache-spark-sql deserialization spark-streaming protocol-buffers

我有一个自引用的protobuf模式:

message A { 
 uint64 timestamp = 1; 
 repeated A fields = 2; 
}

我正在使用scalaPB生成对应的Scala类,然后尝试按照以下步骤解码从Kafka流中消耗的消息:

def main(args : Array[String]) {

  val spark = SparkSession.builder.
    master("local")
    .appName("spark session example")
    .getOrCreate()

  import spark.implicits._

  val ds1 = spark.readStream.format("kafka").
      option("kafka.bootstrap.servers","localhost:9092").
      option("subscribe","student").load()

  val ds2 = ds1.map(row=> row.getAs[Array[Byte]]("value")).map(Student.parseFrom(_))

  val query = ds2.writeStream
      .outputMode("append")
      .format("console")
      .start()

  query.awaitTermination()

}

This is a related question here on StackOverflow

但是,Spark结构化流在此行抛出循环引用错误。

val ds2 = ds1.map(row=> row.getAs[Array[Byte]]("value")).map(Student.parseFrom(_))

我理解这是因为递归引用只能在驱动程序(基本上是RDDDataset级别)上在Spark中处理。有没有人找到解决此问题的方法,例如通过UDF启用递归调用?

1 个答案:

答案 0 :(得分:0)

事实证明,这是由于制作火花架构的方式受到限制所致。为了处理大量数据,代码与部分数据一起分布在所有从属节点上,结果通过主节点进行协调。现在,由于在工作程序节点上没有任何东西可以跟踪堆栈,因此不允许在工作程序上进行递归,而只能在驱动程序级别上进行递归。

简而言之,对于当前的spark版本,无法进行这种递归解析。最好的选择是移至具有类似库并轻松解析递归protobuf文件的Java。