Bkkbrad 的方法可能是最有效的,因为从每个映射器发出的记录数(最多)为 K。另一方面,请注意它假设样本本身(即 K 个元素)适合内存单个减速器。
如果不是这种情况,您可能会倾向于简单地使用完全分布式方法,其中映射器为每个匹配行分配一个 {1,..,K} 中的随机整数,然后 reduce 阶段选择一个元素每个键(另见this question)。但是,这种方法的问题在于,可能偶然没有将行分配给某些键,在这种情况下,最终样本的元素将少于 K。即使如果 K 远小于总行数 N 时这种情况发生的概率很小,但如果 K 是 N 的一个常数部分(例如当 K=N/3 时),它会以恒定概率发生。
一个可行的解决方案如下:假设我们有 B 个桶,首先将每个元素放入一个随机桶中,然后在每个桶中生成一个随机排序,从而生成元素的随机排序。第一个桶中的元素被认为比第二个桶中的元素小(相对于排序),依此类推。然后,如果我们想选择一个大小为 K 的样本,我们可以收集前 j 个桶中的所有元素,如果它们总体上包含的元素数量 t 小于 K,然后从下一个桶中选择剩余的 K-t 个元素。这里 B 是一个参数,使得 N/B 个元素适合内存。关键是桶可以并行处理。
Mapper:输出所有符合条件的行,每行都有一个随机键 (j, r),其中 j 是 {1,..,B} 中的随机整数,r 是随机浮点数。此外,跟踪 key 小于 j 的元素的数量(对于 1
Shuffle:对 j 进行分区,对 r 进行二次排序。
Reducer:考虑桶 j 并假设 reducer 知道桶中有多少元素小于 j 以及桶 j 中有多少(通过聚合映射器接收到的信息)。如果桶中小于或等于j的元素个数小于或等于K,则输出桶j中的所有元素;如果桶中严格小于 j 的元素数量为 t
我不知道有什么更简单的解决方案可以解决这个问题,但如果有的话就更好了。
您可以找到更多详细信息here on my blog。