Apache Avroのガイド
1. 概要
データのシリアル化は、データをバイナリ形式またはテキスト形式に変換する手法です。 この目的で使用できるシステムは複数あります。 Apache Avroは、それらのデータシリアル化システムの1つです。
Avro is a language independent, schema-based data serialization library。 スキーマを使用して、シリアル化と逆シリアル化を実行します。 さらに、AvroはJSON形式を使用して、より強力なデータ構造を指定します。
このチュートリアルでは、Avroのセットアップ、シリアル化を実行するJava API、およびAvroと他のデータシリアル化システムとの比較について詳しく説明します。
主に、システム全体の基盤となるスキーマの作成に焦点を当てます。
2. アパッチアブロ
Avroは、言語に依存しないシリアル化ライブラリです。 これを行うために、Avroはコアコンポーネントの1つであるスキーマを使用します。 stores the schema in a file for further data processingです。
Avroは、ビッグデータ処理に最適です。 処理が高速なため、HadoopとKafkaの世界で非常に人気があります。
Avroは、メタデータセクションにスキーマとともにデータを保持するデータファイルを作成します。 とりわけ、豊富なデータ構造を提供し、他の同様のソリューションよりも人気があります。
シリアル化にAvroを使用するには、以下の手順に従う必要があります。
3. 問題文
例で使用するAvroHttRequestというクラスの定義から始めましょう。 このクラスには、プリミティブ型と複合型の属性が含まれています。
class AvroHttpRequest {
private long requestTime;
private ClientIdentifier clientIdentifier;
private List employeeNames;
private Active active;
}
ここで、requestTimeはプリミティブ値です。 ClientIdentifierは、複合型を表す別のクラスです。 また、複合型であるemployeeNameもあります。 Activeは、指定された従業員のリストがアクティブであるかどうかを表す列挙型です。
私たちの目的は、Apache Avroを使用してAvroHttRequestクラスをシリアル化および逆シリアル化することです。
4. Avroデータタイプ
先に進む前に、Avroでサポートされているデータ型について説明しましょう。
Avroは2種類のデータをサポートしています。
-
プリミティブ型:Avroはすべてのプリミティブ型をサポートしています。 プリミティブ型名を使用して、特定のフィールドの型を定義します。 たとえば、Stringを保持する値は、スキーマで\ {“ type”:“ string”}として宣言する必要があります。
-
複合型:Avroは、6種類の複合型をサポートしています:レコード、列挙、配列、マップ、ユニオン、固定
たとえば、問題の説明では、ClientIdentifierはレコードです。
その場合、ClientIdentifierのスキーマは次のようになります。
{
"type":"record",
"name":"ClientIdentifier",
"namespace":"com.example.avro",
"fields":[
{
"name":"hostName",
"type":"string"
},
{
"name":"ipAddress",
"type":"string"
}
]
}
5. Avroを使用する
まず、必要なMaven依存関係をpom.xmlファイルに追加しましょう。
次の依存関係を含める必要があります。
-
Apache Avro –コアコンポーネント
-
コンパイラ– Avro IDLおよびAvro固有のJava APIT用のApache Avroコンパイラ
-
ツール-Apache Avroコマンドラインツールとユーティリティを含む
-
Mavenプロジェクト用のApache Avro Mavenプラグイン
このチュートリアルではバージョン1.8.2を使用しています。
ただし、Maven Centralで最新バージョンを見つけることを常にお勧めします。
org.apache.avro
avro-compiler
1.8.2
org.apache.avro
avro-maven-plugin
1.8.2
Maven依存関係を追加したら、次の手順は次のようになります。
-
スキーマ作成
-
プログラムでスキーマを読み取る
-
Avroを使用してデータをシリアル化する
-
最後に、データをデシリアライズします
6. スキーマ作成
Avroは、JSON形式を使用してスキーマを記述します。 特定のAvroスキーマには、主に4つの属性があります。
-
複合型かプリミティブ値かを問わず、スキーマの型を記述するType-
-
指定されたスキーマが属する名前空間を記述するNamespace-
-
Name –スキーマの名前
-
Fields-は、特定のスキーマに関連付けられているフィールドについて通知します。 Fields can be of primitive as well as complex type。
スキーマを作成する1つの方法は、前のセクションで見たように、JSON表現を記述することです。
SchemaBuilderを使用してスキーマを作成することもできます。これは、間違いなく、スキーマを作成するためのより優れた効率的な方法です。
6.1. SchemaBuilderユーティリティ
クラスorg.apache.avro.SchemaBuilderは、スキーマの作成に役立ちます。
まず、ClientIdentifier:のスキーマを作成しましょう
Schema clientIdentifier = SchemaBuilder.record("ClientIdentifier")
.namespace("com.example.avro")
.fields().requiredString("hostName").requiredString("ipAddress")
.endRecord();
それでは、これを使用してavroHttpRequestスキーマを作成しましょう。
Schema avroHttpRequest = SchemaBuilder.record("AvroHttpRequest")
.namespace("com.example.avro")
.fields().requiredLong("requestTime")
.name("clientIdentifier")
.type(clientIdentifier)
.noDefault()
.name("employeeNames")
.type()
.array()
.items()
.stringType()
.arrayDefault(null)
.name("active")
.type()
.enumeration("Active")
.symbols("YES","NO")
.noDefault()
.endRecord();
ここで重要なのは、clientIdentifierフィールドのタイプとしてclientIdentifierを割り当てたことです。 この場合、タイプの定義に使用されるclientIdentifierは、以前に作成したスキーマと同じです。
後で、toStringメソッドを適用して、SchemaのJSON構造を取得できます。
Schema files are saved using the .avsc extension。 生成したスキーマを“src/main/resources/avroHttpRequest-schema.avsc”ファイルに保存しましょう。
7. スキーマの読み取り
スキーマの読み取りは、多かれ少なかれcreating Avro classes for the given schemaについてです。 Avroクラスが作成されると、それらを使用してオブジェクトをシリアル化および逆シリアル化できます。
Avroクラスを作成するには2つの方法があります。
-
プログラムによるAvroクラスの生成:クラスはSchemaCompilerを使用して生成できます。 Javaクラスの生成に使用できるAPIがいくつかあります。 GitHubで生成クラスのコードを見つけることができます。
-
Mavenを使用してクラスを生成する
仕事をうまくこなすmavenプラグインが1つあります。 プラグインを含めてmvn clean installを実行する必要があります。
プラグインをpom.xmlファイルに追加しましょう:
org.apache.avro
avro-maven-plugin
${avro.version}
schemas
generate-sources
schema
protocol
idl-protocol
${project.basedir}/src/main/resources/
${project.basedir}/src/main/java/
8. Avroによるシリアル化と逆シリアル化
スキーマの生成が完了したら、シリアル化の部分の調査を続けましょう。
Avroがサポートするデータシリアル化形式には、JSON形式とバイナリ形式の2つがあります。
まず、JSON形式に焦点を当て、次にバイナリ形式について説明します。
さらに先に進む前に、いくつかの重要なインターフェイスを確認する必要があります。 シリアル化には、以下のインターフェイスとクラスを使用できます。
DatumWriter<T>:これを使用して、特定のスキーマにデータを書き込む必要があります。 この例ではSpecificDatumWriterの実装を使用しますが、DatumWriterには他の実装もあります。 他の実装はGenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.です
Encoder:エンコーダーが使用されているか、前述のようにフォーマットを定義しています。 EncoderFactoryは、バイナリエンコーダーとJSONエンコーダーの2種類のエンコーダーを提供します。
DatumReader<D>:逆シリアル化用の単一インターフェイス。 繰り返しになりますが、複数の実装がありますが、この例ではSpecificDatumReaderを使用します。 他の実装は-GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.
Decoder:デコーダーは、データの逆シリアル化中に使用されます。 Decoderfactoryは、バイナリデコーダーとJSONデコーダーの2種類のデコーダーを提供します。
次に、Avroでシリアル化と逆シリアル化がどのように行われるかを見てみましょう。
8.1. 直列化
AvroHttpRequestクラスの例を取り上げ、Avroを使用してシリアル化してみます。
まず、JSON形式でシリアル化します。
public byte[] serealizeAvroHttpRequestJSON(
AvroHttpRequest request) {
DatumWriter writer = new SpecificDatumWriter<>(
AvroHttpRequest.class);
byte[] data = new byte[0];
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Encoder jsonEncoder = null;
try {
jsonEncoder = EncoderFactory.get().jsonEncoder(
AvroHttpRequest.getClassSchema(), stream);
writer.write(request, jsonEncoder);
jsonEncoder.flush();
data = stream.toByteArray();
} catch (IOException e) {
logger.error("Serialization error:" + e.getMessage());
}
return data;
}
このメソッドのテストケースを見てみましょう。
@Test
public void whenSerialized_UsingJSONEncoder_ObjectGetsSerialized(){
byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
assertTrue(Objects.nonNull(data));
assertTrue(data.length > 0);
}
ここでは、jsonEncoderメソッドを使用して、スキーマを渡しました。
バイナリエンコーダを使用する場合は、jsonEncoder()メソッドをbinaryEncoder():に置き換える必要があります
Encoder jsonEncoder = EncoderFactory.get().binaryEncoder(stream,null);
8.2. 逆シリアル化
これを行うには、上記のDatumReaderおよびDecoderインターフェースを使用します。
同様にEncoderFactoryを使用してEncoder,を取得したので、DecoderFactoryを使用してDecoderオブジェクトを取得します。
JSON形式を使用してデータを逆シリアル化します。
public AvroHttpRequest deSerealizeAvroHttpRequestJSON(byte[] data) {
DatumReader reader
= new SpecificDatumReader<>(AvroHttpRequest.class);
Decoder decoder = null;
try {
decoder = DecoderFactory.get().jsonDecoder(
AvroHttpRequest.getClassSchema(), new String(data));
return reader.read(null, decoder);
} catch (IOException e) {
logger.error("Deserialization error:" + e.getMessage());
}
}
そして、テストケースを見てみましょう。
@Test
public void whenDeserializeUsingJSONDecoder_thenActualAndExpectedObjectsAreEqual(){
byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
AvroHttpRequest actualRequest = deSerealizer
.deSerealizeAvroHttpRequestJSON(data);
assertEquals(actualRequest,request);
assertTrue(actualRequest.getRequestTime()
.equals(request.getRequestTime()));
}
同様に、バイナリデコーダを使用できます。
Decoder decoder = DecoderFactory.get().binaryDecoder(data, null);
9. 結論
Apache Avroは、ビッグデータを扱う際に特に役立ちます。 ユースケースごとに使用できるJSON形式だけでなく、バイナリ形式のデータのシリアル化も提供します。
Avroのシリアル化プロセスは高速で、スペース効率も高くなっています。 Avroは、各フィールドのフィールドタイプ情報を保持しません。代わりに、スキーマにメタデータを作成します。
最後になりましたが、Avroは幅広いプログラミング言語との優れた結合性を備えているため、優位性があります。
いつものように、コードはover on GitHubで見つけることができます。