[英]How can I efficiently join a large rdd to a very large rdd in spark?
我有两个 RDD。 一个 RDD 的条目数在 5-1000 万之间,另一个 RDD 的条目数在 5 亿到 7.5 亿之间。 在某些时候,我必须使用公共密钥加入这两个 rdd。
val rddA = someData.rdd.map { x => (x.key, x); } // 10-million
val rddB = someData.rdd.map { y => (y.key, y); } // 600-million
var joinRDD = rddA.join(rddB);
当 spark 决定做这个 join 时,它决定做一个 ShuffledHashJoin。 这会导致 rddB 中的许多项目在网络上被打乱。 同样,一些 rddA 也在网络上被洗牌。 在这种情况下,rddA 太大而不能用作广播变量,但似乎 BroadcastHashJoin 会更有效。 是否有提示使用 BroadcastHashJoin 的提示? (Apache Flink 通过加入提示支持这一点)。
如果没有,是增加 autoBroadcastJoinThreshold 的唯一选择吗?
更新 7/14
我的性能问题似乎完全源于重新分区。 通常,从 HDFS 读取的 RDD 将按块进行分区,但在这种情况下,源是 [我制作的] 镶木地板数据源。 当 spark (databricks) 写入 parquet 文件时,它会为每个分区写入一个文件,同样地,它会为每个文件读取一个分区。 因此,我发现的最佳答案是,在数据源的生产过程中,要按键对其进行分区,然后写出镶木地板接收器(然后自然地共同分区)并将其用作 rddB。
给出的答案是正确的,但我认为有关镶木地板数据源的详细信息可能对其他人有用。
您可以使用相同的分区器对 RDD 进行分区,在这种情况下,具有相同键的分区将被配置在同一个执行器上。
在这种情况下,您将避免加入操作的 shuffle。
Shuffle 只会发生一次,当您更新 parititoner 时,如果您将缓存 RDD 之后的所有连接,则应该是执行程序本地的
import org.apache.spark.SparkContext._
class A
class B
val rddA: RDD[(String, A)] = ???
val rddB: RDD[(String, B)] = ???
val partitioner = new HashPartitioner(1000)
rddA.partitionBy(partitioner).cache()
rddB.partitionBy(partitioner).cache()
您也可以尝试更新广播阈值大小,也许 rddA 可以广播:
--conf spark.sql.autoBroadcastJoinThreshold=300000000 # ~300 mb
我们使用 400mb 进行广播连接,而且效果很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.