在Spark Streaming SQL中解析嵌套的JSON字符串化列

时间:2016-01-04 23:38:33

标签: json apache-spark apache-spark-sql spark-streaming

我遵循了spark流媒体指南,并且能够使用sqlContext.read.json(rdd)获取我的json数据的sql上下文。问题是其中一个json字段是我想要解析的JSON字符串。

有没有办法在spark sql中完成这个,或者使用ObjectMapper解析字符串并加入其余数据会更容易吗?

为了澄清,JSON的一个值是字符串,其中包含内部引号转义的JSON数据。我正在寻找一种方法来告诉解析器将该值视为字符串化JSON

示例Json

{ 
  "key": "val",
  "jsonString": "{ \"too\": \"bad\" }",
  "jsonObj": { "ok": "great" }
}

SQLContext如何解析它

root
 |-- key: string (nullable = true)
 |-- jsonString: string (nullable = true)
 |-- jsonObj: struct (nullable = true)
 |    |-- ok: string (nullable = true)

我希望如何

root
 |-- key: string (nullable = true)
 |-- jsonString: struct (nullable = true)
 |    |-- too: string (nullable = true)
 |-- jsonObj: struct (nullable = true)
 |    |-- ok: string (nullable = true)

4 个答案:

答案 0 :(得分:4)

您可以使用from_json功能来解析数据集的列:

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

val stringified = spark.createDataset(Seq("{ \"too\": \"bad\" }", "{ \"too\": \"sad\" }"))
stringified.printSchema()

val structified = stringified.withColumn("value", from_json($"value", StructType(Seq(StructField("too", StringType, false)))))
structified.printSchema()

value列从string转换为struct

root
 |-- value: string (nullable = true)

root
 |-- value: struct (nullable = true)
 |    |-- too: string (nullable = false)

答案 1 :(得分:2)

较旧的RDD API方法(请参阅DataFrame API的已接受答案)

我最终使用Jackson来解析json信封,然后再次解析内部转义字符串。

val parsedRDD = rdd.map(x => {

      // Get Jackson mapper
      val mapper = new ObjectMapper() with ScalaObjectMapper
      mapper.registerModule(DefaultScalaModule)

      // parse envelope
      val envelopeMap = mapper.readValue[Map[String,Any]](x)
      //println("the original envelopeMap", envelopeMap)

      // parse inner jsonString value
      val event = mapper.readValue[Map[String,Any]](envelopeMap.getOrElse("body", "").asInstanceOf[String])

      // get Map that includes parsed jsonString
      val parsed = envelopeMap.updated("jsonString", event)

      // write entire map as json string
      mapper.writeValueAsString(parsed)
})

val df = sqlContext.read.json(parsedRDD)

现在parsedRDD包含有效的json,数据框正确地推断出整个模式。

我认为必须有一种方法可以避免必须序列化到json并再次解析但到目前为止我没有看到任何在RDD上运行的sqlContext API [Map [String,Any]]

答案 2 :(得分:0)

显然

  

“jsonString”:“{\”too \“:\”bad \“}”

是无效的json数据,修复:并确保整个字符串是有效的json结构。

答案 3 :(得分:0)

你提供的json是错误的,所以修复并给你一个例子。

让我们把json带到下面。 {“key”:“val”,“jsonString”:{“too”:“bad”},“jsonObj”:{“ok”:“great”}}

Spark SQL Json解析器也允许你读取嵌套的json,坦率地说,如果没有提供,它就不完整了,因为你会看到几乎99%的嵌套jsons。

要了解如何访问它,您需要选择使用。 。这是jsonString.too或jsonObj.ok。

以下是理解

的示例
scala> val df1 = sqlContext.read.json("/Users/srini/workspace/splunk_spark/file3.json").toDF
df1: org.apache.spark.sql.DataFrame = [jsonObj: struct<ok:string>, jsonString: struct<too:string>, key: string]

scala> df1.show
+-------+----------+---+
|jsonObj|jsonString|key|
+-------+----------+---+
|[great]|     [bad]|val|
+-------+----------+---+


scala> df1.select("jsonString.too");
res12: org.apache.spark.sql.DataFrame = [too: string]

scala> df1.select("jsonString.too").show
+---+
|too|
+---+
|bad|
+---+


scala> df1.select("jsonObj.ok").show
+-----+
|   ok|
+-----+
|great|
+-----+
希望你能理解。如果您需要更多信息,请回复。它只是父节点。子节点。而已。