我在数据框的一列中有以下字符串:
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。使用解析器的全部建议就是这样。
答案 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推断一次架构,之后再使用该架构。