Embulkを用いたダミーデータの生成

開発中のシステムの動作検証をするとき、少なからずシードデータやダミーのデータが必要となることが多いと思います。

私が携わった業務の中でも「パフォーマンス検証用に十数カラム数千万レコードのデータを用意しなければ」ということがあり、その際[Embulk](https://www.embulk.org/docs/)が非常に役立ったため生地に残したいと思います。

# Embulkの便利なところ

まずEmbulkとは、よく「Fluentdのバッチ版」と説明されますがその通りで、大量データの転送、加工（ETL）処理を行うことができます。

今回Embulkを扱うことの利点として以下が挙げられます。

- 様々なプラグインを利用できる
- インプット先、アウトプット先が多様
- 設定ファイルを書くだけで実行できる

多数あるプラグインを用いることで、ファイルやDB、クラウドサービスまで様々なデータソースを利用することが可能です。
また、「どこからデータを取ってきて、どこに送るのか」、「データをどう変換・加工するのか」をyamlファイルだけで定義できるのですぐに使い始めることができます。

# ダミーデータ生成

今回はランダムデータを生成してくれる[embulk-input-randomj](https://github.com/yuokada/embulk-input-randomj)というインプットプラグインを利用します。

また、出力はホストPC内のCSVファイルとします。

## プラグインのインストール

※ Embulk自体の実行環境は整っている前提とします。

embulk-input-randomjプラグインをインストールします。

```sh
$ embulk gem install embulk-input-randomj
```

## 設定ファイルを作成

作成するダミーデータのフォーマットを設定するため、下記に示す`config.yml`ファイルを作成します（ファイル名はすきに変更して大丈夫です）。
今回は気軽に試せるように生成するレコード数は少なく設定しています。

```yml:config.yml
in:
  type: randomj
  rows: 100
  threads: 4
  primary_key: id
  schema:
  - {name: id, type: long}
  - {name: name, type: string}
  - {name: hash, type: string, length: 16}
  - {name: hobby, type: string, null_rate: 1000}
  - {name: price, type: long}
  - {name: day, type: long, min_value: 1, max_value: 31}
  - {name: average, type: double}
  - {name: rate, type: double, min_value: -100, max_value: 100}
  - {name: flag, type: boolean}
  - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
  - {name: date, type: timestamp, format: '%Y-%m-%d', start_date: 20180101, end_date: 20201231}

out:
  type: file
  path_prefix: output_
  file_ext: csv
  formatter:
    type: csv
    header_line: true
    charset: UTF-8
    newline: CRLF
    column_options:
      time: {format: '%Y-%m-%d %H:%M:%S'}
      date: {format: '%Y-%m-%d'}
```

### randomjプラグインの設定について

randojプラグインの設定パラメータは次の通りです。

| パラメータ名 | 説明 |
|---|---|
| rows | 生成するレコード数（スレッド単位） |
| threads | スレッド数 |
| primary_key | 主キーカラムの指定。指定したカラムは連番の値となる。 |
| schema | カラムの設定 |

生成される総レコード数は`rows * threads`の値となります。上記設定ファイルだと`100 * 4 = 400`レコード分だけ生成されます。

## 実行

次のコマンドでEmbulkを実行します。

```sh
$ embulk run config.yml
```

（なお、`embulk preview config.yml`でdry-runもできます。）

処理が終了すると、実行ディレクトリ下に`output_*.csv`というファイルが複数生成されているのが確認できます。
ファイル数は並列実行数すなわちスレッド数とCPUコア数によって異なります。

```sh
$ ls -l
total 168
-rw-r--r--  1 uro3  staff    934  2 16 15:01 config.yml
-rw-r--r--  1 uro3  staff  16569  2 16 15:02 output_000.00.csv
-rw-r--r--  1 uro3  staff      0  2 16 15:02 output_001.00.csv
-rw-r--r--  1 uro3  staff  16639  2 16 15:02 output_002.00.csv
-rw-r--r--  1 uro3  staff      0  2 16 15:02 output_003.00.csv
-rw-r--r--  1 uro3  staff  16679  2 16 15:02 output_004.00.csv
-rw-r--r--  1 uro3  staff      0  2 16 15:02 output_005.00.csv
-rw-r--r--  1 uro3  staff  16643  2 16 15:02 output_006.00.csv
-rw-r--r--  1 uro3  staff      0  2 16 15:02 output_007.00.csv
```

生成するレコード数が少なかったり、threadsパラメータの値を低くすると空のファイルが生成されることもあります（上記実行例でも空ファイルが生成されてしまってますね）。

ファイルの中身を確認してみます。

```sh
$ head -n 5 output_000.00.csv
1,dQYp5qfwcs4LEG8tpXXcL9nk8T5z8p0b,6jrmeMklNClY6z9D,uQDLLqDIzEGr04lZ1sk1HfSBTtPXrC4d,2627,1,9319.759903806967,-60.2255006491297,true,2020-05-03 06:09:20,2019-12-18
2,2zzN94AhX7dKEPj7iYNqpa1bFzis44RW,ymz2GQL7gGXLDHAq,6mlKrDC3I0vfDVGppW7W4YRj19WlPyHX,5883,13,4519.424678970713,16.01039975680497,true,2020-05-26 17:54:12,2018-08-21
3,6Lh4yZlDd6bNJMi6JWjcFafcufP5CsYw,H7egv5rdCgPgOxGo,GfOFodiZgcm115ja4EnhXMrdGGEwiB4r,1323,28,750.4551048594033,29.261926615295117,true,2020-03-30 20:29:09,2018-07-01
4,QcN0omRoNepFEmXycolrfmF5EetNTWR0,yjty1bTTb9ns0o9L,WF7lS4Ules7qjh7ECsx4zVpB28JwWmUg,8218,27,1103.5836005487843,30.128739554862438,false,2020-06-05 18:59:53,2020-01-13
5,rUQc8nXMLa2S6Q2ecXOUODx0B2SPOtLF,2VuDAxO4cu1i5F9u,DFQMU8DpiCnf6WTbRvPzu4qSY2C5SU5N,385,25,7301.194699442833,6.115086705050664,true,2020-03-05 03:01:28,2019-01-02
```

設定通りのデータができているようです。

生成された複数のファイルを一つのファイルにまとめたいときはcatコマンドを使いましょう。

```sh
$ cat output_*.csv >> result.csv
```

# もう少しリッチなダミーデータ

基本的に文字列は完全にランダムな値なのでなんだか味気ないですよね。
そこで、他のfilterプラグインを活用して少しだけデータをリッチにしてみましょう。

今回は下記のプラグインを利用します。

- [embulk-filter-gsub](https://github.com/cesare/embulk-filter-gsub)
- [embulk-filter-typecast](https://github.com/sonots/embulk-filter-typecast)

embulk-filter-gsubは正規表現にマッチした文字列を任意の文字列に変換するプラグインです。
embulk-filter-typecastはカラムの型をキャストするプラグインです。embulk-filter-gsubで変換するにはstring型にする必要があるため、このプラグインを利用して型を変換します。

インストールコマンドは次の通りです。

```sh
$ embulk gem install embulk-filter-gsub embulk-filter-typecast
```

新しく`config_2.yml`という名前で設定ファイルを作成します。

```yml:config_2.yml
in:
  type: randomj
  rows: 100
  threads: 4
  primary_key: id
  schema:
  - {name: id, type: long}
  - {name: filename, type: string, length: 8}
  - {name: device, type: boolean}
  - {name: weekday, type: long, min_value: 0, max_value: 6}

filters:
- type: typecast
  columns:
  - {name: "device", type: string}
  - {name: "weekday", type: string}
- type: gsub
  target_columns:
    filename:
    - {type: regexp_replace, pattern: (^.*$), to: $1.txt}
    device:
    - {type: regexp_replace, pattern: 'true', to: PC}
    - {type: regexp_replace, pattern: 'false', to: SP}
    weekday:
    - {type: regexp_replace, pattern: '0', to: 日}
    - {type: regexp_replace, pattern: '1', to: 月}
    - {type: regexp_replace, pattern: '2', to: 火}
    - {type: regexp_replace, pattern: '3', to: 水}
    - {type: regexp_replace, pattern: '4', to: 木}
    - {type: regexp_replace, pattern: '5', to: 金}
    - {type: regexp_replace, pattern: '6', to: 土}

out:
  type: file
  path_prefix: output_
  file_ext: csv
  formatter:
    type: csv
    header_line: false
    charset: UTF-8
    newline: CRLF
```

`filename`カラムにはサフィックスとして拡張子をつけるようにしました。
また、`device`カラムにはPCかSPという文字列が、`weekday`カラムには曜日を表す文字列がそれぞれ入ります。

それでは実行してみます。

```sh
$ embulk run config_2.yml
```

生成されたファイルの中身を確認してみます。

```sh
$ head -n 5 output_000.00.csv
1,udbQMu8j.txt,SP,木
2,PwdY5iJb.txt,SP,金
3,gtB79Y5W.txt,SP,金
4,DFSVa32v.txt,SP,月
5,jqSdcCGu.txt,PC,日
```

これである程度規則のあるデータも作成することができました。

# まとめ

Embulkのembulk-input-randomjプラグインを使うことでダミーデータを簡単に生成することができます。

今回はcsvファイルとして作成しましたが、他にもDBやクラウドストレージにデータ挿入することもできたいへん便利です。
なお、生成するレコード数や出力先によってはある程度のマシンパワーが必要となるのでご注意ください。

# 参考

- [Fluentdのバッチ版Embulk(エンバルク)のまとめ](https://qiita.com/hiroysato/items/397f36c4838a0a93e352)
- [Embulk(エンバルク)プラグインのまとめ](https://qiita.com/hiroysato/items/da45e52fb79c39547f69)