如何将那些行(来自大表)与左小表中的键联合起来?

时间:2017-05-19 05:58:34

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

我有两个数据帧,一个很大,另一个很小:

val small_df = sc.parallelize(List(("Alice", 15), ("Bob", 20)).toDF("name", "age")

val large_df = sc.parallelize(("Bob", 40), ("SomeOne", 50) , ... ).toDF("name", "age")

我想将这两个数据框加起来,但只有那些在我的小表中有关键字的数据框,也就是说,我希望我的结果如下:

List(("Alice", 15), ("Bob", 60))

我的第一次尝试是尝试unionreduceByKey,但我似乎无法找到union两个表的方法,并保留这些行中的键。只有一个。

有没有办法做类似"左联盟"或其他方式来接近我的答案?

2 个答案:

答案 0 :(得分:2)

那应该给你你想要的东西:

val existingKeys = small_df.
  join(large_df, "name").
  select($"name", large_df("age"))
val all = small_df.
  union(existingKeys).
  groupBy("name").
  agg(sum("age") as "age")
scala> all.show
+-----+---+
| name|age|
+-----+---+
|  Bob| 60|
|Alice| 15|
+-----+---+

答案 1 :(得分:2)

解决此问题的一种方法是创建外部联接,然后将两个结果年龄列相加。请注意,应导入spark.implicits._以使用$org.apache.spark.sql.functions.broadcast进行广播。

如果两个数据帧中的任何一个包含重复项(在名称列中),最终的数据帧也将包含重复项,这可能是您想要的或不是。对于large_df中的重复项,只有问题中指定的small_df中有相应的名称才会显示这些重复项。

作为优化,由于其中一个数据帧较小,因此可以在连接之前进行广播以提高性能。

val small_df = sc.parallelize(List(("Alice", 15), ("Bob", 20)).toDF("name", "age")
val large_df = sc.parallelize(("Bob", 40), ("SomeOne", 50)).toDF("name", "age")

val df = large_df.withColumnRenamed("age", "large_age").join(broadcast(small_df), Array("name"), "right_outer")
val df2 = df.withColumn("age", when($"large_age".isNotNull, $"age" + $"large_age").otherwise($"age")).select("name", "age")
df2.show

+-----+----+
| name| age|
+-----+----+
|Alice|15.0|
|  Bob|60.0|
+-----+----+