我有两个数据帧,一个很大,另一个很小:
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))
我的第一次尝试是尝试union
和reduceByKey
,但我似乎无法找到union
两个表的方法,并保留这些行中的键。只有一个。
有没有办法做类似"左联盟"或其他方式来接近我的答案?
答案 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|
+-----+----+