Java Object SerializationとHadoopのプロローグを深く分析します。


一、Java Object Serialization
1,何がプログレッシブですか?
プログレッシブとは、構造化されたオブジェクトをバイトストリームに変換して、ネットワーク上でまたはディスクに永久に格納するプロセスをいう。アンチプログレッシブとは、バイトストリームを構造化オブジェクトに戻す逆プロセスのことです。単純な理解は、オブジェクトをバイトストリームに変換して伝送と保存を行い、バイトストリームをオブジェクトに変換してオブジェクトを元の状態に戻すことである。
2,プロローグの役割
(1)メモリ内のオブジェクトの状態を一つのファイルまたはデータベースに保存するシステムです。
(2)ソケットを用いてネットワーク上でオブジェクトを転送する通信機構。
(3)Javaリモートメソッド呼び出し(RMI)オブジェクトの呼び出しが必要な場合、
3,Serializableインターフェースの対象の序列化を実現しました。
java.ioパッケージでは、インターフェースSerializationは、オブジェクトのシリアル化を実現するためのツールとして使用され、Serializationのクラスを実現したオブジェクトだけが、プログレッシブ化されます。Serializableインターフェースには何の方法もありません。クラスの声明がSerializableインターフェースを実現するには、このクラスがプログレッシブプロトコルに参加することを示すだけで、特別な方法を実現する必要はありません。
オブジェクトを順番に並べて、まずOutputStreamオブジェクトを作成し、Object OutputStreamオブジェクトにカプセル化します。このとき、writeObject()を呼び出してオブジェクトを逐次並べてOutput Streamに送信します。アンチプログレッシブ時には、一つのInputStreamをObject InputStream内にカプセル化し、その後readObject()を呼び出し、結果としてObjectオブジェクトとなり、最終的に必要なオブジェクトに変換する必要があります。注意したいのは、Serializableオブジェクトに対して逆順序化を行う過程で、デフォルトのビルダーを含めて、オブジェクト全体がInputStreamからデータを取得して回復してきたものです。オブジェクトのプログレッシブはバイト向けなので、InputStreamとOutputStreamの階層構造を採用しています。
Studentへの序列化

package cn.test.serializable;
/**
 *        Serializable  
 * @author Young
 * created on 2017-5-25
 */
import java.io.Serializable;
public class Student implements Serializable {
  private String id;
  private String name;
  public Student (String id,String name){
    this.id=id;
    this.name=name;
  }
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}
序文化

package cn.test.serializable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
 *    
 * @author Young
 * created on 2017-5-25
 */
