序列化概述
(1) 什么是序列化
序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。
反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。
(2)为什么要序列化
一般来说,“活的”对象只生存在内存里,关机断电就没有了。而且“活的”对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机j。 然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。
(3)为什么不用java的序列化
java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于在网络中高效传输。所以,Hadoop自己开发了一套序列化机制(Writable)。
(4)Hadoop序列化特点
紧凑 :高效使用存储空间。
快速:读写数据的额外开销小。
互操作:支持多语言的交互
在Hadoop中提供了序列化类型
自定义序列化
但是只有这些还是远远不够的,我们在开发中经常需要自定义对象也能序列化
自定义对象实现序列化需要实现序列化接口 Writable
步骤分为7步
(1)必须实现Writable接口
(2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造
public FlowBean() {
super();
}
(3) 重写序列化方法
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
}
(4)重写反序列方法
@Override
public void readFields(DataInput in) throws IOException {
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
}
(5)注意序列化 和反序列化的顺序要一致
(6)要想把结果显示在文件中,需要重写toString() 方法。可以用“\t”分开,方便后续使用
(7)如果需要将自定义的bean放在key中传输,还需要实现Comparable接口,因为MapReduce框架中Shuff过程要求对Key能排序。
@Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
序列化案例实操
(2)需求分析
3 编写MapReduce
(1) 编写 流量统计的Bean类
package com.chenxiang.mapreduce.writable;
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/*
*
* 1 定义类实现writable接口
* 2 重写序列化和反序列化方法
* 3 空参构造方法
* 4 toString 方法*/
public class FlowBean implements Writable {
private long upFlow;//上行流量
private long downFlow;//下行流量
private long sumFlow;//总流量
//空参构造
public long getUpFlow() {
return upFlow;
}
public void setUpFlow(long upFlow) {
this.upFlow = upFlow;
}
public long getDownFlow() {
return downFlow;
}
public void setDownFlow(long downFlow) {
this.downFlow=downFlow;
}
public long getSumFlow() {
return sumFlow;
}
public void setSumFlow() {
this.sumFlow= this.upFlow+this.downFlow;
}
public FlowBean() {
}
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
}
@Override
public void readFields(DataInput in) throws IOException {
this.upFlow= in.readLong();
this.downFlow=in.readLong();
this.sumFlow=in.readLong();
}
@Override
public String toString() {
return upFlow+"\t"+downFlow+"\t"+sumFlow; }
}
(2)编写Mapper类
package com.chenxiang.mapreduce.writable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class FlowMapper extends Mapper<LongWritable, Text, Text, FlowBean> {
private Text outK = new Text();
private FlowBean outV = new FlowBean();
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// //获取一行信息
String line = value.toString();
String[] split = line.split("\t");//切割
// 抓取数据
String phone = split[1];
String up = split[split.length - 3];
String down = split[split.length - 2];
//封装
outK.set(phone);
outV.setUpFlow(Long.parseLong(up));
outV.setDownFlow(Long.parseLong(down));
outV.setSumFlow();
// 写出
context.write(outK,outV);
}
}
(3)编写Reducer类
package com.chenxiang.mapreduce.writable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class FlowReducer extends Reducer<Text,FlowBean, Text,FlowBean> {
private FlowBean outV =new FlowBean();
@Override
protected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {
//遍历累加值
long totalUp=0;
long totalDown=0;
for(FlowBean value:values)
{
totalUp+=value.getUpFlow();
totalDown+=value.getDownFlow();
}
//2 封装
outV.setDownFlow(totalDown);
outV.setUpFlow(totalUp);
outV.setSumFlow();
context.write(key,outV);
}
}
(4)编写Driver驱动类
package com.chenxiang.mapreduce.writable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class FlowDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 1 获取job
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2 设置jar
job.setJarByClass(FlowDriver.class);
//3 关联 mapper reducer
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReducer.class);
// 4 设置Mapper输出类型
job.setMapOutputValueClass(FlowBean.class);
job.setMapOutputKeyClass(Text.class);
//设置Mapper最终输出路径
job.setOutputValueClass(FlowBean.class);
job.setOutputKeyClass(Text.class);
//6 设置数据的输入路径和输出路径
FileInputFormat.setInputPaths(job, new Path("D:\\input\\inputflow"));
FileOutputFormat.setOutputPath(job, new Path("D:\\output\\output8"));
//7 提交job
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}