Spark sql如何在不丢失空值的情况下爆炸

新手上路,请多包涵

我有一个要展平的数据框。作为过程的一部分,我想分解它,所以如果我有一列数组,数组的每个值都将用于创建一个单独的行。例如,

 id | name | likes
_______________________________
1  | Luke | [baseball, soccer]

应该成为

id | name | likes
_______________________________
1  | Luke | baseball
1  | Luke | soccer

这是我的代码

private DataFrame explodeDataFrame(DataFrame df) {
    DataFrame resultDf = df;
    for (StructField field : df.schema().fields()) {
        if (field.dataType() instanceof ArrayType) {
            resultDf = resultDf.withColumn(field.name(), org.apache.spark.sql.functions.explode(resultDf.col(field.name())));
            resultDf.show();
        }
    }
    return resultDf;
}

问题是在我的数据中,一些数组列有空值。在这种情况下,整行都将被删除。所以这个数据框:

 id | name | likes
_______________________________
1  | Luke | [baseball, soccer]
2  | Lucy | null

成为

id | name | likes
_______________________________
1  | Luke | baseball
1  | Luke | soccer

代替

id | name | likes
_______________________________
1  | Luke | baseball
1  | Luke | soccer
2  | Lucy | null

我怎样才能分解我的数组,这样我就不会丢失空行?

我正在使用 Spark 1.5.2 和 Java 8

原文由 alexgbelov 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 662
2 个回答

火花 2.2+

您可以使用 explode_outer 功能:

 import org.apache.spark.sql.functions.explode_outer

df.withColumn("likes", explode_outer($"likes")).show

// +---+----+--------+
// | id|name|   likes|
// +---+----+--------+
// |  1|Luke|baseball|
// |  1|Luke|  soccer|
// |  2|Lucy|    null|
// +---+----+--------+

火花 <= 2.1

在 Scala 中,但 Java 等效项应该几乎相同(导入单个函数使用 import static )。

 import org.apache.spark.sql.functions.{array, col, explode, lit, when}

val df = Seq(
  (1, "Luke", Some(Array("baseball", "soccer"))),
  (2, "Lucy", None)
).toDF("id", "name", "likes")

df.withColumn("likes", explode(
  when(col("likes").isNotNull, col("likes"))
    // If null explode an array<string> with a single null
    .otherwise(array(lit(null).cast("string")))))

这里的想法基本上是用所需类型的 array(NULL) 替换 NULL 。对于复杂类型(又名 structs ),您必须提供完整的架构:

 val dfStruct = Seq((1L, Some(Array((1, "a")))), (2L, None)).toDF("x", "y")

val st =  StructType(Seq(
  StructField("_1", IntegerType, false), StructField("_2", StringType, true)
))

dfStruct.withColumn("y", explode(
  when(col("y").isNotNull, col("y"))
    .otherwise(array(lit(null).cast(st)))))

或者

dfStruct.withColumn("y", explode(
  when(col("y").isNotNull, col("y"))
    .otherwise(array(lit(null).cast("struct<_1:int,_2:string>")))))

注意

如果数组 Column 已使用 containsNull 设置为 false 创建,您应该首先更改它(使用 Spark 2.1 测试):

 df.withColumn("array_column", $"array_column".cast(ArrayType(SomeType, true)))

原文由 zero323 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 explode_outer() 功能。

原文由 TopGuys 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题