当k个元素不适合内存时,mapreduce中的top-k

时间:2014-07-11 07:11:02

标签: algorithm sorting hadoop mapreduce

当k太大而无法在内存中拟合k个元素时,从数据集中查找top-k元素的有效MapReduce算法是什么?我说的是数百万个元素的数据集,而k是例如其中3/4。想象一下,每个元素都有一个值,我们想要找到具有最高值的k个元素。

E.g。表格中的数据:

  

e1:5

     

e2:10

     

e3:7

     

e4:8

然后,前2名是e4和e2(不关心他们的相关顺序)。

我见过the solution to the problem, when k is small enough,但它没有扩展。 显然,使用单个减速器,再次不实用(内存不足错误)。

3 个答案:

答案 0 :(得分:1)

您需要两种MR工作方式:

第一份工作:

在映射器中执行您描述的逻辑以在reducer中获取分组计数。 然后,reducer将计数(作为键)写入键值对(作为值)。这里的reducer可以并行化,以防你遇到性能问题。

第二份工作:

映射器只是映射身份。通过定义倒置比较器来处理降序排序。

此处的单个reducer获取降序排序数据。 然后你可以简单地增加,直到你击中" k"并发出值。

请注意,您可能拥有相同计数的项目,因此您需要将从减少的值中获得的每个值计为新的" k"。

答案 1 :(得分:0)

这可能不是 最有效,但它易于理解且易于实施。

MapReduce Stage-1: 将减速器数量设置为1。

  • 地图:读取输入(键k,值v)对并将它们发送到 减速器,键为v,值为k。
  • Reduce:sh​​uffle阶段将根据数值对数据进行排序(因为它们是键),因为数据是通过 网络。数据将到达reducer,reducer将按排序顺序输出单个文件。

MapReduce Stage-2:不需要减少阶段。

  • Map:读取单个已排序的文件并输出前k个元素。

如果要选择k为百分比的前k,则可以在Stage-1映射阶段使用Hadoop counter来计算输入文件中存在的记录数,然后在其中使用另一个计数器Stage-2选择前k%。

答案 2 :(得分:0)

我认为我找到了我想要的东西。答案在这里找到: http://www.philippeadjiman.com/blog/2009/12/20/hadoop-tutorial-series-issue-2-getting-started-with-customized-partitioning/

想法是使用TotalOrderParitioner。此分区器首先需要采样,可以使用InputSampler生成,例如RandomSampler。我相信,此采样用于负载平衡,以确保所有减速器将获得几乎相同的工作量(数据)。

默认分区程序(hashPartitioner)的问题在于,(键,值)对最终的reducer基于键的哈希值。然后,排序发生在每个减速器的输入中。这并不能保证“跟随”减速器可以处理更大的密钥。 TotalOrderPartitioner保证后者,并且采样用于负载平衡。

数据完全排序后,我们可以取最后一个k(例如,在tail -k的结果中使用unix中的hadoop dfs -getmerge命令),或者使用倒置比较器并取正如Thomas Jungblut所暗示的那样,第一个k。如果不正确,请随意评论/编辑我的答案。

编辑:提供了一个更好的示例(就源代码而言)here

编辑2:看起来这个问题毕竟是一个“经典”问题,汤姆怀特的书“Hadoop the Definitive Guide”(第1版第223页)的“总排序”一节中也描述了这个解决方案。 。您也可以关注this link进行免费预览。