【问题标题】:How can I split a column containing array of some struct into separate columns?如何将包含某些结构的数组的列拆分为单独的列?
【发布时间】:2019-07-05 23:28:20
【问题描述】:

我有以下几种情况:

case class attribute(key:String,value:String)
case class entity(id:String,attr:List[attribute])


val entities = List(entity("1",List(attribute("name","sasha"),attribute("home","del"))),
entity("2",List(attribute("home","hyd"))))

val df = entities.toDF()

// df.show
+---+--------------------+
| id|                attr|
+---+--------------------+
|  1|[[name,sasha], [d...|
|  2|        [[home,hyd]]|
+---+--------------------+

//df.printSchema
root
 |-- id: string (nullable = true)
 |-- attr: array (nullable = true)
 |    |-- element: struct (containsNull = true)
      |    |    |-- key: string (nullable = true)
      |    |    |-- value: string (nullable = true) 

我想要制作的是

+---+--------------------+-------+
| id|  name              |  home |
+---+--------------------+-------+
|  1| sasha              |del    |
|  2| null               |hyd    |
+---+--------------------+-------+

我该怎么做。我在堆栈上查看了很多类似的问题,但找不到任何有用的东西。

我的主要动机是对不同的属性进行 groupBy,因此希望将其带入上述格式。

我研究了爆炸功能。它将列表分解为单独的行,我不希望这样。我想从attribute 的数组中创建更多列。

我发现了类似的东西:

Spark - convert Map to a single-row DataFrame

Split 1 column into 3 columns in spark scala

Spark dataframe - Split struct column into 2 columns

【问题讨论】:

    标签: scala apache-spark dataframe


    【解决方案1】:

    这可以很容易地简化为PySpark converting a column of type 'map' to multiple columns in a dataframeHow to get keys and values from MapType column in SparkSQL DataFrame。先将attr转换成map<string, string>

    import org.apache.spark.sql.functions.{explode, map_from_entries, map_keys}
    
    val dfMap = df.withColumn("attr", map_from_entries($"attr"))
    

    那么这只是找到唯一键的问题

    val keys = dfMap.select(explode(map_keys($"attr"))).as[String].distinct.collect
    

    然后从地图中选择

    val result = dfMap.select($"id" +: keys.map(key => $"attr"(key) as key): _*)
    result.show
    
    +---+-----+----+
    | id| name|home|
    +---+-----+----+
    |  1|sasha| del|
    |  2| null| hyd|
    +---+-----+----+
    

    效率较低但更简洁的变体是 explodepivot

    val result = df
      .select($"id", explode(map_from_entries($"attr")))
      .groupBy($"id")
      .pivot($"key")
      .agg(first($"value"))
    
    result.show
    
    +---+----+-----+
    | id|home| name|
    +---+----+-----+
    |  1| del|sasha|
    |  2| hyd| null|
    +---+----+-----+
    

    但实际上我建议不要这样做。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    相关资源
    最近更新 更多