如何在Spark中将两个数组字段分解为多个列?

时间:2018-09-19 07:11:46

标签: scala apache-spark apache-spark-sql

出于类似的需要,我指的是How to explode an array into multiple columns in Spark

我可以对单个数组字段数据框使用该代码,但是,当我有多个数组字段数据框时,无法将它们都转换为多列。

例如,

dataframe1

+--------------------+----------------------------------+----------------------------------+
|                 f1 |f2                                |f3                                |
+--------------------+----------------------------------+----------------------------------+
|12                  |                              null|                              null|
|13                  |                              null|                              null|
|14                  |                              null|                              null|
|15                  |                              null|                              null|
|16                  |                              null|                              null|
|17                  |                [[Hi, 256, Hello]]|        [[a, b], [a, b, c],[a, b]]|
|18                  |                              null|                              null|
|19                  |                              null|                              null|
+--------------------+----------------------------------+----------------------------------+

我想将其转换为以下数据框:

dataframe2

+--------------------+----------------------------------+----------------------------------+----------------------------------+
|                 f1 |f2_0                              |f3_0                              |f3_1                              |
+--------------------+----------------------------------+----------------------------------+----------------------------------+
|12                  |                              null|                              null|                              null|
|13                  |                              null|                              null|                              null|
|14                  |                              null|                              null|                              null|
|15                  |                              null|                              null|                              null|
|16                  |                              null|                              null|                              null|
|17                  |                  [Hi, 256, Hello]|                            [a, b]|                         [a, b, c]|
|18                  |                              null|                              null|                              null|
|19                  |                              null|                              null|                              null|
+--------------------+----------------------------------+----------------------------------+----------------------------------+

我尝试使用以下代码:

val dataframe2 = dataframe1.select(
  col("f1") +: (0 until 2).map(i => col("f2")(i).alias(s"f2_$i")): _* +: (0 until 2).map(i => col("f3")(i).alias(s"f3_$i")): _*
)

但是在第一个“ _ *”之后期望“)”时抛出了错误。

2 个答案:

答案 0 :(得分:1)

+:在Scala中用于将单个元素添加到列表中。它不能用于将两个列表连接在一起。相反,您可以按以下方式使用++

val cols = Seq(col("f1")) 
  ++ (0 until 1).map(i => col("f2")(i).alias(s"f2_$i")) 
  ++ (0 until 2).map(i => col("f3")(i).alias(s"f3_$i"))

val dataframe2 = dataframe1.select(cols: _*)

请注意,要使用此方法,您需要事先知道列表中的元素数量。上面,我将f2列的2更改为1。

答案 1 :(得分:0)

Shaido答案已经是正确的,并且此答案只是对此的增强。在这里,我只是添加了动态查找列的最大长度。

如果列f2f3已经是数组,则按以下方法计算相应的最大数组大小。

val s1 = df.select(max(size(df("f2")))).first().getInt(0)
val s2 = df.select(max(size(df("f3")))).first().getInt(0)

否则,如果应基于定界符将列拆分并进一步划分为列,请首先按以下方式计算大小。

val s1 = df.select(max(size(split(df("f2"), ",")))).first().getInt(0)
val s2 = df.select(max(size(split(df("f3"), ",")))).first().getInt(0)

然后我们可以在Shaido答案的map函数中使用s1s2 (0 until s1).map( .....