如何连接两个DataFrame并更新缺失值?

时间:2017-04-18 13:08:40

标签: apache-spark dataframe apache-spark-sql

我使用Spark 2.0 ,并希望在DataFrame中更新/合并行值。

我有两个DataFrames(旧的和新的),我想以一种方式合并,当旧的DataFrame有比新的DataFrame更多的行时,设置旧的数据值0。

案例1合并

旧数据框:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bc|
## +---+----+----+

新数据框:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bb|
## |  3|  cc|  cc|
## +---+----+----+

结果:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bb|
## |  3|  cc|  cc|
## +---+----+----+

案例2更新

旧数据框:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bb|
## |  3|  cc|  cc|
## +---+----+----+

新数据框:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bc|
## +---+----+----+

结果:

## +---+----+----+
## |key|val1|val2|
## +---+----+----+
## |  1|  aa|  ab|
## |  2|  bb|  bc|
## |  3|  00|  00|
## +---+----+----+

密钥在两种情况下是唯一的,在实际情况下,DataFrame可以有很多列。

如何编写Spark / Scala代码以在一个函数中实现这两种情况?

2 个答案:

答案 0 :(得分:4)

诀窍是使用fullOuterJoinwhen条件。

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

val dfa = Seq(
  (1, "aa", "ab"),
  (2, "bb", "bb"),
  (3, "cc", "cc")).toDF("key", "val1", "val2")

val dfb = Seq(
  (1, "aa", "ab"),
  (2, "bb", "bb")).toDF("key", "val1", "val2")

val q = dfa
  .join(dfb, Seq("key"), "outer")
  .select($"key",
     when(dfb("val1").isNull, lit(0)).otherwise(dfb("val1")).as("val1"), 
     when(dfb("val2").isNull, lit(0)).otherwise(dfb("val2")).as("val2"))
  .orderBy("key")

scala> q.show
+---+----+----+
|key|val1|val2|
+---+----+----+
|  1|  aa|  ab|
|  2|  bb|  bb|
|  3|   0|   0|
+---+----+----+

答案 1 :(得分:1)

就像the comment中建议的@summerbulb一样,您应该使用na运算符来填充缺失值。

请注意,我使用as运算符来为列提供别名。

val oldDF = Seq(
  (1, "aa", "ab"),
  (2, "bb", "bb"),
  (3, "cc", "cc")).toDF("key", "val1", "val2")
val newDF = Seq(
  (1, "aa", "ab"),
  (2, "bb", "bc")).toDF("key", "val1", "val2")
val q = oldDF.join(newDF.as("new"), Seq("key"), "outer")
  .select("key", "new.*")
  .na.fill("0")  // <-- na.fill("0") because of String type
  .orderBy("key")

scala> q.show
+---+----+----+
|key|val1|val2|
+---+----+----+
|  1|  aa|  ab|
|  2|  bb|  bc|
|  3|   0|   0|
+---+----+----+

根据列的类型,您可能希望将0用作StringDouble类型。

the scaladoc of Dataset中阅读asna