【问题标题】:Is it possible to coalesce Spark partitions "evenly"?是否可以“均匀地”合并 Spark 分区?
【发布时间】:2018-11-24 00:22:26
【问题描述】:

假设我们有一个 PySpark 数据帧,其中数据均匀分布在 2048 个分区中,我们希望合并到 32 个分区以将数据写回 HDFS。使用coalesce 非常适合,因为它不需要昂贵的随机播放。

但是coalesce 的缺点之一是它通常会导致数据在新分区中的分布不均匀。我假设这是因为原始分区 ID 被散列到新的分区 ID 空间,并且冲突的数量是随机的。

但是,原则上应该可以均匀合并,以便将原始数据帧的前 64 个分区发送到新数据帧的第一个分区,接下来的 64 个分区发送到第二个分区,如此结束,导致分区分布均匀。生成的数据帧通常更适合进一步计算。

这是否可能,同时防止洗牌?

我可以使用this question 中的技巧来强制在初始分区和最终分区之间建立我想要的关系,但是 Spark 不知道每个原始分区中的所有内容都将转到特定的新分区。因此它无法优化掉 shuffle,而且它的运行速度比 coalesce 慢得多。

【问题讨论】:

  • 感谢您编辑答案,并对造成的误解深表歉意。为什么你认为合并会不均匀地分布数据?如果当前分区数是所需分区数的倍数,我希望每个新分区在合并后的沿袭中具有偶数个上游分区。这对你有意义吗?无论如何我都会检查代码。
  • 检查并添加了一个新答案,您可以安全地合并,并且在保持均匀性的同时不会洗牌。 :)

标签: apache-spark pyspark partitioning


【解决方案1】:

在您的情况下,您可以安全地将 2048 个分区合并为 32 个,并假设 Spark 会将上游分区平均分配给合并后的分区(在您的情况下每个分区为 64 个)。

这里是an extract from the Scaladoc of RDD#coalesce

这会导致依赖范围狭窄,例如如果您从 1000 个分区增加到 100 个分区,则不会发生 shuffle,而是 100 个新分区中的每一个都将占用当前分区中的 10 个。

考虑一下,您的分区在集群中的物理分布方式也会影响合并发生的方式。以下是CoalescedRDD's ScalaDoc的摘录:

如果父节点中没有位置信息(没有preferredLocations),那么合并非常简单:在数组中以块的形式靠近的块父节点。 如果有位置信息,它会按照以下四个目标进行打包:

(1) 平衡组,使它们大致具有相同数量的父分区

(2) 实现每个分区的局部性,即找到一台大多数父分区更喜欢的机器

(3) 高效,即 n 个父分区的 O(n) 算法(问题可能是 NP-hard)

(4) 平衡首选机器,即尽可能避免选择相同的首选机器

【讨论】:

  • 不幸的是,根据经验,我可以看到我的数据以良好的分区均匀分布开始,并以不均匀分布结束。这些数字与帖子中的数字略有不同,但原始数据帧有 768 个分区,每个分区平均有 294k 条记录,方差非常小。合并后的最终数据帧有 48 个分区 - 其中一些分区包含来自原始分区中少至 13 个的数据,而其他分区则来自多达 19 个分区,记录数量也有相应的变化。
  • 如果重要的话,我正在使用 PySpark,我的 sparkContext.version 报告为 2.2.0。
  • 听起来像一个错误,记录的行为是不同的。我会为此开张票。另外,分区是如何分布在集群中的?也许合并还考虑到分区的物理位置并尝试为此进行优化。
  • 我编辑了我的答案:似乎我的直觉可以为您指明正确的方向。检查分区在不同机器中的分布情况,位置信息可能会影响新分区从旧分区派生的方式。
  • 非常感谢您的回答,但目前还不清楚如何进一步挖掘,因为我不知道如何找到分区的首选位置。我在这里问了一个问题:stackoverflow.com/questions/50872579/….
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-25
  • 2013-06-25
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多