繁体   English   中英

如何在 spark 中有效地将大 rdd 连接到非常大的 rdd?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM