【问题标题】:Spark get datatype of nested objectSpark获取嵌套对象的数据类型
【发布时间】:2018-06-24 06:03:37
【问题描述】:

我有一些如下所示的 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

但是当我尝试使用 schema.("key5.key51").dataType 获取嵌套在 key5 下的 key51 的数据类型时,我收到以下错误:

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,然后分解该列。

但是有没有更好、更优雅的方法来做到这一点,同时仍然能够确定给定列的数据类型?

【问题讨论】:

    标签: arrays apache-spark dataframe apache-spark-sql


    【解决方案1】:

    这里有一些(递归)代码来查找所有 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
    

    这还不适用于地图内的数组或嵌套数组

    【讨论】:

      【解决方案2】:

      最简单的解决方案是select感兴趣的字段,然后检索架构:

      df.select("key5.key51").schema.head.dataType
      

      直接使用完整架构,需要遍历架构,并且可能很难正确执行,而使用嵌入式 .StructTypes 和复杂类型(MapsArrays)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-10
        • 2021-12-08
        相关资源
        最近更新 更多