2015年12月3日木曜日

EmbulkのFILTER系プラグインを使ってみた(embulk-filter-column,embulk-filter-row)

こんにちは、井下です。

しばらく触れられていませんでしたが、久しぶりにEmbulkについて書いていきます。
タイトル通り、2つのFILTER系プラグインを使ってみて、どのようにデータをいじれるのかを検証してみます。
なお、検証のために使うデータ・ymlファイルのベースは、Embulkのexampleコマンド⇒guessコマンドによって生成されるデータ・ymlファイルです。


ちなみに以前書いたEmbulkの内容は以下の通りです。

1.embulk-filter-column

2015年12月現在、FILTER系では一番ダウンロードされている(GitHubから)プラグイン、embulk-filter-columnです。
主にできることは"カラムの絞り込み"と"カラムの追加"です。

GitHub上のREADMEではExampleとして"columns"、"add_columns"、"drop_columns"の説明があります。
"add_columns"は"カラムの追加"、"drop_columns"は"カラムの絞り込み"、"columns"は"カラムの絞り込みとカラムの追加の両方"に対応しています。

1-1.add_columnsの例

add_columnsでは2通りのカラムの追加方法があります。

1つ目は、追加するカラムのデフォルト値を用意する方法。
2つ目は、元々存在しているカラムの値をコピーし、新しいカラムとする方法。

例として、1つ目の方法として"add_time"カラムを追加し、2つ目の方法として"copy_id"カラムを追加します。

データ(guessコマンドの自動生成のまま。特筆しない限り以降も同じデータです)
id,account,time,purchase,comment
1,32864,2015-01-27 19:23:49,20150127,embulk
2,14824,2015-01-27 19:01:23,20150127,embulk jruby
3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
4,11270,2015-01-29 11:54:36,20150129,NULL

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: column
    add_columns:
      - {name: add_time, type: timestamp, default: '20151201', format: "%Y%m%d" }
      - {name: copy_id, src: id}
out: {type: stdout}

なお、デフォルト値は"default"キーに指定します。上記のymlファイルでは"20151201"を指定しました。
コピー元のカラムは"src"キーに指定します。上記のymlファイルでは"id"を指定しました。

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+--------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |             comment:string |      add_time:timestamp | copy_id:long |
+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+--------------+
|       1 |       32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC |                     embulk | 2015-12-01 00:00:00 UTC |            1 |
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |               embulk jruby | 2015-12-01 00:00:00 UTC |            2 |
|       3 |       27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin | 2015-12-01 00:00:00 UTC |            3 |
|       4 |       11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC |                       NULL | 2015-12-01 00:00:00 UTC |            4 |
+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+--------------+

実行結果を見ると、ymlファイル内で定義した通りの値で、"add_time"カラムと"copy_id"カラムが追加されていることが分かります。
※カラム名を分かりやすくするため、previewの実行結果を表示しています。timestamp型のデータにタイムゾーンが表示されているのはそのためです。
 なお、runの場合、"add_time"の値は"2015-12-01 00:00:00.000000 +0000"と表示されていました




ところで"default"キーと"src"キーはどちらかの設定が必須になっていますが、どちらも設定した場合はどうなるのでしょうか?

GitHub上では説明されていなかったので、検証してみたところ、基本的に"src"キーで設定した値をコピーしていました。
ただし、コピー元のカラムのうち、空となっているデータがある場合、そのデータは"default"キーの値によって上書きしていました。

要約すると、"カラムをコピーしつつ、空データがあれば初期値を設定できる"ということになります。
空のデータがあると困る場合などに使えるかもしれませんね。

ちなみに、検証に利用したデータ・ファイル・結果は下記の通りです。

データ(緑字を追記)
id,account,time,purchase,comment
1,32864,2015-01-27 19:23:49,20150127,embulk
2,14824,2015-01-27 19:01:23,20150127,embulk jruby
3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
4,11270,2015-01-29 11:54:36,20150129,NULL
5,,,,

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: column
    add_columns:
      - {name: add_time, type: timestamp, default: '2015-12-01', format: "%Y-%m-%d", src: time }
out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |             comment:string |      add_time:timestamp |
+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+
|       1 |       32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC |                     embulk | 2015-01-27 19:23:49 UTC |
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |               embulk jruby | 2015-01-27 19:01:23 UTC |
|       3 |       27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin | 2015-01-28 02:20:02 UTC |
|       4 |       11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC |                       NULL | 2015-01-29 11:54:36 UTC |
|       5 |              |                         |                         |                            | 2015-12-01 00:00:00 UTC |

+---------+--------------+-------------------------+-------------------------+----------------------------+-------------------------+


1-2.drop_columnsの例

