hadoop文件的序列化

目錄 java

    一、爲何要序列化?apache

    二、什麼是序列化?數組

    三、爲何不用Java的序列化?服務器

    四、爲何序列化對Hadoop很重要?網絡

    五、Hadoop中定義哪些序列化相關的接口呢?框架

    六、Hadoop 自定義Writable 接口分佈式

 

一、爲何要序列化? ide

     通常來講,"活的"對象只存在內存裏,關機斷電就沒有了。並且"活的"對象只能由本地的進程使用,不能被髮送到網絡上的另一臺計算機。 然而序列化能夠存儲"活的"對象,能夠將"活的"對象發送到遠程計算機。函數

二、什麼是序列化?oop

     序列化就是指將對象(實例)轉化爲字節流(字符數組)。反序列化就是將字節流轉化爲對象的逆過程。 因而,若是想把"活的"對象存儲到文件,存儲這串字節便可,若是想把"活的"對象發送到遠程主機,發送這串字節便可,須要對象的時候,作一下反序列化,就能將對象"復活"了。

     將對象序列化存儲到文件,術語又叫"持久化"。將對象序列化發送到遠程計算機,術語又叫"數據通訊"。

三、爲何不用Java的序列化?

     Java的序列化機制的缺點就是計算量開銷大,且序列化的結果體積大太,有時能達到對象大小的數倍乃至十倍。它的引用機制也會致使大文件不能分割的問題。這些缺點使得Java的序列化機制對Hadoop來講是不合適的。因而Hadoop設計了本身的序列化機制。

四、爲何序列化對Hadoop很重要?

  由於Hadoop在集羣之間進行通信或者RPC調用的時候,須要序列化,並且要求序列化要快,且體積要小,佔用帶寬要小。因此必須理解Hadoop的序列化機制。

  序列化和反序列化在分佈式數據處理領域常常出現:進程通訊和永久存儲。然而Hadoop中各個節點的通訊是經過遠程調用(RPC)實現的,那麼 RPC序列化要求具備如下特色:
    緊湊:緊湊的格式能讓咱們能充分利用網絡帶寬,而帶寬是數據中心最稀缺的資源
    快速:進程通訊造成了分佈式系統的骨架,因此須要儘可能減小序列化和反序列化的性能開銷,這是基本的
    可擴展:協議爲了知足新的需求變化,因此控制客戶端和服務器過程當中,須要直接引進相應的協議,這些是新協議,原序列化方式能支持新的協議報文
    互操做:能支持不一樣語言寫的客戶端和服務端進行交互

五、Hadoop中定義哪些序列化相關的接口呢?

  Hadoop中定義了兩個序列化相關的接口:Writable 接口和 Comparable 接口,這兩個接口能夠合併成一個接口 WritableComparable

  下面咱們就瞭解一下這兩個序列化接口:

  • Writable接口

 全部實現了Writable接口的類均可以被序列化和反序列化。 Writable 接口中定義了兩個方法,分別爲write(DataOutput out)和readFields(DataInput in)。write 用於將對象狀態寫入二進制格式的DataOutput流,readFields 用於從二進制格式的 DataInput 流中讀取對象狀態。

 1 package org.apache.hadoop.io;
 2 
 3 import java.io.DataOutput;
 4 
 5 import java.io.DataInput;
 6 
 7 import java.io.IOException;
 8 
 9 import org.apache.hadoop.classification.InterfaceAudience;
10 
11 import org.apache.hadoop.classification.InterfaceStability;
12 
13 public interface Writable {
14     /**
15 
16     * 將對象轉換爲字節流並寫入到輸出流out中
17 
18     */
19 
20     void write(DataOutput out) throws IOException;
21     
22     /**
23     
24     * 從輸入流in中讀取字節流反序列化爲對象
25     
26     */
27 
28     void readFields(DataInput in) throws IOException;
29 }

對於一個特定的 Writable,咱們能夠對它進行哪些操做呢?

有兩種經常使用操做:賦值和取值,這裏咱們以 IntWritable 爲例來分別說明(IntWritable是對Java的int類型的封裝)

1)經過 set() 函數設置 IntWritable 的值

  IntWritable value = new IntWritable();

  value.set(588)

  相似的,也可使用構造函數來賦值。

  IntWritable value = new IntWritable(588);

