LoginSignup
10
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-12-01

概要

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)

10
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
0