とにかくGolangでAvroを使わせろ


概要

Apache Avroにはデータ・スキーマを用いて永続化や通信を行うデータを圧縮する為の仕様「A compact, fast, binary data format.(コンパクトで高速なバイナリ形式データ)」があります。
本記事ではAvroの詳細まで言及しませんが、この仕様をGolangで実装して圧縮されたデータを実感してみたいと思います。

データ圧縮の準備

Avroスキーマ

Avroバイナリデータに圧縮するには、予めデータ構造のスキーマ定義を作成する必要があります。
まずは2つの項目を持つ簡単なスキーマを定義します。
(後ほどGolangのソースコード内でstringデータとして使用します)

{
  "namespace": "TestSchema",
  "type": "record",
  "name": "TestData",
  "fields" : [
    { "name" : "id", "type" : "int" }, { "name" : "value", "type" : "string" }
  ]
}

圧縮前のデータ(JSON)

スキーマにはint型の"id"と言う名前の項目とstring型の"value"と言う2つの項目が定義されています。
この定義に沿った以下のJSONデータを作成します。

{"id":10001,"value":"test_value"}

データ圧縮ロジック

Goライブラリ

以下のコマンドを実行してライブラリを取得します。

go get "github.com/linkedin/goavro"

シリアライズ処理手順

以下の手順で実行します。

// 1.JSON文字列をGolangのプリミティブ型のデータへ変換
// 1-1.スキーマを設定したCodecを生成
codec, _ := goavro.NewCodec(`
  {
    "namespace": "TestSchema",
    "type": "record",
    "name": "TestData",
    "fields" : [
      { "name" : "id", "type" : "int" }, { "name" : "value", "type" : "string" }
    ]
  }`)

// 1-2.JSON文字列をGoデータへ変換
textual := []byte(`{"id":10001,"value":"test_value"}`)
native, _, err := codec.NativeFromTextual(textual) // nativeはmap[string]interface{}型
if err != nil {
  panic(err)
}
log.Printf("textual length:[%d]\n", len(textual))

// 2.GoデータをAvroバイナリへシリアライズ
binary, err := codec.BinaryFromNative(nil, native) // binaryは[]byte型
if err != nil {
  panic(err)
}
log.Printf("binary length:[%d]\n", len(binary))

処理結果

元のJSON文字列33バイトから、バイナリデータ変換後は14バイトまで圧縮されています。

textual length:[33]
binary length:[14]

デシリアライズ処理手順

以下の手順で実行します。
Codecはシリアライズと同じものを使用できます。

// 3.AvroバイナリデータをGoデータへデシリアライズ
native, _, err := codec.NativeFromBinary(binary)
if err != nil {
  panic(err)
}
log.Printf("Deserialized:%v\n", native)

// 4.JSON文字列に戻すことも可能
textual, err := codec.TextualFromNative(nil, native)
if err != nil {
  panic(err)
}
log.Printf("JSON string :%v\n", string(textual))

処理結果

バイナリから復元されたデータはmap[string]interface{}型に変換されます。

Deserialized:map[id:10001 value:test_value]
JSON string :{"value":"test_value","id":10001}

どの辺がポイント?

・データ構造の情報を持たない
 シリアライズにもデシリアライズにもスキーマ定義が必要で、その管理も必要になりますが、スキーマに書かれている情報を持つ必要が無いのでデータは小さくなります。
 永続化にも通信にも有用です。


取り急ぎGolangでAvroのデータを扱いたい時は上記ソースコードをコピペして、スキーマ定義とJSON文字列を適切な値へ置換してください。(エラー処理の実装も忘れずに)

Appendix

*Apache Avro公式ページ
*linkedin/goavro(Github)