Apache Avroのガイド
1.概要
データ直列化は、データをバイナリ形式またはテキスト形式に変換する手法です。この目的のために利用可能な複数のシステムがあります。
Apache Avro
は、これらのデータ直列化システムの1つです。
-
Avroは、言語に依存しない、スキーマベースのデータ直列化ライブラリです。スキーマを使用してシリアライゼーションとデシリアライゼーションを実行します。
さらに、AvroはJSON形式を使用してデータ構造を指定し、それをより強力にします。
このチュートリアルでは、Avroセットアップ、シリアル化を実行するためのJava API、およびAvroと他のデータシリアル化システムとの比較について詳しく説明します。
システム全体の基盤となるスキーマの作成に主に焦点を当てます。
2. Apache Avro
Avroは、言語に依存しないシリアル化ライブラリです。これを実行するために、Avroはコアコンポーネントの1つであるスキーマを使用します。それは
さらなるデータ処理
のためにファイルにスキーマを格納します。
Avroはビッグデータ処理に最適です。 HadoopとKafkaの世界では、処理が速いという点で非常に人気があります。
Avroは、メタデータセクションにスキーマと一緒にデータを保持するデータファイルを作成します。何よりも、それは他の同様のソリューションよりも人気がある豊富なデータ構造を提供します。
シリアル化にAvroを使用するには、以下の手順に従う必要があります。
3.問題ステートメント
例として使用する
AvroHttRequest
というクラスの定義から始めましょう。このクラスはプリミティブ型と複合型の属性を含みます。
class AvroHttpRequest {
private long requestTime;
private ClientIdentifier clientIdentifier;
private List<String> 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.baeldung.avro",
"fields":[ {
"name":"hostName",
"type":"string"
},
{
"name":"ipAddress",
"type":"string"
}
]}
5. Avroを使う
最初に、
pom.xml
ファイルに必要なMavenの依存関係を追加しましょう。
以下の依存関係を含める必要があります。
-
Apache Avro – コアコンポーネント
-
コンパイラ – Avro IDLおよびAvro固有のJava用のApache Avroコンパイラ
APIT
** ツール – Apache Avroコマンドラインツールとユーティリティを含みます。
-
Mavenプロジェクト用のApache Avro Mavenプラグイン
このチュートリアルではバージョン1.8.2を使用しています。
しかし、それは常にhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22avro%22%20AND%20g%3A%22org.apache.avro%で最新バージョンを見つけることをお勧めします22[メイヴン中央]:
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro-compiler</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.8.2</version>
</dependency>
Mavenの依存関係を追加した後の次の手順は、
-
スキーマ作成
-
私たちのプログラムでスキーマを読む
-
Avroを使ってデータをシリアル化する
-
最後に、データをデシリアライズする
6.スキーマ作成
Avroは、JSON形式を使用してそのスキーマを説明しています。特定のAvroスキーマには、主に4つの属性があります。
-
Type-
は、その複合型かどうかにかかわらず、スキーマの型を表します。
原始値
**
Namespace-
は、指定されたスキーマが存在するネームスペースを表します。
属する
**
Name
– スキーマの名前
-
Fields-
は、特定のスキーマに関連付けられているフィールドについて説明します。 -
フィールドは、複合型** と同様に原始的なものにすることができます。
スキーマを作成する1つの方法は、前のセクションで見たように、JSON表現を書くことです。
SchemaBuilder
を使ってスキーマを作成することもできます。
6.1.
SchemaBuilder
ユーティリティ
クラス
org.apache.avro.SchemaBuilder
は、スキーマを作成するのに役立ちます。
最初に、__ClientIdentifierのスキーマを作成しましょう。
Schema clientIdentifier = SchemaBuilder.record("ClientIdentifier")
.namespace("com.baeldung.avro")
.fields().requiredString("hostName").requiredString("ipAddress")
.endRecord();
それでは、これを使って
avroHttpRequest
スキーマを作成しましょう。
Schema avroHttpRequest = SchemaBuilder.record("AvroHttpRequest")
.namespace("com.baeldung.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
を割り当てたことです。この場合、typeを定義するために使用される
clientIdentifier
は、以前に作成したものと同じスキーマです。
後で
toString
メソッドを適用して
Schema
の
JSON
構造体を取得できます。
-
スキーマファイルは** .avsc拡張子を使用して保存されます。生成したスキーマを
“ src/main/resources/avroHttpRequest-schema.avsc”
ファイルに保存しましょう。
7.スキーマを読む
スキーマを読むことは、多かれ少なかれ
与えられたスキーマのためのAvroクラスを作成すること
についてです。 Avroクラスが作成されたら、それらを使用してオブジェクトをシリアル化および逆シリアル化できます。
Avroクラスを作成する方法は2つあります。
-
プログラムによるAvroクラスの生成:クラスを生成することができます
SchemaCompiler
を使用します。 Javaクラスを生成するために使用できるAPIがいくつかあります。 GitHubで生成クラスのコードを見つけることができます。
-
Mavenを使ってクラスを生成する
我々はうまく仕事をする1つのMavenプラグインを持っています。プラグインをインクルードして
mvn clean install
を実行する必要があります。
プラグインを
pom.xml
ファイルに追加しましょう。
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>${avro.version}</version>
<executions>
<execution>
<id>schemas</id>
<phase>generate-sources</phase>
<goals>
<goal>schema</goal>
<goal>protocol</goal>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>${project.basedir}/src/main/resources/</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
8. Avroによるシリアライゼーションとデシリアライゼーション
スキーマの生成が終わったら、引き続きシリアライゼーション部分を調べていきましょう。
Avroがサポートするデータシリアライゼーションフォーマットは、JSONフォーマットとBinaryフォーマットの2つです。
まず、JSON形式に焦点を絞り、次にBinary形式について説明します。
先に進む前に、いくつかの重要なインターフェースについて説明します。以下のインターフェースとクラスを直列化に使用できます。
DatumWriter <T>:
与えられたスキーマにデータを書き込むためにこれを使うべきです。
この例では
SpecificDatumWriter
実装を使用しますが、
DatumWriter
には他の実装もあります。他の実装は__GenericDatumWriter、Json.Writer、ProtobufDatumWriter、ReflectDatumWriter、ThriftDatumWriterです。
Encoder
:エンコーダーが使用されるか、または前述のようにフォーマットを定義します。
EncoderFactory
は、2種類のエンコーダ、バイナリエンコーダ、およびJSONエンコーダを提供します。
DatumReader <D>:
シリアル化解除のための単一のインタフェース。繰り返しますが、複数の実装がありますが、この例では
SpecificDatumReader
を使用します。他の実装は
GenericDatumReader、Json.ObjectReader、Json.Reader、ProtobufDatumReader、ReflectDatumReader、ThriftDatumReader.
です。
Decoder:
Decoderはデータのデシリアライズ中に使用されます。
Decoderfactory
は、2種類のデコーダ、バイナリデコーダとJSONデコーダを提供します。
次に、Avroでシリアライゼーションとデシリアライゼーションがどのように行われるかを見てみましょう。
8.1. 直列化
AvroHttpRequest
クラスの例を取り、Avroを使用してそれをシリアル化しようとします。
まずはじめに、JSON形式でシリアル化しましょう。
public byte[]serealizeAvroHttpRequestJSON(
AvroHttpRequest request) {
DatumWriter<AvroHttpRequest> 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
インターフェイスを使用します。
Encoderを取得するために
EncoderFactory
を使用したので、
Decoder
オブジェクトを取得するために同様に
DecoderFactory__を使用します。
JSON形式を使用してデータをデシリアライズしましょう。
public AvroHttpRequest deSerealizeAvroHttpRequestJSON(byte[]data) {
DatumReader<AvroHttpRequest> 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は、幅広いプログラミング言語と密接に結び付いています。
いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/apache-avro[over on GitHub]にあります。