序列化
就是把内存中的对象,转换成字节序列
(或其他数据传输协议
)以便于存储到磁盘(持久化)
和网络传输
反序列化
就是将收到字节序列
(或其他数据传输协议
)或者是磁盘的持久化数据
,转换成内存中的对象
—般来说,
“活的”对象
只生存在内存
里,关机断电就没有了。而且“活的”对象只能由本地的进程
使用,不能被发送到网络上的另外一台计算机。然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。也就是将对象序列化
成字节序列
,然后就能被网络传输
或者是存储到磁盘中
,而不是存储在内存
中,在断电以后就会消失
hadoop的信息处理也需要经过序列化,因为数据需要在介质之间传输,但是
hadoop
的序列化是自定义
的,而不是使用Java的序列化
。因为Java
的序列化是一个重量级序列化框架Serializable
),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header
,继承体系等),不便于在网络中高效传输。所以,hadoop
自己开发了一套序列化机制(Writable
)。
hadoop
中数据类型是自定义的
,Java的对于每个基本类型的数在例如参数传递的场景都会经过序列化,但是hadoop
不使用Java
的序列化机制,所以就需要自定义自身的基本数据类型。以下是hadoop
的基本数据类型和Java
的对比
但是仅仅是基本数据类型的序列化是远远不够的,所以需要自行实现
Writable接口
来自定义对象的序列化
Writable接口
无参数构造器
(反序列化时会通过反射
的方式调用无参数构造器
来创建对象)重写write
方法实现序列化的过程(自定义序列化的内容)readFields
方法实现反序列化的过程1、需求分析:统计每一个手机号耗费的总上行流量、下行流量、总流量
2、期望输出:
#手机号 上行流量 下行流量 总流量
13560436666 1126 954 2080
2、测试数据:
#ID 手机号 IP 上行流量 下行流量 网络状态码
1 13560436666 120.196.101.99 1126 954 200
2 13560436667 120.196.102.99 1136 954 200
3 13560436668 120.196.103.99 1146 954 200
4 13560436669 120.196.104.99 1156 954 200
5 13560436676 120.196.105.99 1166 954 200
6 13560436686 120.196.106.99 1176 954 200
7 13560436666 120.196.107.99 1126 954 200
8 13560436667 120.196.108.99 1136 954 200
9 13560436668 120.196.109.99 1146 954 200
3、实现思路:在map
阶段会将每一行数据按空格进行切分,切分出手机号后,将对应的上行流量以及下行流量处理到一个bean对象
,然后序列化输出。虽然是可以使用其他方法,但是这里仅就对序列化学习。对于简单的MapReduce程序
编写可以看这里:MapReduce学习2-1:以官方wordcount实例为例的MapReduce程序学习
对于
mapper程序
通过context.write
方法进行参数传递过程中会有一个写入磁盘的过程,所以需要序列化,对于hadoop
的基本数据类型是已经实现了序列化而无需自行处理,但是对于其他对象就需要自行实现Writable接口
4、创建FlowBean类
并实现Writable接口
package com.writable.maven;
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class FlowBean implements Writable {
// 上行流量、下行流量和总流量
private Long upFlow;
private Long downFlow;
private Long sumFlow;
FlowBean(){
}
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 void setSumFlow(){
this.sumFlow = this.upFlow + this.downFlow;
}
public Long getSumFlow() {
return sumFlow;
}
public void setSumFlow(Long sumFlow) {
this.sumFlow = sumFlow;
}
// 实现Writable接口必须实现该方法,用以将数据序列化输出,输出顺序为执行顺序以及类型也为设置的类型,如下
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(this.upFlow);
out.writeLong(this.downFlow);
out.writeLong(this.sumFlow);
}
// 实现Writable接口必须实现该方法,用以将数据反序列化输出,执行顺序以及类型也为设置的类型与write方法相适应
@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 this.upFlow + "\t" + this.downFlow + "\t" + this.sumFlow;
}
}
5、创建FlowMapper类
package com.writable.maven;
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 flowBean = new FlowBean();
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// super.map(key, value, context);
// 获取一行
String line = value.toString();
// 按空白分割一行
String[] parts = line.split("\\s+");
outK.set(parts[1]);
flowBean.setUpFlow(Long.parseLong(parts[parts.length-3]));
flowBean.setDownFlow(Long.parseLong(parts[parts.length-2]));
flowBean.setSumFlow();
context.write(outK, flowBean);
}
}
6、创建FlowReducer
类
package com.writable.maven;
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 flowBean = new FlowBean();
@Override
protected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {
// super.reduce(key, values, context);
Long sumUpFlow = 0L;
Long sumDownFlow = 0L;
for (FlowBean fb: values){
sumUpFlow += fb.getUpFlow();
sumDownFlow += fb.getDownFlow();
}
flowBean.setUpFlow(sumUpFlow);
flowBean.setDownFlow(sumDownFlow);
flowBean.setSumFlow();
context.write(key, flowBean);
}
}
7、创建FlowDriver
类
package com.writable.maven;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
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 {
Configuration conf = new Configuration();
Job job = new Job(conf);
job.setJarByClass(FlowDriver.class);
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class);
// 这里仅做本地测试
FileInputFormat.setInputPaths(job, new Path("E:\\bigdata\\study\\test_files\\flowinput\\flow.txt"));
FileOutputFormat.setOutputPath(job, new Path("E:\\bigdata\\study\\test_files\\flowoutput"));
job.waitForCompletion(true);
}
}
上述代码不多做解释,如需详细了解可看这里:MapReduce学习2-1:以官方wordcount实例为例的MapReduce程序学习