天天看點

Hadoop 序列化1. 序列化反序列化2. Writable 自定義實作3. 寫在最後

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. 緊湊:高校使用存儲空間
  2. 快速:讀寫資料的額外開銷小
  3. 可擴充:原始序列化方式支援新協定的封包
  4. 互操作:支援多種語言的互動

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 用于在對象和位元組序列之間做轉換。

自定義實作需要注意幾點:

  1. 必須要實作 Writable 接口
  2. 需要提供無參構造,應為反序列化需要反射調用空參構造函數
  3. 重寫序列、反序列方法,且序列和反序列的順序保持一緻
  4. 如果後期需要指定 key 排序,還需要實作 Comparable 接口

2.1 窺見源碼

Writable

接口中隻有兩個方法

  1. write

    :用于序列化操作
  2. 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;

    // 必須實作 Writable 接口 ========================================

    /**
     *  Writable 序列化方法
     * @param dataOutput 輸出流 用來将類的成員屬性 按序輸出為二進制資料
     * @throws IOException
     */
    @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);
    }

    /**
     *  Writable 反序列化方法
     * @param dataInput 輸入流 将讀取到的每一個值指派到自己的成員屬性
     * @throws IOException
     */
    @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();
    }

    /**
     *  比較方法,當 age 一緻時,根據 money 降序排列
     * @param o
     * @return
     */
    @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;
    }

    // 提供 set 方法,友善後期使用
    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 ❤️

繼續閱讀