15

我正在尝试使用结构化流方法,使用基于 DataFrame/Dataset API 的 Spark-Streaming 从 Kafka 加载数据流。

我用:

  • 火花 2.10
  • 卡夫卡 0.10
  • 火花-sql-kafka-0-10

Spark Kafka DataSource 定义了底层架构:

|key|value|topic|partition|offset|timestamp|timestampType|

我的数据采用 json 格式,它们存储在value列中。我正在寻找一种方法如何从 value 列中提取底层架构并将接收到的数据帧更新为存储在value中的列?我尝试了下面的方法,但它不起作用:

 val columns = Array("column1", "column2") // column names
 val rawKafkaDF = sparkSession.sqlContext.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers","localhost:9092")
  .option("subscribe",topic)
  .load()
  val columnsToSelect = columns.map( x => new Column("value." + x))
  val kafkaDF = rawKafkaDF.select(columnsToSelect:_*)

  // some analytics using stream dataframe kafkaDF

  val query = kafkaDF.writeStream.format("console").start()
  query.awaitTermination()

在这里我得到了异常org.apache.spark.sql.AnalysisException: Can't extract value from value#337;,因为在创建流时,里面的值是未知的......

你有什么建议吗?

4

1 回答 1

13

从 Spark 的角度来看value,它只是一个字节序列。它不知道序列化格式或内容。为了能够提取文件,您必须先对其进行解析。

如果数据被序列化为 JSON 字符串,您有两种选择。您可以cast value使用StringTypefrom_json提供架构:

import org.apache.spark.sql.types._
import org.apache.spark.sql.functions.from_json

val schema: StructType = StructType(Seq(
  StructField("column1", ???),
  StructField("column2", ???)
))

rawKafkaDF.select(from_json($"value".cast(StringType), schema))

或者cast,使用以下StringType路径提取字段get_json_object

import org.apache.spark.sql.functions.get_json_object

val columns: Seq[String] = ???

val exprs = columns.map(c => get_json_object($"value", s"$$.$c"))

rawKafkaDF.select(exprs: _*)

然后cast是所需的类型。

于 2017-04-08T18:49:02.507 回答