我们的reduceByKey
操作的结果导致RDD
非常偏斜,在一个或两个分区中有大量数据。在reduceByKey
我们执行repartition
之后增加处理的并行性,这会强制进行随机播放。
rdd.reduceByKey(_+_).repartition(64)
我知道可以将分区程序传递到reduceByKey
操作系统。但是(除了创建自定义之外)我认为选项是HashPartioner
和RangePartitioner
。我认为这些都会导致数据在分区后出现偏差,因为密钥非常独特。
是否可以在RDD
内均匀地混合输出reduceByKey
,而无需额外repartition
来电?
答案 0 :(得分:2)
你的假设: "我认为选项是HashPartioner和RangePartitioner。我认为这些都会导致数据在分区后出现偏差,因为密钥非常独特。" 不一定正确。
标准RangePartitioner
尝试通过抽样均匀分布数据,在我们的情况下,使用非常偏斜的数据(取决于人的地理分布),结果非常好,并均匀分布数据。
另请参阅此处的说明:How does range partitioner work in Spark?
所以我建议在reducyByKey中使用标准RangePartitioner
。
编写一个小测试或记录输出,用于检查分区的大小。
您可以使用mapPartitionsWithIndex
收集有关分区的一些统计信息,并为日志记录输出提供Id。
答案 1 :(得分:0)
我假设您在某些地区使用reduceByKey聚类后拥有密钥。例如,1,2,3,4,5,45,46,47,48,49,356,789。
因此,当您使用rangePartitioner时,您将有偏差数据。但是HashPartitioner依赖于用于计算密钥哈希值的哈希函数。
(Scala RDD可能使用hashCode,DataSet使用MurmurHash 3,PySpark,portable_hash)。
现在,如果默认的hashPartitioner也给你数据倾斜,那么你将不得不使用自定义分区器并使用一些好的散列分区器来应用散列,这肯定会产生稀疏散列,例如MD5。
要在spark中实现自定义分区程序,您必须扩展分区程序并实现3种方法:
getPartition
在getPartition方法中,您可以计算密钥的md5哈希值,并根据numPartitions参数进行分配。
您还可以查看Zero323的答案。
答案 2 :(得分:-1)
帕特里克,
我不知道您是否可以访问Spark UI。但是,如果您需要对RDD进行重新分区,我建议您使用numPartitions
的方法添加
这个你可以“免费”改组你的rdd。
如果您可以检查您的Spark用户界面,如果您使用,则显示:
rdd.reduceByKey(_+_).repartition(64)
您将看到执行图表,将执行reduce,之后将重新开始重新分区。
如果您使用:
rdd.reduceByKey(_+_, numPartitions=64)
您将看到执行将在没有任何额外工作的情况下发生。
以下是使用方法:Spark ReduceByKey