MapReduce 之 排序


    排序是MapReduce核心技术,尽管实际应用中可能不需要对数据进行排序,但是MapReduce过程本身就含有排序的概念。

MapReduce的排序是默认按照Key排序的,也就是说输出的时候,key会按照大小或字典顺序来输出,比如一个简单的wordcount,出现的结果也会是左侧的字母按照字典顺序排列。

 

1)排序的分类:

1)部分排序MapReduce中默认的排序方式,默认输出是按照键的自然顺序排列,这种方法很简单,因为你只需要重写map函数和reduce函数就可以,剩下的一切MapReduce已经帮你做好了。基于上面的情况,我们会发现结果集只有一个文件,因为MapReduce默认启动Reduce Task的个数是一个。现在我们通过job.setNumReduceTasks(n),来改变我们reduce的个数,在n等于2的情况下,那么一个Wordcount可能的输出就会是一个reduce内有序,也就是说最后产生的两个结果文件,它们只是在内部有序,两个文件之间却不是有序的,所以这也叫部分排序。

那么为什么会产生这样的结果?因为Reduce接受Map穿过来的数据,接受到的时候已经排好序了。

如何改善这种结果,我们便有了全局排序。

 

2)全排序:

        什么是全局排序,通俗的说,就是最终无论产生多少个结果文件,后一个的第一个键在自然顺序上总是大于/小于前一个的最后一个键。这时候,我们就要用到分区。MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部排序。

        如何用Hadoop产生一个全局排序的文件?最简单的方法是使用一个分区。MapReduce默认只是保证同一个分区内的Key是有序的,但是不保证全局有序。如果我们将所有的数据全部发送到一个Reduce在只是用一个分区时MapReduce的只需要将jobNumReduceTasks设置为1即可:job.setNumReduceTasks(1);

        MapReduce只是用一个分区处理大型文件时有个很大的局限性,所有的数据都发送到一个Reduce进行排序,这样不能充分利用集群的计算资源,而且在数据量很大的情况下,很有可能会出现OOM问题,而且效率很低,因为一台机器必须处理所有输出文件,从而完全丧失了MapReduce所提供的并行架构。

        我们分析一下,MapReduce默认的分区函数是HashPartitioner,其实现的原理是计算map输出key hashCode ,然后对Reduce个数求模,这样只要求模结果一样的Key都会发送到同一个Reduce。如果我们能够实现一个分区函数,以实现MapReduce的全排序,如下是其替代方案:

        替代方案:首先创建一系列排好序的文件;其次,串联这些文件;最后,生成一个全局排序的文件。主要思路是使用一个分区来描述输出的全局排序。例如:就以上提到的wordcount示例,按字母顺序输出各个单词的数量,我们可以为待分析单词文件创建3个分区,在第一分区中,记录的单词首字母a-g,第二分区记录单词首字母h-n, 第三分区记录单词首字母o-z。如果需要跟多的分区可以对各个分区进行细分。

 

怎么确定索引的范围

        列出键的所有的可能取的值,这个种类就是索引的个数 
如果键的可能的取值是无穷尽的,那么试图寻找出键的某一部分的所有的可能的取值(在排序上是不同的)

 

实现步骤

        1):使用WritableComparable实现对键进行排序,或者实现自定义的Comparator,实现compareTo方法
        2)
:定义一个方法将Reducer实例转换为一个索引值 (此步骤非必须,可根据实际情况来)
        3)
:实现一个自定义的Partitioner 应该清楚整个Reducer键的索引范围 利用键的索引将实例分配给相应的Reducer

    原文作者:hochoy
    原文地址: https://blog.csdn.net/hochoy/article/details/80202522
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