Flattern Scala数组数据类型列到多列

时间:2018-12-17 19:57:25

标签: scala apache-spark dataframe

他们是否有可能在Scala DF中展平数组?

据我所知,使用列并选择filed.a是可行的,但我不想手动指定它们。

  df.printSchema()
 |-- client_version: string (nullable = true)
 |-- filed: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a: string (nullable = true)
 |    |    |-- b: string (nullable = true)
 |    |    |-- c: string (nullable = true)
 |    |    |-- d: string (nullable = true)

最终df

df.printSchema()
     |-- client_version: string (nullable = true)
     |-- filed_a: string (nullable = true)
     |-- filed_b: string (nullable = true)
     |-- filed_c: string (nullable = true)
     |-- filed_d: string (nullable = true)

2 个答案:

答案 0 :(得分:2)

您可以使用ArrayTypeexplode嵌套的struct元素名称将map列展平为所需的顶级列名称,如下所示:

import org.apache.spark.sql.functions._

case class S(a: String, b: String, c: String, d: String)

val df = Seq(
  ("1.0", Seq(S("a1", "b1", "c1", "d1"))),
  ("2.0", Seq(S("a2", "b2", "c2", "d2"), S("a3", "b3", "c3", "d3")))
).toDF("client_version", "filed")

df.printSchema
// root
//  |-- client_version: string (nullable = true)
//  |-- filed: array (nullable = true)
//  |    |-- element: struct (containsNull = true)
//  |    |    |-- a: string (nullable = true)
//  |    |    |-- b: string (nullable = true)
//  |    |    |-- c: string (nullable = true)
//  |    |    |-- d: string (nullable = true)

val dfFlattened = df.withColumn("filed_element", explode($"filed"))

val structElements = dfFlattened.select($"filed_element.*").columns

val dfResult = dfFlattened.select( col("client_version") +: structElements.map( 
    c => col(s"filed_element.$c").as(s"filed_$c")
  ): _*
)

dfResult.show
// +--------------+-------+-------+-------+-------+
// |client_version|filed_a|filed_b|filed_c|filed_d|
// +--------------+-------+-------+-------+-------+
// |           1.0|     a1|     b1|     c1|     d1|
// |           2.0|     a2|     b2|     c2|     d2|
// |           2.0|     a3|     b3|     c3|     d3|
// +--------------+-------+-------+-------+-------+

dfResult.printSchema
// root
//  |-- client_version: string (nullable = true)
//  |-- filed_a: string (nullable = true)
//  |-- filed_b: string (nullable = true)
//  |-- filed_c: string (nullable = true)
//  |-- filed_d: string (nullable = true)

答案 1 :(得分:0)

使用explode通过添加更多行来展平数组,然后使用select表示法*使struct列回到顶部。

import org.apache.spark.sql.functions.{collect_list, explode, struct}
import spark.implicits._

val df = Seq(("1", "a", "a", "a"),
  ("1", "b", "b", "b"),
  ("2", "a", "a", "a"),
  ("2", "b", "b", "b"),
  ("2", "c", "c", "c"),
  ("3", "a", "a","a")).toDF("idx",  "A", "B", "C")
  .groupBy(("idx"))
  .agg(collect_list(struct("A", "B", "C")).as("nested_col"))

df.printSchema()
// root
//  |-- idx: string (nullable = true)
//  |-- nested_col: array (nullable = true)
//  |    |-- element: struct (containsNull = true)
//  |    |    |-- A: string (nullable = true)
//  |    |    |-- B: string (nullable = true)
//  |    |    |-- C: string (nullable = true)

df.show
// +---+--------------------+
// |idx|          nested_col|
// +---+--------------------+
// |  3|         [[a, a, a]]|
// |  1|[[a, a, a], [b, b...|
// |  2|[[a, a, a], [b, b...|
// +---+--------------------+

val dfExploded = df.withColumn("exploded", explode($"nested_col")).drop("nested_col")

dfExploded.show
// +---+---------+
// |idx| exploded|
// +---+---------+
// |  3|[a, a, a]|
// |  1|[a, a, a]|
// |  1|[b, b, b]|
// |  2|[a, a, a]|
// |  2|[b, b, b]|
// |  2|[c, c, c]|
// +---+---------+

val finalDF = dfExploded.select("idx", "exploded.*")

finalDF.show
// +---+---+---+---+
// |idx|  A|  B|  C|
// +---+---+---+---+
// |  3|  a|  a|  a|
// |  1|  a|  a|  a|
// |  1|  b|  b|  b|
// |  2|  a|  a|  a|
// |  2|  b|  b|  b|
// |  2|  c|  c|  c|
// +---+---+---+---+