Hadoop序列化
序列化:就是把内存中的对象转换成字节序列(或其他数据传输协议),以便于存储到磁盘(持久化)和网络传输。
反序列化:就是将收到的字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。
因为Java自带的序列化存储了很多额外信息(各种校验、Header、继承体系等),是一个重量级序列化框架,不便于在网络中传输,所以Hadoop有自己的一套序列化。
Hadoop序列化的特点:
- 紧凑:存储空间少
- 快速:传输速度快
- 互操作性:支持多语言的交互
实际开发中,Hadoop自带的Text
、IntWritable
等基本的序列化类型往往不够用,需要自定义一些可序列化的 JavaBean。
自定义需要序列化的类:
- 必须实现
Writable
接口 - 反序列化时,需要反射调用空参构造函数,所以必须要有空参构造
- 实现序列化方法
write()
: - 实现反序列化方法
readFields()
: - 注意反序列化顺序要和序列化的顺序完全一致(先进先出)
- 如果想把结果显示在文件中,还需要重写
toString()
方法 - 如果要把自定义的类的对象放在key中传输,则还需要实现
Comparable
接口,因为MapReduce框架中的Shuffle过程要求key必须能够排序
示例:
package com.study.mapreduce.writable;
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class MyWritable implements Writable,Comparable<MyWritable> {
private Integer id;
private Long scale;
private Integer age;
/**
* 需要有无参构造器
*/
public MyWritable() {
}
/**
* 序列化
* @param out
* @throws IOException
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(id);
out.writeLong(scale);
out.writeInt(age);
}
/**
* 反序列化
* @param in
* @throws IOException
*/
@Override
public void readFields(DataInput in) throws IOException {
// 读取顺序要和write方法写的顺序一致,即先进先出
id = in.readInt();
scale = in.readLong();
age = in.readInt();
}
/**
* 如果想当做key在MapReduce中传输,需要实现Comparable,因为Shuffle过程要求key必须能排序
* @param o
* @return
*/
@Override
public int compareTo(MyWritable o) {
return this.id > o.getId() ? -1 : 1;
}
/**
* 为方便查看,还可以重写toString()方法
* @return
*/
@Override
public String toString() {
MessageFormat mf = new MessageFormat("MyWritable:{id:[0], scale:[1], age:[2]}");
return mf.format(new Object[]{id, scale, age});
}
// 生成getter/setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Long getScale() {
return scale;
}
public void setScale(Long scale) {
this.scale = scale;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}