Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spark是否计划加入?_Java_Apache Spark - Fatal编程技术网

Java Spark是否计划加入?

Java Spark是否计划加入?,java,apache-spark,Java,Apache Spark,我正在加入两个RDDrddA和rddB rddA有100个分区,rddB有500个分区 我试图理解join操作的机制。默认情况下,无论连接的顺序如何,我最终都会使用相同的分区结构;i、 e.rddA.join(rddB)和rddB.join(rddA)产生相同数量的分区,通过观察,它使用较小的分区大小100。我知道我可以通过使用rddA.join(rddB,500)来增加分区大小,但我更感兴趣的是在引擎盖下发生的事情以及为什么选择较小的大小。根据观察,即使我重新划分了小的rdd,它的分区仍然会被

我正在加入两个RDD
rddA
rddB

rddA
有100个分区,
rddB
有500个分区

我试图理解
join
操作的机制。默认情况下,无论连接的顺序如何,我最终都会使用相同的分区结构;i、 e.
rddA.join(rddB
)和
rddB.join(rddA)
产生相同数量的分区,通过观察,它使用较小的分区大小100。我知道我可以通过使用
rddA.join(rddB,500)
来增加分区大小,但我更感兴趣的是在引擎盖下发生的事情以及为什么选择较小的大小。根据观察,即使我重新划分了小的
rdd
,它的分区仍然会被使用;Spark是否对密钥大小进行启发式分析

我的另一个问题是我得到的偏斜程度。我较小的分区最终有3314个条目,较大的分区最终有1139207个条目,总大小为599911729(键)。两个RDD都使用默认的分区器,那么如何决定数据洗牌呢? 我模模糊糊地回忆起读到的内容,如果一个
rdd
有一个分区器集,那么将使用该分区器。是这样吗?是否“建议”这样做

最后,请注意,我的
rdd
s都相对较大(~90GB),因此广播连接没有帮助。相反,任何为
join
操作提供一些见解的方法都可能是可行的


注:任何关于左连接和右连接机制的细节都是一个额外的好处:)

尽管我还没有解释分区是如何派生的,但我确实发现了数据是如何被洗牌的(这是我最初的问题)。联接有一些副作用:

洗牌/分区: Spark将散列分区“RDD”键,并在“Workers”之间移动/分发。给定键(例如5)的每一组值都将在一个“Worker”/JVM中结束。这意味着,如果您的“join”有一个1..N关系,并且N是严重倾斜的,那么您将得到倾斜的分区和JVM堆(即,一个“分区”可能有Max(N)和另一个Min(N))。避免这种情况的唯一方法是尽可能使用“广播”或容忍这种行为。由于数据最初是均匀分布的,因此洗牌量将取决于密钥散列

重新分区: 在“倾斜”联接之后,调用“重新分区”似乎可以在分区之间均匀地重新分配数据。所以,如果你有不可避免的偏斜问题,这是一件好事。请注意,虽然此转换将触发严重的洗牌,但后续操作将快得多。但其缺点是无法控制对象的创建(见下文)

对象创建/堆污染: 您设法加入了您的数据,并认为重新分区是重新平衡集群的一个好主意,但出于某种原因,“重新分区”会触发“OOME”。发生的情况是,最初连接的数据重新使用连接的对象。当您触发“重新分区”或任何其他涉及洗牌的“操作”时,例如额外的联接或“groupBy”(后跟“操作”),数据将被序列化,因此您将失去对象重用。对象反序列化后,它们现在是新实例。还要注意的是,在序列化过程中,重复使用会丢失,因此萨福克将相当沉重。因此,在我的例子中,1..1000000连接(其中1是我的“重”对象)将在触发洗牌的任何操作之后失败

解决方法/调试:

  • 我使用“mapPartitionsWithIndex”来调试分区大小,方法是返回带有每个分区计数的单个项“Iterable>”。这非常有用,因为您可以看到“重新分区”的效果以及“操作”后分区的状态
  • 您可以在联接RDD上使用“CountByKeyAppro”或“countByKey”来了解基数,然后分两步应用联接。高基数键使用“广播”,低基数键使用“连接”。将这些操作包装在“rdd.cache()”和“rdd.unpersist()”块中将显著加快此过程。尽管这可能会使代码复杂一些,但它将提供更好的性能,尤其是在执行后续操作时。另外请注意,如果您在每个“映射”中使用“广播”来进行查找,您还将显著减少洗牌大小
  • 调用影响分区数量的其他操作的“重新分区”可能非常有用,但请注意,(随机)大量分区将导致更多的skenewsess,因为给定密钥的大型集将创建大型分区,但其他分区的大小将很小或为0。创建一个调试方法来获得分区的大小将帮助您选择一个合适的大小