Spark分区器HashPartitioner和RangePartitioner/全局排序

Spark分区器

  在Spark中分区器直接决定了RDD中分区的个数,RDD中每条数据经过Shuffle过程属于哪个分区以及Reduce的个数。只有Key-Value类型的RDD才有分区的,非Key-Value类型的RDD分区的值是None的。
  在Spark中,存在两类分区函数:HashPartitionerRangePartitioner,它们都是继承自Partitioner,主要提供了每个RDD有几个分区(numPartitions)以及对于给定的值返回一个分区ID(0~numPartitions-1),也就是决定这个值是属于那个分区的。

HashPartitioner分区

  HashPartitioner分区的原理很简单,对于给定的key,计算其hashCode,并除于分区的个数取余,最后返回的值就是这个key所属的分区ID。

RangePartitioner分区

  从HashPartitioner分区的实现原理可以看出,其结果可能导致每个分区中数据量的不均匀。而RangePartitioner分区则尽量保证每个分区中数据量的均匀,而且分区与分区之间是有序的,但是分区内的元素是不能保证顺序的。sortByKey底层就是RangePartitioner分区器。
  首先了解蓄水池抽样(Reservoir Sampling),它能够在O(n)时间内对n个数据进行等概率随机抽取。首先构建一个可放k个元素的蓄水池,将序列的前k个元素放入蓄水池中。然后从第k+1个元素开始,以k/n的概率来替换掉蓄水池中国的某个元素即可。当遍历完所有元素之后,就可以得到随机挑选出的k个元素,复杂度为O(n)。
  RangePartitioner分区器的主要作用就是将一定范围内的数映射到某一个分区内。该分区器的实现方式主要是通过两个步骤来实现的,第一步,先从整个RDD中抽取出样本数据,将样本数据排序,计算出每个分区的最大key值,形成一个Array[KEY]类型的数组变量rangeBounds;第二步,判断key在rangeBounds中所处的范围,给出该key的分区ID。

RangePartitioner的重点是在于构建rangeBounds数组对象,主要步骤是:

  1. 计算总体的数据抽样大小sampleSize,计算规则是:(math.min(20.0 * partitions, 1e6)),至少每个分区抽取20个数据或者最多1M的数据量
  2. 根据sampleSize和分区数量计算每个分区的数据抽样样本数量sampleSizePrePartition(math.ceil(3.0 * sampleSi

你可能感兴趣的:(Spark)