火花重新分配落入单一分区

时间:2018-01-27 11:55:33

标签: apache-spark pyspark

我正在学习spark,当我使用下面的表达式在pyspark shell中测试repartition()函数时,我发现了一个非常奇怪的结果:所有元素在repartition()函数之后都属于同一个分区。 在这里,我使用glom()来了解rdd中的分区。我期待repartition()洗牌元素并在分区之间随机分配。只有当我使用新的分区数< =原始分区重新分区时才会发生这种情况。

在我的测试中,如果我设置了新的分区数>原来的分区,也没有观察到洗牌。我在这里做错了吗?

In [1]: sc.parallelize(range(20), 8).glom().collect()
Out[1]:
[[0, 1],
 [2, 3],
 [4, 5],
 [6, 7, 8, 9],
 [10, 11],
 [12, 13],
 [14, 15],
 [16, 17, 18, 19]]

In [2]: sc.parallelize(range(20), 8).repartition(8).glom().collect()
Out[2]:
[[],
 [],
 [],
 [],
 [],
 [],
 [2, 3, 6, 7, 8, 9, 14, 15, 16, 17, 18, 19, 0, 1, 12, 13, 4, 5, 10, 11],
 []]

In [3]: sc.parallelize(range(20), 8).repartition(10).glom().collect()
Out[3]:
[[],
 [0, 1],
 [14, 15],
 [10, 11],
 [],
 [6, 7, 8, 9],
 [2, 3],
 [16, 17, 18, 19],
 [12, 13],
 [4, 5]]

我正在使用spark版本2.1.1。

2 个答案:

答案 0 :(得分:2)

恭喜!您刚重新发现SPARK-21782 - 当numPartitions为2的幂时,重新分区会产生偏差

  

目前,重新分区算法(启用随机播放的合并)如下:

     

对于每个初始分区索引,生成位置为(new Random(index))。nextInt(numPartitions)       然后,对于初始分区索引中的元素号k,将其放入新分区位置+ k(模数numPartitions)。

     

因此,基本上元素在numPartitions桶上大致相同 - 从数字位置+ 1开始。

     

请注意,为每个初始分区索引创建一个新的Random实例,并使用固定的种子索引,然后将其丢弃。因此,对于世界上任何RDD的每个指数,该位置都是确定性的。此外,nextInt(绑定)实现有一个特殊情况,当bound是2的幂时,它基本上从初始种子中获取几个最高位,只有最小的加扰。

PySpark使情况变得更糟,因为它uses batched serializer的默认批量大小等于10,所以每个分区上的项目数量都很少,所有这些都被拖拽到相同的输出。

好消息是,already resolved in Spark 2.3感谢Sergey Serebryakov

答案 1 :(得分:0)

啊,我认为与底层分区程序有关。我尝试了更大的数字,现在结果更有意义。

In [95]: [len(lst) for lst in sc.parallelize(range(1000), 8).glom().collect()]
Out[95]: [125, 125, 125, 125, 125, 125, 125, 125]

In [96]: [len(lst) for lst in sc.parallelize(range(1000), 8).repartition(10).glom().collect()]
Out[96]: [95, 95, 100, 105, 95, 95, 100, 105, 105, 105]

In [97]: [len(lst) for lst in sc.parallelize(range(1000), 8).repartition(5).glom().collect()]
Out[97]: [190, 195, 205, 210, 200]
相关问题