2)經過get()函數獲取 IntWritable 的值。

 int result = value.get();// 這裏獲取的值爲588

  • Comparable接口

  全部實現了Comparable的對象均可以和自身相同類型的對象比較大小。該接口定義爲:

 1 package java.lang;
 2 
 3 import java.util.*;
 4 
 5 public interface Comparable<T> {
 6     /**
 7     * 將this對象和對象o進行比較,約定:返回負數爲小於,零爲大於,整數爲大於
 8     */
 9     public int compareTo(T o);
10 }

六、Hadoop 自定義Writable 接口

  雖然 Hadoop 自帶一系列Writable實現,如IntWritable,LongWritable等,能夠知足一些簡單的數據類型。但有時,複雜的數據類型須要本身自定義實現。經過自定義Writable,可以徹底控制二進制表示和排序順序。

  現有的 Hadoop Writable 應用已獲得很好的優化,但爲了對付更復雜的結構,最好建立一個新的 Writable 類型,而不是使用已有的類型。下面咱們來學習一下如何自定義 Writable 類型,以自定義一個Writable 類型TextPair爲例,以下所示

 1 import java.io.*;
 2 
 3 import org.apache.hadoop.io.*;
 4 
 5 /** 
 6 * @ProjectName Serialize
 7 * @ClassName TextPair
 8 * @Description 自定義Writable類型TextPair
 9 * @Author 劉吉超
10 * @Date 2016-04-16 23:59:19
11 */
12 public class TextPair implements WritableComparable<TextPair> {
13     // Text 類型的實例變量
14     private Text first;
15     // Text 類型的實例變量
16     private Text second;
17     
18     public TextPair() {
19         set(new Text(), new Text());
20     }
21 
22     public TextPair(String first, String second) {
23         set(new Text(first), new Text(second));
24     }
25 
26     public TextPair(Text first, Text second) {
27         set(first, second);
28     }
29 
30     public void set(Text first, Text second) {
31         this.first = first;
32         this.second = second;
33     }
34 
35     public Text getFirst() {
36         return first;
37     }
38 
39     public Text getSecond() {
40         return second;
41     }
42     
43     @Override
44     // 將對象轉換爲字節流並寫入到輸出流out中
45     public void write(DataOutput out) throws IOException {
46         first.write(out);
47         second.write(out);
48     }
49     
50     @Override
51     // 從輸入流in中讀取字節流反序列化爲對象
52     public void readFields(DataInput in) throws IOException {
53         first.readFields(in);
54         second.readFields(in);
55     }
56 
57     @Override
58     public int hashCode() {
59         return first.hashCode() * 163 + second.hashCode();
60     }
61 
62     @Override
63     public boolean equals(Object o) {
64         if (o instanceof TextPair) {
65             TextPair tp = (TextPair) o;
66             return first.equals(tp.first) && second.equals(tp.second);
67         }
68         return false;
69     }
70 
71     @Override
72     public String toString() {
73         return first + "\t" + second;
74     }
75 
76     // 排序
77     @Override
78     public int compareTo(TextPair tp) {
79         int cmp = first.compareTo(tp.first);
80         if (cmp != 0) {
81             return cmp;
82         }
83         return second.compareTo(tp.second);
84     }
85 }

  TextPair對象有兩個Text實例變量(first和second)、相關的構造函數、get方法和set方法。 全部的Writable實現都必須有一個默認的構造函數,以便MapReduce框架可以對它們進行實例化,進而調用readFields()方法來填充它們的字段。Writable實例是易變的、常常重用的,因此應該儘可能避免在 write() 或 readFields() 方法中分配對象。

  經過委託給每一個 Text 對象自己,TextPair 的 write() 方法依次序列化輸出流中的每個 Text 對象。一樣也經過委託給 Text 對象自己,readFields() 反序列化 輸入流中的字節。DataOutput 和 DataInput 接口有豐富的整套方法用於序列化和反序列化 Java 基本類型,因此在通常狀況下,可以徹底控制 Writable 對象的數據傳輸格式。

  正如爲Java寫的任意值對象同樣,會重寫java.lang.Object的hashCode()、equals()和toString()方法。 HashPartitioner使用hashcode()方法來選擇reduce分區,因此應該確保寫一個好的哈希函數來肯定reduce函數的分區在大小上是至關的。

  TextPair是WritableComparable的實現,因此它提供了compareTo()方法的實現,加入咱們但願的排序:經過一個一個String逐個排序

若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】。
若是,您但願更容易地發現個人新博客,不妨點擊一下左下角的【關注我】。
若是,您對個人博客所講述的內容有興趣,請繼續關注個人後續博客,我是【劉超★ljc】。

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索