四,MapReduce中的排序

  

一、排序概述

  

1,在MapReduce的洗牌过程中执行了三次排序,分别是:
地图的溢写阶段:根据分区以及关键进行快速排序
地图的合并溢写文件:将同一个分区的多个溢写文件进行归并排序,合成大的溢写文件
减少输入阶段:将同一分区,来自不同地图任务的数据文件进行归并排序

  

2,在MapReduce整个过程中,默认是会对输出的KV对按照关键进行排序的,而且是使用快速排序。
地图输出的排序的,其实也就是上面的溢写过程中的排序。
减少输出的排序,即减少处理完数据后,MapReduce内部会自动对输出的KV按照关键进行排序

  

以上排序都是根据KV中关键的进行排序的,所以当我们自定义的类作为关键时,需要实现WritableComparable接口,也就是实现里面的compareTo()方法,用于排序时进行比较。
比较规则如下:

  
 <代码>公共int compareTo(对象){
  this>其他返回1,正序,返回1,逆序。
  } 
  

二、二次排序的定义

  

而在依据关键进行排序时,如果关键是一个复合对象,即该对象中包含多个成员属性,那么在进行关键比较时,就会涉及到多个属性间的比较,而如果compareTo()方法中,比较条件为两个的话,就称为<强>二次排序

  

三、辅助排序的定义

  

辅助排序也叫分组排序,是指在减少前的组织过程中根据排序规则进行的分组,因为分组的时候是需要比较KV中关键是否相同,如果相同才会归为同一个组,如果不相等,就归为不同的组,所以就涉及到关键比较方法了。总的来说其实定义关键在什么情况下才相等。这个过程可以自己定义分组的方法,也就是分组排序的实现类。
使用方法:
1,自定义分组类,继承WritableComparator
2,调用父类的构造方法,创建实例
3,重写父类的比较方法

  

例子:   

 <代码类="语言java ">公共类OrderGroupCompartor延伸WritableComparator {
  
  保护OrderGroupCompartor () {
  超级(OrderBean。类,真实);
  }/* *
  *以orderbean对象中的ID为分组依据。
  *同一ID的认为是同一个组,一个组只会调用一次减少
  *
  * @param比较对象1
  * @param b比较对象2
  * @return
  */@Override
  公共int比较(WritableComparable, WritableComparable b) {
  OrderBean aOrderBean=(OrderBean);
  OrderBean bOrderBean=b (OrderBean);
  
  如果(aOrderBean.getID()在bOrderBean.getID ()) {
  返回1;
  }else if (aOrderBean.getID () & lt;bOrderBean.getID ()) {
  返回1;
  其他}{
  返回0;
  }
  }
  } 
  

我们要注意的是,在进行分组时,同一个分组内的关键是以第一个进入该分区的KV对中的关键为准的。如:

  
 <代码>有两个KV对:
  1、& lt;[1,裤子),20比;
  2、& lt;[1,袜子),21比;
  其中键由id和物品名称组成的,价值则是物品价格
  假设分组依据是根据中关键的id来分组的,那么上面两个KV是属于同一个组,但是实际上这两个千伏
  的关键是不相等的,当1号KV先进入该集团,那么就会以1号的关键作为该集团的关键,分组的结果为:
  & lt;[1,裤子),(20、21)比;
  如果2号KV先进入,则按照前面的规则,分组结果为:
  & lt;[1,袜子),(20、21)比;
  
  就会有这样的情况的发生,我们要注意利用好这点。 
  

那么谁先进入该集团的呢?很简单,是按照事先排序的顺序,在前面的自然先进入。这里的排序其实就是前面减少端的归并排序的结果,而使用的排序依据其实就是关键的包装类中compareTo方法,属于普通排序里面的东西。

  

编写好自定义的分组排序类之后,需要在工作中指定好自定义的分组类:

  
 <代码> job.setGroupingComparatorClass (OrderGroupCompartor.class);  
  

四、排序实例

  

普通排序请看“MapReduce——统计手机号流量”
二次排序和辅助排序请看“MapReduce——获取价格最高的商品”

四,MapReduce中的排序