MapReduce中的排序
1 默认排序
在mapTask到reduceTask之间,框架默认的添加了排序功能。
默认的排序规则是:按照map端输出的key的字典序排序(升序)。
比如:想将WordCount中词频出现的次数,按由低到高进行排序;就可以将词频字段放在map输出的key的位置上,就可以实现按词频排序。
2 按自定义的类实现排序
MapReduce也支持按照自定义的类实现排序,具体方法如下:
①创建自定义类,并实现WritableComparable接口,实现接口中未实现的方法;决定排序的方法是:compareTo();
②将自定义的类,放在map输出的key的位置上;
以流量数据为例,现在我想将所有用户的总流量,按倒叙排列,具体实现如下所示:
①创建自定义类,实现WritableComparable接口
package com.ethan.mrsort;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
/**
* @Description 自定义类排序
* @author Ethan
* @date 2020年1月31日
*/
public class FlowBean implements WritableComparable<FlowBean>{
/**
* 电话号码
*/
private String phoneNumber;
/**
* 上行流量
*/
private int upFlow;
/**
* 下行流量
*/
private int downFlow;
/**
* 总流量
*/
private int sumFlow;
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public int getUpFlow() {
return upFlow;
}
public void setUpFlow(int upFlow) {
this.upFlow = upFlow;
}
public int getDownFlow() {
return downFlow;
}
public void setDownFlow(int downFlow) {
this.downFlow = downFlow;
}
public int getSumFlow() {
return sumFlow;
}
public void setSumFlow(int sumFlow) {
this.sumFlow = sumFlow;
}
public FlowBean() {
super();
}
public FlowBean(String phoneNumber, int upFlow, int downFlow, int sumFlow) {
super();
this.phoneNumber = phoneNumber;
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = sumFlow;
}
@Override
public String toString() {
return phoneNumber + "\t" + upFlow + "\t" + downFlow + "\t" + sumFlow;
}
/**
* 写,序列化方法
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(phoneNumber);
out.writeInt(upFlow);
out.writeInt(downFlow);
out.writeInt(sumFlow);
}
/**
* 读,反序列化方法
*/
@Override
public void readFields(DataInput in) throws IOException {
this.phoneNumber = in.readUTF();
this.upFlow = in.readInt();
this.downFlow = in.readInt();
this.sumFlow = in.readInt();
}
/**
* 比较方法
* 需求:按照总流量进行倒叙排序
*/
@Override
public int compareTo(FlowBean o) {
return o.getSumFlow() - this.getSumFlow();
}
}
②将自定义类放在map输出的key的位置上
package com.ethan.mrsort;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/**
* 将FlowBean放在map输出的Key的位置,可实现自定义排序
* @author Ethan
* @date 2020年1月31日
*/
public class MyMapper extends Mapper<LongWritable, Text, FlowBean, NullWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 取出一行的内容,切分,放入FlowBean
String[] infos = value.toString().split("\t");
String phoneNumString = infos[0];
int upFlow = Integer.parseInt(infos[1].trim());
int downFlow = Integer.parseInt(infos[2].trim());
int sumFlow = Integer.parseInt(infos[3].trim());
FlowBean flowBean = new FlowBean(phoneNumString,upFlow,downFlow,sumFlow);
context.write(flowBean, NullWritable.get());
}
}
注意:写操作对应序列化方法;读操作对应反序列化方法;
3 总结
(1)Hadoop中自带的基本数据类型,调用的是自带类型中的compareTo()方法实现排序;
(2)自定义的类型,则是根据自定义类中重写的compareTo()方法进行排序的;
(3)排序时尽量不要在reduce端进行排序,影响性能。