基本的二次排序,以按照两个字段排序为例。先按第一字段升序,再按第二字段降序。二次排序的核心是把原来的key--value对组合成key,称为newkey,value还是value。与原来的wordcount相比,多了一个“分组”步骤,就是把newkey中的第一个字段相同的数据放到一起,再按第二个字段排序。
如图,pre-map阶段,namenode切分文件后,再把文件内容按行(\n)分割,距行首的偏移量作为key值,这一行的内容作为value。这样形成初始的key-value对。
map过程:进入map方法的数据是文件的一行行内容,通过我们自己编程,按照空格切分,然后把前两个字段置为newkey,第二个字段置为value,之后,进行分区过程,按照newkey中的key进行分区,分区依据是key.hashcode%reducenum,得到相同结果的分配到同一个分区,然后分区内进行按照newkey第一字段排序(sort)。
reduce过程:数据被fetch到reduce中,同一个分区号的数据被放到一起,同时进行排序(sort)和聚合(merge),此时的排序是按照第二字段排序的,排序之后,进行分组过程,newkey中key相同的被分配到同一组。我们自己编写reduce方法时,把newkey中的第一字段提取出来作为key,value不变,这样就而完成了二次排序。
代码实现:
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
// 启动mr的driver类
public class SecondSortV3 {
/**
* 自定义的newKey
*/
public static class KeyPairWritable implements
WritableComparable {
// 组合key,key1是分区key,key2是二次排序key
private String key1;
private int key2;
public KeyPairWritable() {
}
public KeyPairWritable(String key1, int key2) {
this.set(key1, key2);
}
// 一次性将两个key设置成完
public void set(String key1, int key2) {
this.key1 = key1;
this.key2 = key2;
}
// 当map端写出的时候的序列化方法,即map如何将对象写出去,保证与读取的顺序一致
@Override
public void write(DataOutput arg0) throws IOException {
arg0.writeUTF(key1);
arg0.writeInt(key2);
}
// 在reducer读取数据时候的反序列化方法,即reduce如何将对象读取出来,保证与写入的顺序一致
@Override
public void readFields(DataInput arg0) throws IOException {
this.key1 = arg0.readUTF();
this.key2 = arg0.readInt();
}
// 自定义比较器方法,先比较key1,确定分区号。在分区号相同的情况下,去比较key2
// 就不需要单独写一个Comparator了
public int compareTo(KeyPairWritable o) {
int compare = this.key1.compareTo(o.key1);
if (compare != 0) {
return compare;
} else {
// 降序排列,故将o放到前边即可
return Integer.valueOf(o.key2).compareTo(
Integer.valueOf(this.getkey2()));
}
}
public int getkey2() {
return key2;
}
public void setkey2(int key2) {
this.key2 = key2;
}
public String getkey1() {
return key1;
}
public void setkey1(String key1) {
this.key1 = key1;
}
}
// map类,实现map函数
public static class LineProcessMapper extends
Mapper
编写完毕,打好jar包,提交到hdfs集群上,然后执行,执行的时候要用到系统参数
yarn jar TlHadoopCore-jar-with-dependencies.jar \
com.Mrs_WuHo_O.examples.secondsort.SecondSortV3 \
-Dmapred.output.compress=true \
-Dmapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec \
-Dmapred.reduce.tasks=1 \
/tmp/Mrs_WuHo_O/input_secondsort /tmp/tianliangedu/output55