【问题标题】:How to explode two array fields to multiple columns in Spark?如何在 Spark 中将两个数组字段分解为多列?
【发布时间】:2018-09-25 01:05:19
【问题描述】:

我指的是How to explode an array into multiple columns in Spark 有类似的需求。

我可以将该代码用于单个数组字段数据帧,但是,当我有多个数组字段数据帧时,我无法将两者都转换为多个列。

例如,

数据框1

+--------------------+----------------------------------+----------------------------------+
|                 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")): _*
)

但它会抛出一个错误,说它在第一个“_*”之后需要一个“)”。

【问题讨论】:

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


    【解决方案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。

    【讨论】:

    • 感谢您的解释。我有一个语法疑问。我的代码中最后一个 _* 表达式是什么意思?我不明白参考链接中的那部分。
    • @user3243499:很高兴为您提供帮助。我认为这里的答案比我能解释得更好:stackoverflow.com/questions/6051302/…
    【解决方案2】:

    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( .....

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-24
      • 2016-07-25
      • 2022-07-31
      • 1970-01-01
      • 2018-05-13
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      相关资源
      最近更新 更多