"drop_columns"は非常にシンプルで、指定したカラムを出力結果から除外します。
設定方法は"name"キーでカラムを指定するだけで、それ以外のキーやオプション設定は存在しません。

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: column
    drop_columns:
      - {name: comment}
out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |
+---------+--------------+-------------------------+-------------------------+
|       1 |       32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC |
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |
|       3 |       27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC |
|       4 |       11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC |
+---------+--------------+-------------------------+-------------------------+

実行結果を見ると、"comment"カラムが出力されていないことが分かります。


1-3.columnsの例

最後に"add_columns"と"drop_columns"を内包する"columns"です。
カラムの追加設定に関しては"add_columns"と同じですが、カラムの絞り込みに関しては"drop_columns"とは逆に、設定したカラムのみを出力します。

データ(緑字を追記)
id,account,time,purchase,comment
1,32864,2015-01-27 19:23:49,20150127,embulk
2,14824,2015-01-27 19:01:23,20150127,embulk jruby
3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
4,11270,2015-01-29 11:54:36,20150129,NULL
5,,,,

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: column
    columns:
      - {name: id}
      - {name: copy_id, src: id }
      - {name: add_time, type: timestamp, default: '2015-12-01', format: "%Y-%m-%d", src: time }
out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+
| id:long | copy_id:long |      add_time:timestamp |
+---------+--------------+-------------------------+
|       1 |            1 | 2015-01-27 19:23:49 UTC |
|       2 |            2 | 2015-01-27 19:01:23 UTC |
|       3 |            3 | 2015-01-28 02:20:02 UTC |
|       4 |            4 | 2015-01-29 11:54:36 UTC |
|       5 |            5 | 2015-12-01 00:00:00 UTC |
+---------+--------------+-------------------------+

"add_columns"と同様の設定で"copy_id"カラムと"add_time"カラムが出力されている一方、"id"、"copy_id"、"add_time"以外のカラムは出力されていません。


現状のデータにカラムを追加したい場合は"add_columns"、現状のデータから不要なカラムを削除したい場合は"drop_columns"、指定したカラムだけ出力・また別途カラムを追加したい場合は"columns"という使い分けができそうですね。

2.embulk-filter-row

"embulk-filter-column"を検証したということで、対の関係(?)になる"embulk-filter-column"についての検証です。
主にできることは、"カラムのデータによる絞り込み"です。イメージとしては、Excelのフィルターに近く、指定したカラムのうち、指定した条件を満たすレコードを出力します。

どんな絞り込みができるかはGitHub上のREADMEに記載してあります。
単純なtrue、false、数値の大小・完全一致のほか、文字列に指定した値を含むか(オプションを含めばその逆も)、前方一致や後方一致での絞りこみを行えます。

では、単純な例として、"id"カラムが1より大きいデータのみ出力してみます。

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: row
    conditions:
      - {column: id, operator: '>', argument: 1}
out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+----------------------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |             comment:string |
+---------+--------------+-------------------------+-------------------------+----------------------------+
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |               embulk jruby |
|       3 |       27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin |
|       4 |       11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC |                       NULL |
+---------+--------------+-------------------------+-------------------------+----------------------------+

"id"カラムが1になっているデータが出力されなくなっています。

今度はさらに"id"カラムに4未満の条件を追加してみます。

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: row
    conditions:
      - {column: id, operator: '>', argument: 1}
      - {column: id, operator: '<', argument: 4}
out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+----------------------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |             comment:string |
+---------+--------------+-------------------------+-------------------------+----------------------------+
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |               embulk jruby |
|       3 |       27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin |
+---------+--------------+-------------------------+-------------------------+----------------------------+

"id"カラムが4になっているデータも出力されなくなっています。

最後に"comment"カラムに"embulk"が含まれる条件を追加してみます。

Embulkの読み込み用ymlファイル(緑字を追記)
in:
  type: file
  path_prefix: ~/lib/try1/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
  - type: row
    conditions:
      - {column: id, operator: '>', argument: 1}
      - {column: id, operator: '<', argument: 4}
      - {column: comment, operator: 'include', argument: 'embulk' }

out: {type: stdout}

実行結果(preview)
+---------+--------------+-------------------------+-------------------------+----------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp | comment:string |
+---------+--------------+-------------------------+-------------------------+----------------+
|       2 |       14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC |   embulk jruby |
+---------+--------------+-------------------------+-------------------------+----------------+

先ほどまでの絞り込み結果に対して、新たに"comment"カラムで絞り込まれています。

ちなみに今のところ、サポートしているのはand条件のみとなっています。
※GitHubではor条件がToDoとして記載されているので、そのうち使えるようになるかもしれません


今回はデータの絞り込みということで、よく使われそうなプラグインを使ってみましたが、次回はもう少し独特なプラグインや、プラグイン同士の組合せについて書こうと考えています。

0 件のコメント:

コメントを投稿