public class TestSerializable {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Student stu=new Student("201441413110","yang");
    try {
      FileOutputStream out=new FileOutputStream("d:\\student");//  OutputStream  
      ObjectOutputStream ob=new ObjectOutputStream(out);//     ObjectOutputStream   
      ob.writeObject(stu);//  writeObject()            OutputStream,   d:\\student 
      ob.close();
      out.close();
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
反プロローグ

package cn.test.serializable;
/**
 *     
 * @author Young
 * created on 2017-5-25
 */
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class TestDeserializable {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    FileInputStream in;
    Student stu;
    try {
      in = new FileInputStream("d:\\student");
      ObjectInputStream ob=new ObjectInputStream(in);//InputStream   ObjectInputStream 
      stu=(Student) ob.readObject();//  readObject(),        Object  ,               .
      ob.close();
      in.close();
      System.out.println(stu.getId());
      System.out.println(stu.getName());
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
プログレッシブ機構がストリームに書いてあるデータは
1,声明とマークは、例えば、プログレッシブ・プロトコルのバージョン、プログレッシブ・プロトコルのバージョンを使用しています。これは新しいオブジェクトであり、声明はここで新しいクラスを開始し、終了マークなどです。
2,オブジェクトが属するクラス、クラスの長さ、
3,SerialVersion UID,プログレッシブID,指定がない場合は,アルゴリズムによってランダムに8 byteのIDが生成されます。
4,すべての非tranientと非staticの属性の個数と名称。名前の長さ、属性の値。
これは単なる対象のプログレッシブ化されたもので、ストリームに書かれたデータです。複雑なオブジェクトの順序化なら、より多くの情報が含まれます。例えば、他のオブジェクトをメンバー変数として参照することができます。また、順序化の場合は対象の状態だけを保存し、対象の方法に関係なく保存します。親クラスが順序化を実現する時、サブクラスは自動的に序列化を実現し、明示的にSerializableインターフェースを実現する必要がない。オブジェクトのインスタンス変数が他のオブジェクトを参照し、オブジェクトをプログレッシブにするときも、参照オブジェクトをプログレッシブにします。
二,Hadoopプロローグ
hadoopノード間の内部通信はRPCを使用しており、RPCプロトコルはメッセージをバイナリバイトストリームに変換してリモートノードに送信し、リモートノードはさらにアンチプログレッシブ化によってバイナリを元の情報に転送する。
Hadoopは自分の序列化フォーマットWritableを使って、絶対的にコンパクトで高速ですが、Java以外の言語で広く開拓して使うのは簡単ではありません。
1,Writableコネクタ
Writableインターフェースは、2つの方法を定義しています。1つは、その状態をDataOutputバイナリストリームに書き込み、もう1つは、Data Inputバイナリストリームからその状態を読み取ります。
コードを実現

package Hadoop.writable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Writable;
/**
 * hadoop         
 * @author Young
 * created by 2017-6-9
 */
public class Serialize {
  public static byte[] serialize(Writable writable) throws IOException{
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    DataOutputStream dataout = new DataOutputStream(out);
    try {
      writable.write(dataout);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      dataout.close();
    }
    return out.toByteArray();
  }
  public static byte[] deserialize(Writable writable ,byte[] bytes) throws IOException{
    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
    DataInputStream datain = new DataInputStream(in);
    try {
      writable.readFields(datain);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    finally{
      datain.close();
    }
    return bytes;
  }
  public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub
    IntWritable intwritable = new IntWritable(20);
    IntWritable newwriatble =new IntWritable();
    byte[] bytes=Serialize.serialize(intwritable);
    deserialize(newwriatble,bytes);
    System.out.println(newwriatble.get());
  }
}
2,Hadoopプログレッシブ機構には他にいくつかの重要なインターフェースが含まれています。Writable Comprable、RawComprator、Writable Comprator
Writable Comprableはタイプ比較の能力を提供し、WritableインターフェースとComprableインターフェースを継承しています。ここでCompparableはタイプ比較を行います。ByteWritable、IntWritable、Doubleなどjava基本タイプに対応するWritableタイプは、すべてWritable Comprableから継承されています。
Writable Comprableコネクタ

package org.apache.hadoop.io;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
import org.apache.hadoop.io.Writable;
@Public
@Stable
public interface WritableComparable<T> extends Writable, Comparable<T> {
}
MapReduceにとっては、中間にキーベースの順序付け段階があるので、タイプの比較が非常に重要である。Hadoopは効率的な比較能力を持つRawCompratorインターフェースを提供します。
RawCompratorインターフェース

package org.apache.hadoop.io;
import java.util.Comparator;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
@Public
@Stable
public interface RawComparator<T> extends Comparator<T> {
  int compare(byte[] arg0, int arg1, int arg2, byte[] arg3, int arg4, int arg5);
}
このインターフェースは、データストリーム中の記録を直接比較することを可能にし、データストリームを最初にオブジェクトに逆順序化する必要がなく、新規オブジェクトからのオーバヘッドを回避する。
Writable Compratorは、Writable Comprable類から継承されているRawComprator類に共通する実現です。二つの主要機能を提供します。1は、オリジナルのcompre()方法のデフォルト実装を提供し、この方法は、ストリーム中で比較されるオブジェクトを逆順序で並べて、オブジェクトのcompre()方法を呼び出すことができる。2,それはRawCompratorの例の工場として働いています。例えばIntWritableのcompratorを得るために、直接に呼び出すことができます。

RawComparator<IntWritable>comparator=WritableComparator.get(IntWritable.class);
以下は「Hadoop権威ガイド」の例です。

package cn.serialization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.RawComparator;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparator;
public class TestWritable {
  //   
  public static byte[] serialize(Writable writable) throws IOException{
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    DataOutputStream dataOut= new DataOutputStream(out);
    writable.write(dataOut);
    dataOut.close();
    return out.toByteArray();
  }
  //    
  public static byte[] deserialize(Writable writable, byte[] bytes) throws IOException{
    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
    DataInputStream dataIn = new DataInputStream(in);
    writable.readFields(dataIn);
    dataIn.close();
    return bytes;
  }
  public static void main(String[] args) throws IOException {
    @SuppressWarnings("unchecked")
    RawComparator <IntWritable> comparator = WritableComparator.get(IntWritable.class);
    IntWritable w1 = new IntWritable(163);
    IntWritable w2 = new IntWritable(67);
    byte[] b1 = serialize(w1);
    byte[] b2 = serialize(w2);
    System.out.println(b1);
    System.out.println(b2);
    System.out.println(comparator.compare(w1, w2));//WritableComparator  compare(),w1>w2 -> 1;w1<w2 -> -1 ; w1=w2 -> 0
  System.out.println(comparator.compare(b1,0,b1.length,b2,0,b2.length));
  }
}
三、Hadoopプログレッシブフレーム
ほとんどのMapReduceプログラムはWritableタイプのkey、valueを使用していますが、すべてのMapReduce APIは強制的に使用されていません。実際には、各タイプをバイナリと往復変換するメカニズムがある限り、任意のタイプが使用されてもよい。このためにHadoopは、org.apphe.hadoop.io.serialzerパッケージの中で、Writable Serializationクラスは、WritableタイプのSerializationに対して実現されるプログレッシブフレームを提供しています。
Writable Serialization類

public class WritableSerialization extends Configured implements Serialization<Writable> {...}
Serializerインターフェース
オープンインターフェース、プログレッシブインターフェース、closeインターフェースを定義しました。

public interface Serializer<T> {
  void open(OutputStream arg0) throws IOException;
  void serialize(T arg0) throws IOException;
  void close() throws IOException;
}
Deserializerインターフェース
オープンインターフェース、アンチプログレッシブインターフェース、closeインターフェースを定義しました。

public interface Deserializer<T> {
  void open(InputStream arg0) throws IOException;
  T deserialize(T arg0) throws IOException;
  void close() throws IOException;
}
Serializationインターフェース
入力をサポートしているかどうかを判断するインターフェースのセットを定義し、入力のクラスに応じて、プログレッシブインターフェースとアンチプログレッシブインターフェースを提供します。

public interface Serialization<T> {
  boolean accept(Class<?> arg0);
  Serializer<T> getSerializer(Class<T> arg0);
  Deserializer<T> getDeserializer(Class<T> arg0);
}
いくつかのインターフェースがあります。APIドキュメントを確認できます。
にもかかわらず、これは私たちがMapReduceでString、IntegerなどのJavaタイプを使うのに便利です。でも、これはやはりWritableほど効率的ではないです。
Hadoopでjava Object Serializationを使わない理由
1,Java Object Serializationはあまり洗練されていません。ここで前述したJava Object Serializationのプログレッシブ化後のバイトフローは、クラス名やオブジェクトなど多くの情報を含んでいます。
2,オブジェクトは、序文化では参照のみを保存し、参照の出現可能な位置はランダムであり、序文化されたオブジェクトの前にも後ろにもあるので、ランダムアクセスや並べ替えに影響を与え、エラーが発生すると、後の順序がすべて誤ってしまい、Writableはランダムアクセスと並べ替えをサポートします。流れの中の記録は互いに独立しているからです。
3.Javaプログレッシブは逆プログレッシブごとにオブジェクトを再作成し、メモリの消費が大きく、Writableは再利用できます。
以上は小编で绍介したJava Object SerialzationとHadoopのプロローグです。皆さんのために役に立つことを望んでいます。ここでも私たちのサイトを応援してくれてありがとうございます。