如何使用Map / Reduce选择随机(小)数据样本?

时间:2010-03-25 08:48:16

标签: hadoop mapreduce hbase random-sample

我想编写一个map / reduce作业,根据行级条件从大型数据集中选择一些随机样本。我想最小化中间键的数量。

伪代码:

for each row 
  if row matches condition
    put the row.id in the bucket if the bucket is not already large enough
你做过这样的事吗?有没有众所周知的算法?

包含连续行的样本也足够好。

感谢。

3 个答案:

答案 0 :(得分:11)

映射器: 输出所有符合条件的值,每个值都带有一个随机整数键。

单减速机: 输出前N个值,扔掉钥匙。

分拣机将为您随机化映射器输出顺序。您不知道映射器将找到多少个限定值,因此每个映射器必须从其分区输出所有合格值。

一般来说,我喜欢建立这样简单的映射器/缩减器工具,尽可能多地使用Hadoop机器;我最终在不同的任务中重复使用它们。

答案 1 :(得分:8)

Karl的方法运行得很好,但我们可以大大减少映射器生成的数据量。

K 您想要的样本数量。我们假设它足够小,可以保存在你的一个节点上。我们将为每个匹配的行分配一个随机值,然后使用selection algorithm的修改来查找 K 最小值。

在每个映射器的设置部分,创建一个priority queue; Fibonnacci heap是一个很好的选择。我们将使用花车作为优先事项;如果你有大量的数据,双打可能更适合避免存在关系。对于符合条件的每一行,将该行插入优先级队列,并将随机选择的0到1之间的浮点作为优先级。如果队列中有超过 K 的内容,请删除值最高的项(这与标准Fibonnacci堆的术语相反)。

最后,在映射器的末尾,发出队列中的所有内容。对于您发出的每个项目,将优先级用作关键字FloatWritable,并将相应行的某些表示形式用作值(行ID,或者可能是整行内容)。每个映射器只会发出 K 值(如果该映射器中的 K 匹配行少于 K ,则会更少)。

在您的单个缩减器中,Hadoop将按从低到高的顺序自动扫描键。发出与您看到的第一个 K 键对应的行( K 最低),然后退出。

这是有效的,因为每个匹配的行具有 K 最小浮点值之一的相同概率。我们跟踪每个映射器的 K 最小浮点数,以确保我们不会错过任何映射器,然后将它们发送到reducer以找到 K 最小的整体。< / p>

答案 2 :(得分:2)

Bkkbrad的方法可能是最有效的,因为从每个映射器发出的记录数量(最多)是K.另一方面,请注意它假设样本本身(即K元素)适合记忆一个减速机。

如果不是这种情况,您可能会想要简单地使用完全分布式方法,其中每个匹配行由映射器分配{1,..,K}中的随机整数,然后reduce阶段选择一个元素每个键(也见this question)。然而,这种方法的问题在于,可能是偶然没有为某些键分配行的情况,在这种情况下,最终样本将具有少于K个元素。即使这种情况发生的概率很小,如果K远小于总行数N,如果K是N的常数分数(例如当K = N / 3)时,它将以恒定的概率发生。

有效的解决方案如下:假设我们有B桶并首先通过将每个元素放在随机桶中然后在每个桶中生成随机排序来生成元素的随机排序。第一个桶中的元素被认为比第二个桶中的元素更小(相对于排序),依此类推。然后,如果我们想要选择大小为K的样本,我们可以收集前j个桶中的所有元素,如果它们总体上包含多个小于K的元素,然后从下一个桶中选择剩余的K-t元素。这里B是一个参数,使得N / B元素适合存储器。关键方面是可以并行处理存储桶。

Mapper:输出所有符合条件的行,每行包含一个随机键(j,r),其中j是{1,..,B}中的随机整数,r是随机浮点数。另外,跟踪密钥小于j的元素的数量(对于1 <= j <= B)并将该信息发送给减速器。

随机播放:对j进行分区,对r进行二次排序。

Reducer:考虑桶j并假设reducer知道桶中的元素数少于j以及桶j中的数量(通过聚合映射器接收的信息)。如果桶中小于或等于j的元素数小于或等于K,则输出桶j中的所有元素;如果具有严格小于j的桶的元素的数量是t

我不知道这个问题有一个更简单的解决方案,但是如果有的话会很好。

您可以找到更多详情here on my blog