Hadoop二次排序总结

最近学习hadoop二次排序,在此对自己总结的内容做些记录,首先是Map端:

1.自定义数据类型CombinationKey -> 重组后的数据类型(将原始数据Key,Value组合)

实现WritableComparable接口,其中writableComparable继承Writable、Comparable接口,所以重整后的Key需要实现:

  a.Writable接口(输入输出)

public interface Writable {
  void write(DataOutput out) throws IOException;
  void readFields(DataInput in) throws IOException;
}

在IntWritable中的实现如下:

@Override
  public void readFields(DataInput in) throws IOException {
    value = in.readInt();
  }
  @Override
  public void write(DataOutput out) throws IOException {
    out.writeInt(value);
  }

  b.Comparable接口

@Override
  public boolean equals(Object o) {
    if (!(o instanceof IntWritable))
      return false;
    IntWritable other = (IntWritable)o;
    return this.value == other.value;
  }

  @Override
  public int hashCode() {
    return value;
  }

  /** Compares two IntWritables. */
  @Override
  public int compareTo(IntWritable o) {
    int thisValue = this.value;
    int thatValue = o.value;
    return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1));
  }

2.自定义分区器Partition

如果不对新组合Key定义分区器,hadoop分区时将默认比较整个Key值,而这里我们只需要其依据原始数据的Key值对数据进行分区。

因此新的分区器只要比较新Key的首列数据,继承Partitioner类,重写getPartition方法

public class DefinedPartition extends Partitioner<CombinationKey, IntWritable>{  
  
    /** 
     * 数据输入来源:map输出 我们这里根据组合键的第一个值作为分区 
     * 如果不自定义分区的话,MapReduce会根据默认的Hash分区方法 
     * 将整个组合键相等的分到一个分区中,这样的话显然不是我们要的效果 
     * @param key map输出键值 
     * @param value map输出value值 
     * @param numPartitions 分区总数,即reduce task个数 
     */  
    public int getPartition(CombinationKey key, IntWritable value, int numPartitions) {    
        return (key.getFirstKey().hashCode() & Integer.MAX_VALUE) % numPartitions;  
    }  
  
}

3.自定义排序器Comparator

分区完成后,需要对组合数据分别排序,排序原则是先根据组合首列值升序排列,然后再根据第二列升序排列

public int compare(WritableComparable a, WritableComparable b) {  
        CombinationKey c1 = (CombinationKey) a;  
        CombinationKey c2 = (CombinationKey) b;  
        int minus = c1.getFirstKey().compareTo(c2.getFirstKey());  
          
        if (minus != 0){   
            return minus;  
        } else {    
            return c1.getSecondKey().get() -c2.getSecondKey().get();  
        }  
    }  

至此Map端暂告一段落,下面是reducer端:

4.自定义分组器GroupSort

依据组合Key的首列分组,每处理一次调用一次reducer来对分组进行输出

@Override  
    public int compare(WritableComparable a, WritableComparable b) {   
        CombinationKey combinationKey1 = (CombinationKey) a;  
        CombinationKey combinationKey2 = (CombinationKey) b;   
        //自定义按原始数据中第一个key分组  
        return combinationKey1.getFirstKey().compareTo(combinationKey2.getFirstKey());  
    }  

5.主体程序部分

a. Mapper

  1)过滤非法数据

  2)设置联合Key值

  3)输出(联合Key值,value值)

b.Reducer

  输出(联合Key值首列值,value值)

c.run

  1)获取配置信息

  2)创建Job任务

  3)设置输入输出路径,因为MapReduce输出路径已经存在将不能正常输出的设定,如果是固定输出路径,此处可增加输出路径文件系统是否存在的判断

  4)设置Map类和map方法的输出Key,value类型

  5)设置分区器 job.setPartitionerClass

  6)设置分组策略job.setGroupingComparatorClass

  7)设置比较策略job.setSortComparatorClass

  8)设置Reducer类和reduce方法的输出类型

  9)提交作业job.waitForCompletion(true)

d.main方法

  1)创建配置

  2)获取或指定输入输出路径(此处可以run方法中直接指定)

  3)调用ToolRunner.run方法

  4)退出 System.exit

 

学习中https://blog.csdn.net/lzm1340458776/article/details/42875751帮助很大,本文多处涉及到,在此特别感谢,受益匪浅,谢谢。

posted @ 2018-05-23 11:17  FightingNoob  阅读(682)  评论(0)    收藏  举报