如何在Apache Spark中爆炸get_json_object

时间:2018-10-30 21:15:01

标签: arrays json apache-spark apache-spark-sql explode

我在数据框的一列中有以下字符串:

row1:[{"key":"foo"},{"key":"bar"},{"key":"baz"}]
row2:[{"key":"foo"},{"key":"bar"}]
row3:null
etc

我发现Spark具有“ get_json_object”功能。因此,如果我想使用xpath提取数据,我将使用:

 get_json_object($"json", s"$[0].key")

将返回:

"foo"
"foo"
null

但是我需要等价于Spark的“爆炸”功能。

我发现我可以在xpath上使用“ *”符号。

 get_json_object($"json", s"$[*].key")

如果不按预期进行操作,则会创建类似以下的字符串:

[foo,bar,baz]
[foo,baz]

我在另一个stackoverflow线程

中找到了解决方案
val jsonElements = (0 until 3).map(i => get_json_object($"json", s"$$[$i].key"))


val jsonElements = .map(i => get_json_object($"json", s"$$[$i].key"))
df.select($"id",explode(array(jsonElements: _*).alias("foo")))

这部分解决了我的问题,因为此解决方案假定我知道我的数组可以达到的最大深度。 Spark的“ from_json”函数需要模式,我拥有巨大的复杂JSON类型,创建模式需要花费“无限”的时间。

免责声明

我将不使用任何正则表达式/子字符串/等来解析JSON。使用解析器的全部建议就是这样。

2 个答案:

答案 0 :(得分:0)

只需坚持使用scala基础知识即可轻松解决它。尝试使用带有选项的案例类来解决问题。

您可以使用任何标准的json解析器。我使用liftweb。

import net.liftweb.json.{DefaultFormats, parseOpt}

case class jsonElement(key: String, value: Optional[String])
//assuming the value key always exists and value may or may not exist, 
//so making that as optional / ignore the fields if you don't really care at all

val jsonKeys = inputRdd.map(eachRow => 
  implicit val formats = DefaultFormats // hate this but deal with scala

  val parsedObject = parseOpt(eachRow).flatMap(_.extractOpt[List[jsonElement]])

  parsedObject match{
    case Some(parsedItem) => parsedItem.map(json => json.key)
    case None => List()
})

这给出了list(key)的Rdd。如果要删除空列表,请使用filter(list =>!list.isEmpty)。你从那里知道。

答案 1 :(得分:0)

此解决方案回答了您的问题,您可以使用Spark推断一次架构,之后再使用该架构。

Apache Spark Read JSON With Extra Columns