溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

十二、hadoop的序列化

發(fā)布時間:2020-07-20 15:51:28 來源:網(wǎng)絡(luò) 閱讀:372 作者:隔壁小白 欄目:大數(shù)據(jù)

一、序列化基本概述

1、何為序列化

序列化就是將內(nèi)存中的對象,轉(zhuǎn)換成字節(jié)序列(或者按照其他數(shù)據(jù)傳輸協(xié)議轉(zhuǎn)換),以便于持久化存儲到磁盤中以及網(wǎng)絡(luò)傳輸

2、為什么需要序列化

一般情況下,對象只存儲在本地的內(nèi)存中,只允許本地的進(jìn)程調(diào)用。而隨著分布式程序的出現(xiàn),需要在不同的主機(jī)上不同進(jìn)程調(diào)用對象,這就需要將對象通過網(wǎng)絡(luò)傳輸?shù)搅硗獾闹鳈C(jī)上。但是對象不經(jīng)過處理無法通過網(wǎng)絡(luò)傳輸,而通過序列化處理之后,對象可以通過網(wǎng)絡(luò)傳輸了。

3、java中的序列化方案

java中自行實現(xiàn)了序列化方案,只要定義一個類的時候?qū)崿F(xiàn) Serializable 接口,那么java內(nèi)部就會自動實現(xiàn)相應(yīng)的序列化。如:

public class Test implements Serializable{

    //這個序列化號是必須的,用于標(biāo)識該類
    private static final long serialVersionUID = xxxx;
}

但是由于Java中的序列化接口實現(xiàn)的時候,會附帶很多額外的信息,如各種校驗信息,header,繼承體系等。不便于在網(wǎng)絡(luò)上高效傳輸(性能不高)。所以hadoop自己額外實現(xiàn)了序列化的機(jī)制,體積短小,占用帶寬低,序列化和反序列化快速

二、hadoop中序列化

1、類基本依賴

hadoop中以實現(xiàn) Writable 這個接口的類,就可以序列化。而且hadoop實現(xiàn)了許多基本類型的可序列化的類。依賴圖如下所示:
十二、hadoop的序列化

? 圖 2.1 hadoop序列化依賴圖

可以看到所有的可序列化的類都實現(xiàn)了 WritableComparable 這個接口,這個接口同時繼承了 Writable 以及 Comparable 接口。下面看看這個這三個接口:

//WritableComparable.java
public interface WritableComparable<T> extends Writable, Comparable<T> {
}
/*
空的接口
*/

//Writable.java
public interface Writable {
    void write(DataOutput var1) throws IOException;

    void readFields(DataInput var1) throws IOException;
}
/*
主要包含讀和寫序列化對象的方法
*/

//Comparable.java
public interface Comparable<T> {
    public int compareTo(T o);
}
/*
提供序列化對象間比較的方法
*/

2、hadoop序列化類和基本類型的對照表

java類型 hadoop writable類型
boolean BooleanWritable
byte ByteWritable
Int IntWritable
float FloatWritable
long LongWritable
double DoubleWritable
string Text
map MapWritable
array ArrayWritable

3、常用序列化類的源碼實現(xiàn)

下面挑個IntWritable這個常用的序列化類來看看源碼

package org.apache.hadoop.io;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;

@Public
@Stable
public class IntWritable implements WritableComparable<IntWritable> {
    private int value;

    public IntWritable() {
    }

    public IntWritable(int value) {
        this.set(value);
    }

    public void set(int value) {
        this.value = value;
    }

    public int get() {
        return this.value;
    }

    //這里是實現(xiàn)了 writable 接口的方法
    public void readFields(DataInput in) throws IOException {
        this.value = in.readInt();
    }

    public void write(DataOutput out) throws IOException {
        out.writeInt(this.value);
    }

    //序列化對象的equals比較方法
    public boolean equals(Object o) {
        if (!(o instanceof IntWritable)) {
            return false;
        } else {
            IntWritable other = (IntWritable)o;
            return this.value == other.value;
        }
    }

    public int hashCode() {
        return this.value;
    }

    //比較對象大小的方法
    public int compareTo(IntWritable o) {
        int thisValue = this.value;
        int thatValue = o.value;
        return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
    }

    public String toString() {
        return Integer.toString(this.value);
    }

    /*這里是關(guān)鍵,將下面的Comparator內(nèi)部類作為默認(rèn)的比較方法。
    因為這里采用靜態(tài)代碼塊的方式,所以只要該類載入時,就會執(zhí)行該代碼塊,直接創(chuàng)建 Comparator對象,后面無需通過外部類創(chuàng)建對象的方式來調(diào)用 compare方法,因為對象已經(jīng)提前創(chuàng)建好了。比起上的 compareTo 方法,還要手動創(chuàng)建一個外部類對象才能調(diào)用 compareTo 方法,這里可以直接調(diào)用,效率要快。
    */
    static {
        WritableComparator.define(IntWritable.class, new IntWritable.Comparator());
    }

    //這個內(nèi)部類也實現(xiàn)了 compare比較方法
    public static class Comparator extends WritableComparator {
        public Comparator() {
            super(IntWritable.class);
        }

        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
            int thisValue = readInt(b1, s1);
            int thatValue = readInt(b2, s2);
            return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
        }
    }
}

其他short,long的序列化類的實現(xiàn)也是類似的。

4、自定義序列化類

要點:
(1)必須實現(xiàn) Writable接口
(2)必須有無參構(gòu)造方法,因為反序列化時需要反射調(diào)用無參構(gòu)造方法
(3)重寫序列化方法

public void write(DataOutput out) throws IOException{
    //DataOutput接口中定義了每個基本類型序列化的方法,這里以Long為例
    out.writeLong(upFlow);
    out.writeLong(downFlow);
    out.writeLong(sumFlow);
}

(4)重寫反序列化方法

public void readFields(DataInput in) throws IOException{
    upFlow = in.readLong();
    downFlow = in.readLong();
    sumFlow = in.readLong();
}

(5)序列化寫入和反序列化讀取時要注意,寫入和讀取的順序必須完全一致
(6)按照需要可以重寫 toSting 方法,便于保存在文件中的內(nèi)容
(7)如果該自定義序列化類是作為鍵值對中的key使用的話,因為MapReduce中會以key進(jìn)行排序,那么就會涉及到 key 的比較問題。所以需要實現(xiàn) Comparable 接口。而該接口就得實現(xiàn) compareTo 方法

public int compareTo(Test o) {
    return (-1 | 0 |1 ); 表示小于,等于,大于三種結(jié)果
}

5、屬性中包含自定義類的序列化

首先屬性中的自定義類也是需要實現(xiàn)序列化接口的。所以下面的DateDimension和ContactDimension都是已經(jīng)實現(xiàn)序列化的了。

public class ComDimension extends BaseDimension {
    private DateDimension dateDimension = new DateDimension();
    private ContactDimension contactDimension = new ContactDimension();

//序列化就直接調(diào)用類的write方法即可,按照下面的形式
 @Override
    public void write(DataOutput dataOutput) throws IOException {
        this.dateDimension.write(dataOutput);
        this.contactDimension.write(dataOutput);
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.dateDimension.readFields(dataInput);
        this.contactDimension.readFields(dataInput);
    }

}
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI