Embulkを使う上で型の不整合に関するエラーに遭遇することが多かったので情報を整理します。Embulkを使う上では、データソース、Embulk、BigQueryの3つの型を意識する必要があります。
この記事では、それぞれのスキーマで定義されている型について紹介し、最後にログファイルのタイムスタンプをBigQueryにロードするときの設定例を紹介します。
データソースの型
ここでいうデータソースはMySQLだったりログファイルだったりです。
データベースの場合は、データベース規定のデータ型があります。ログファイルは全てテキストですが、Rubyでプラグインを書く場合には Ruby のデータ型が対応します。
ちなみに embulk-input-mysql プラグインには次のようにあります。
- value_type: embulk get values from database as this value_type. Typically, the value_type determines getXXX method of java.sql.PreparedStatement. (string, default: depends on the sql type of the column. Available values options are: long, double, float, decimal, boolean, string, json, date, time, timestamp)
- type: Column values are converted to this embulk type. Available values options are: boolean, long, double, string, json, timestamp). By default, the embulk type is determined according to the sql type of the column (or value_type if specified).
MySQLの値はMySQLのスキーマのデータ型 long, double, float, decimal, boolean, string, json, date, time, timestamp のいずれかとして読み込むことができて、Embulkのスキーマのデータ型 boolean, long, double, string, json, timestamp のいずれかに変換されます。
Embulkにおけるデータ型
既にembulk-input-mysqlプラグインで出てきていますが、入力されたデータはEmbulkのスキーマのデータ型に変換されます。Embulkのデータ型は次の5種類です。
型 | 説明 |
---|---|
boolean | 真偽値 |
long | 整数型 |
timestamp | 時刻 |
double | 浮動小数点数 |
string | 文字列 |
データソースから読み込んだデータは上の表のどれかと対応することになります。
たとえば、Rubyの場合であれば boolen-Boolean、long-Integer、timestamp-Time、double-Float、string-String と対応します。
BigQueryにおけるデータ型
BigQueryのスキーマにもデータ型があります。GUIからデータ型(Type)を指定しようとするときに見えるのは、STRING, BYTES, INTEGER, FLOAT, NUMERIC, BOOLEAN, TIMESTAMP, DATE, TIME, DATETIME, GEOGRAPHY, RECORDの12種類です。
公式リファレンスによると標準型SQLのデータ型として説明されています。大枠は同じですが、エイリアスがあるなどして表記がややこしいですね。代表的な例を載せておきます。
型 | 説明 |
---|---|
INTEGER (INT64) | 整数型 |
FLOAT (FLOAT64) | 浮動小数点型 |
BOOLEAN | 真偽値 |
BYTES | 可変長文字バイナリデータ |
DATE | 日付型 YYYY-MM-DD |
DATETIME | 日時型 YYYY-MM-DD HH:mm:ss |
TIME | 時刻型 HH:mm:ss |
TIMESTAMP | タイムスタンプ型 YYYY-MM-DD HH:mm:ss TZ |
STRING | 文字列型 |
embulkとの対応はどうでしょうか?
embulk-output-bigqueryプラグインのオプションの説明では次のようになっています。
- type: BigQuery type such as BOOLEAN, INTEGER, FLOAT, STRING, TIMESTAMP, DATETIME, DATE, and RECORD. See belows for supported conversion type.
- boolean: BOOLEAN, STRING (default: BOOLEAN)
- long: BOOLEAN, INTEGER, FLOAT, STRING, TIMESTAMP (default: INTEGER)
- double: INTEGER, FLOAT, STRING, TIMESTAMP (default: FLOAT)
- string: BOOLEAN, INTEGER, FLOAT, STRING, TIMESTAMP, DATETIME, DATE, RECORD (default: STRING)
- timestamp: INTEGER, FLOAT, STRING, TIMESTAMP, DATETIME, DATE (default: TIMESTAMP)
- json: STRING, RECORD (default: STRING)
Embulkのデータ型boolen, long, double, string, timestamp, jsonは上記の通りに変換することが可能です。逆に言えばここにある以外の変換はできないので実行時にエラーが発生します。
BigQueryの型の説明はこの記事も詳しいです。
実践編:ログファイルのタイムスタンプをBigQueryにロードするには?
では、ここまでの情報を元にログファイルのタイムスタンプを取得してYYYY-MM-DD HH:mm:ssの形でBigQueryに格納する例を考えてみます。
タイムスタンプに関してUTCになって9時間ずれるという事象があります。解決方法はあるようですが、ここではBigQuery上のデータ型をSTRINGにすることでタイムゾーン問題を無視します。
データの流れとしては ログ > Ruby > Embulk > BigQuery になります。データ型はこれに合わせて String > Time > timestamp > STRING のように変換されるように設定します。
まず、parserプラグインで読み込んだ値をTime型に変換してEmbulkのtimestamp型に渡します。
require 'time' raw = '2021-10-25 12:00:00:000' Time.parse(raw)
これでEmbulkはtimestamp型として受け取ることになります。今度は Embulk > BigQuery のときにtimestampをSTRINGとして渡せるようにoutを書きます。
out: column_options: - name: column_name type: STRING timestamp_format: "%Y-%m-%d %H:%M:%S"
これでOKです。(READMEによるとcolumn_optionsはワンラインで書けるはずなのですがうまくいきませんでした。上記の書き方なら行けたので今回は無視しました)