我有一些JSON数据,如下所示:
{
"key1":"value1",
"key2":[
1,
2,
3
],
"key3":{
"key31":"value31",
"key32":"value32"
},
"key4":[
{
"key41":"value411",
"key42":"value412",
"key43":"value413"
},
{
"key41":"value421",
"key42":"value422",
"key43":"value423"
}
],
"key5":{
"key51":[
{
"key511":"value511",
"key512":"value512",
"key513":"value513"
},
{
"key511":"value521",
"key512":"value522",
"key513":"value523"
}
]
},
"key6":{
"key61":{
"key611":[
{
"key_611":"value_611",
"key_612":"value_612",
"key_613":"value_613"
},
{
"key_611":"value_621",
"key_612":"value_622",
"key_613":"value_623"
},
{
"key_611":"value_621",
"key_612":"value_622",
"key_613":"value_623"
}
]
}
}
}
它包含简单,复杂和数组类型值的混合。
如果我尝试获取key1 schema.("key1").dataType
的数据类型,我得到StringType
,同样也得到key2,key3和key4。
对于key5,我得到StructType
。
但是当我尝试获取key51的数据类型时,它使用schema.("key5.key51").dataType
嵌套在key5下,我收到以下错误:
java.lang.IllegalArgumentException: Field "key5.key51" does not exist.
at org.apache.spark.sql.types.StructType$$anonfun$apply$1.apply(StructType.scala:264)
at org.apache.spark.sql.types.StructType$$anonfun$apply$1.apply(StructType.scala:264)
at scala.collection.MapLike$class.getOrElse(MapLike.scala:128)
at scala.collection.AbstractMap.getOrElse(Map.scala:59)
at org.apache.spark.sql.types.StructType.apply(StructType.scala:263)
... 48 elided
我的主要目的是能够爆炸某个类型,如果它的ArrayType
并且不会爆炸任何其他类型。
explode函数能够正确识别这个给定的键(key5.key51)并爆炸阵列。但问题在于确定数据类型。
对我来说,一个可能的解决方案是选择key5.key51作为单独的列key51然后爆炸该列。
但是还有更好,更优雅的方法可以确定给定列的数据类型吗?
答案 0 :(得分:3)
最简单的解决方案是select
感兴趣的字段,然后检索模式:
df.select("key5.key51").schema.head.dataType
直接使用完整模式,需要遍历模式,并且可能很难做到,而嵌入式.
,StructTypes
和复杂类型(Maps
和Arrays
)。
答案 1 :(得分:0)
以下是一些(递归)代码,用于查找所有ArrayType
字段名称:
import org.apache.spark.sql.types._
def findArrayTypes(parents:Seq[String],f:StructField) : Seq[String] = {
f.dataType match {
case array: ArrayType => parents
case struct: StructType => struct.fields.toSeq.map(f => findArrayTypes(parents:+f.name,f)).flatten
case _ => Seq.empty[String]
}
}
val arrayTypeColumns = df.schema.fields.toSeq
.map(f => findArrayTypes(Seq(f.name),f))
.filter(_.nonEmpty).map(_.mkString("."))
对于您的数据框,这会给出:
arrayTypeColumns.foreach(println)
key2
key4
key5.key51
key6.key61.key611
这对于map或嵌套数组中的数组
还不行