1. 序列化反序列化
1.1 序列化反序列化是什么
序列化: 是将内存中的对象转换称为字节序列,以便持久化到磁盘中或用于网络传输
反序列化: 将字节序列转换称为内存中的对象
1.2 JDK 序列化反序列化
Java 中,如果需要序列化,需要实现 java.io.Serializable 接口,利用序列化版本ID serialVersionUID 来标识版本。
JDK 需要借助 ObjectOutputStream (writeObject(Object))和 ObjectInputStream (readObject())分别实现序列化反序列化。
1.3 Hadoop 序列化反序列化
Hadoop 不适用 JDK 序列化,是因为利用 Serializable 序列化后会附带很多额外的信息,不便于数据的网络传输。
Hadoop 实现的序列化机制为 Writable。
1.4 Hadoop 序列化的意义
Hadoop 在集群之间进行通讯或者 RPC 调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。所以必须理解 Hadoop 的序列化机制。
序列化和反序列化在分布式数据处理领域经常出现:进程通信和永久存储。然而Hadoop中各个节点的通信是通过远程调用(RPC)实现的,那么就不能使用 JDK 序列化,所以 Hadoop 自己实现了一套序列化机制。
Hadoop 序列化特点:
- 紧凑:高校使用存储空间
- 快速:读写数据的额外开销小
- 可扩展:原始序列化方式支持新协议的报文
- 互操作:支持多种语言的交互
1.5 序列化类型
| Java 类型 | Hadoop Writable 类型 |
|---|
boolean | BooleanWritable | byte | ByteWritable | int | IntWritable | float | FloatWritable | long | LongWritable | double | DoubleWritable | string | Text | map | MapWritable | array | ArrayWritable |
2. Writable 自定义实现
Writable 用于在对象和字节序列之间做转换。
自定义实现需要注意几点:
- 必须要实现 Writable 接口
- 需要提供无参构造,应为反序列化需要反射调用空参构造函数
- 重写序列、反序列方法,且序列和反序列的顺序保持一致
- 如果后期需要指定 key 排序,还需要实现 Comparable 接口
2.1 窥见源码
Writable 接口中只有两个方法
write:用于序列化操作readFields:用于反序列化操作
public interface Writable {
void write(DataOutput var1) throws IOException;
void readFields(DataInput var1) throws IOException;
}
如果需要比较,我们可以直接实现WritableComparable 接口,该接口只是继承了两个接口类,因此还需要实现 Comparable 的 compareTo 方法。
@Public
@Stable
public interface WritableComparable<T> extends Writable, Comparable<T> {
}
public interface Comparable<T> {
public int compareTo(T o);
}
2.2 自定义 Bean
比如:对日志文件进行相关信息统计
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class WritableUser implements WritableComparable<WritableUser> {
long id;
String name;
int age;
boolean sex;
int money;
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeLong(this.id);
dataOutput.writeUTF(this.name);
dataOutput.writeInt(this.age);
dataOutput.writeBoolean(this.sex);
dataOutput.writeInt(this.money);
}
@Override
public void readFields(DataInput dataInput) throws IOException {
this.id = dataInput.readLong();
this.name = dataInput.readUTF();
this.age = dataInput.readInt();
this.sex = dataInput.readBoolean();
this.money = dataInput.readInt();
}
@Override
public int compareTo(WritableUser o) {
if (this.age == o.age){
return -Integer.compare( this.money, o.money);
} else {
return -Integer.compare( this.age, o.age);
}
}
public WritableUser() {
}
public WritableUser(long id, String name, int age, boolean sex, int money) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.money = money;
}
public void set(long id, String name, int age, boolean sex, int money) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.money = money;
}
@Override
public String toString() {
return "WritableUser{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", money=" + money +
'}';
}
}
3. 写在最后
只需要序列化时,实现 Writable ,如果还需要排序,可实现 WritableComparable 。
如果想要降序排列,在返回值前加个负号(-)
?
???END???
|