一、MapReduce的编码规范
1、键值对输入输出
继承Mapper和Reducer的子类的入口和出口都是键值对
2、Mapper端
入口键值对为切片的行偏移量和行内容,一行内容就是一个Mapper对象;
在Mapper对象里的map()方法中将行的内容解析成N个新的键值对输出;
3、Reducer端
Reducer端从所有的Mapper端获取属于该分区的键值并根据键group分组,一个分组一个Reducer对象;
在Reducer对象的reduce()方法中对该组数据进行聚合后以键值对输出;
二、传输类型序列化
序列化和反序列化是什么:
序列化是把对象转化为字节流,写入到输出流中的过程;反序列化是读取字节流,反序列化为对象的过程
1、传输类型为什么要使用序列化
支持序列化的传输类型才可能以流的方式在节点间传输和写盘
2、MapReduce常用序列化类型
Java 类型——Hadoop Writable 类型
boolean——BooleanWritable
byte——ByteWritable
int——IntWritable
float——FloatWritable
long——LongWritable
double——DoubleWritable
string——Text
map——MapWritable
array——ArrayWritable
三、自定义序列化
自定义 bean 对象要想序列化传输,必须实现序列化接口,需要注意以下几项。
1、必须实现 Writable 接口
避免使用java的Serializable接口,使得序列化过程太重
public class COBean implements Writable {
private String customerId;
private String orderId;
private String customerName;
private String orderStatus;
private int flag;
2、反序列化时,需要反射调用空参构造函数,所以必须有空参构造。
public COBean() {
}
3、重写序列化方法
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeUTF(customerId);
dataOutput.writeUTF(customerName);
dataOutput.writeUTF(orderId);
dataOutput.writeUTF(orderStatus);
dataOutput.writeInt(flag);
}
4、重写反序列化方法
@Override
public void readFields(DataInput dataInput) throws IOException {
this.customerId=dataInput.readUTF();
this.customerName=dataInput.readUTF();
this.orderId=dataInput.readUTF();
this.orderStatus=dataInput.readUTF();
this.flag=dataInput.readInt();
}
5、注意反序列化的字段顺序和序列化的字段顺序完全一致
6、要想把结果显示在文件中,需要重写 toString(),可用”\t”分开
@Override
public String toString() {
return orderId+"\t"+customerName+"\t"+orderStatus;
}
7、自定义键类型必须同时实现WritableComparable接口
因为 MapReduce 中的 shuffle 过程一定会对 Key进行排序,所以还需要实现comparable接口,实现其中的compareTo()方法。
四、Driver提交任务代码
//1、获取配置信息以及创建任务
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2、指定Driver类程序jar所在的路径
job.setJarByClass(FlowDriver.class);
//3、指定Mapper和Reducer
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReduce.class);
//4、指定Partitioner分区类
job.setPartitionerClass(MyPartitioner.class);
//5、指定Mapper端的输出类型kv
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class);
//6、指定最终的结果输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class);
//7、指定输入文件和输出文件的路径
FileInputFormat.setInputPaths(job,new Path("D:\\JavaProjects\\ClassStudy\\Javahigh\\hadooptest\\data\\phone_data\\input"));
FileOutputFormat.setOutputPath(job,new Path("D:\\JavaProjects\\ClassStudy\\Javahigh\\hadooptest\\data\\phone_data\\output"));
//默认使用hashPartitioner,分区数是由reduce task决定
//设置一下reducetask
//如果使用自定义分区,指定了分区数量,那么reducetask不能小于分区数
//如果reduce task数量大于自定义分区数,那么,会有reduce task接收不到数据,浪费资源
job.setNumReduceTasks(5);
//8、提交任务并输出
boolean result = job.waitForCompletion(true);
System.exit(result?0:1);