spark中的分区器有三种:
1.HashPartitioner分区可能HashPartitioner导致每个分区中数据量的不均匀。
2.RangePartitioner分区尽量保证每个分区中数据量的均匀,将一定范围内的数映射到某一个分区内。分区与分区之间数据是有序的,但分区内的元素是不能保证顺序的。(这里其实就用到了水塘抽样算法)
3.自定义
那水塘抽样算法是什么呢?能解决什么类型的问题呢?
问题描述:
给定一个数据流,数据流长度N很大,且N直到处理完所有数据之前都不可知,如何在只遍历一遍数据(O(N))的情况下,能够随机选取出这组数据的k个概率相等的均匀抽样。
要求:
- 仅扫描数据一次
- 空间复杂度为O(N),空间复杂度与整个数据量无关,只与抽样大小有关。
- 扫描到数据的前n个数据时(n>k),保存当前已扫描数据的k个均匀抽样。
根据要求,首先体积很大内存一次装不下,不能直接不能直接取N内的k个随机数,因为N的长度是未知的。此外也不能采用不能先遍历一遍,然后分块存储数据,再随机选取。最后要求是数据选取绝对随机的保证。
可以采用水塘抽样算法:
- 如果接受的数据量小于k,则依次放入采样数组中
- 当接收到第i个数据,i大于等于k时,在[0,i]的范围内取一个随机数d 如果d落在了[0,k-1]的范围内,则取接收到的第i个数据替换采样数组中下标等于d位置上的值。
- 重复步骤2
// @param:input 模拟的原始数组
// @param:k 采样的个数
// return:返回采样的数据
import random
def sample(input, k):
res = []
for i in range(len(input)):
if i<k:
res.append(input[i])//先取,前k个数字放在数组里面
else:
//如果i>k,在0和i之间,取一个随机数字,如果这个随机数字小于k,就替换数组,否则就继续遍历,直到结束
rand = random.randint(0, i)
if rand < k:
res[rand] = input[i]
return res
这种算法的能保证概率相等的前提就是: 当数据总量加1的时候,都会在当前总量的范围内,进行生成随机数,这样就能保证范围内的所有的数字出现概率都是相等的,然后根据概率均等随机数字来判断,是否落在了我们采样数组的边界中,如果落到了就替换原来数组中相同的位置的值,如果没有落到,就继续遍历选取,直到所有的数据处理完毕。