我需要根据一些共享键列将join
多个DataFrame放在一起。对于键值RDD,可以指定分区器,以便将具有相同键的数据点混洗到同一个执行器,因此加入更有效(如果在join
之前有一个shuffle相关操作)。可以在Spark DataFrames或DataSet上完成同样的事情吗?
答案 0 :(得分:8)
如果你知道你将多次加入DataFrame,你可以repartition
加载一个DataFrame
val users = spark.read.load("/path/to/users").repartition('userId)
val joined1 = users.join(addresses, "userId")
joined1.show() // <-- 1st shuffle for repartition
val joined2 = users.join(salary, "userId")
joined2.show() // <-- skips shuffle for users since it's already been repartitioned
因此,它会将数据混洗一次,然后在后续加入时重复使用随机播放文件。
但是,如果您知道您将反复对某些键上的数据进行洗牌,那么您最好的选择是将数据保存为分段表。这将把数据写入预先散列分区的数据,因此当您读取表并加入它们时,您可以避免随机播放。你可以这样做:
// you need to pick a number of buckets that makes sense for your data
users.bucketBy(50, "userId").saveAsTable("users")
addresses.bucketBy(50, "userId").saveAsTable("addresses")
val users = spark.read.table("users")
val addresses = spark.read.table("addresses")
val joined = newUsers.join(addresses, "userId")
joined.show() // <-- no shuffle since tables are co-partitioned data
为了避免混乱,桌子必须使用相同的桶(例如相同数量的桶并在桶列上连接)。
答案 1 :(得分:1)
可以使用repartition
方法使用DataFrame / DataSet API。使用此方法,您可以指定一个或多个用于数据分区的列,例如
val df2 = df.repartition($"colA", $"colB")
同时也可以在同一命令中指定所需分区的数量,
val df2 = df.repartition(10, $"colA", $"colB")
注意:这并不能保证数据帧的分区位于同一节点上,只能保证分区以相同的方式完成。