JRubyからEmbulkEmbedを動かす

# 目的

* Embulkを複数回連続実行したときの処理時間を削減するためにEmbulkEmbedを利用したい
* しかし、Java を書きたくはない

JRubyからEmbulkを呼び出してみる

この記事は[Emblkの利用でミスマッチをしてしまった話](https://qiita.com/jca02266/items/394d77b1ace097404e5e)の続きであり、細かいことはそちらに記載してある

# Embulk バージョン

```console
embulk --version
embulk 0.9.1
```

# インストール

embulk本体のインストール

公式(https://github.com/embulk/embulk#linux--mac--bsd)

```
$ curl --create-dirs -o ~/.embulk/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar"
$ chmod +x ~/.embulk/bin/embulk
$ echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc
$ embulk --version
embulk 0.9.1
```

# Embulk をサンプルで実行してみる

```console
$ embulk example ./work
$ embulk guess work/seed.yml -o config.yml
$ embulk preview config.yml

+---------+--------------+-------------------------+-------------------------+----------------------------+
| id:long | account:long |          time:timestamp |      purchase:timestamp |             comment:string |
+---------+--------------+-------------------------+-------------------------+----------------------------+
|       1 |       32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC |                     embulk |
|       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 |                            |
+---------+--------------+-------------------------+-------------------------+----------------------------+
```

# EmbulkでCSV出力

```diff:config.yml.diff
--- config.yml.orig  2018-02-11 13:57:36.000000000 +0900
+++ config.yml 2018-02-11 14:11:55.000000000 +0900
@@ -21,4 +21,13 @@
     - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
     - {name: purchase, type: timestamp, format: '%Y%m%d'}
     - {name: comment, type: string}
-out: {type: stdout}
+
+out:
+  type: file
+  path_prefix: work/sample_
+  file_ext: csv
+  formatter:
+    type: csv
+
+exec:
+  min_output_tasks: 1
```

```console
$ embulk run config.yml
$ ls work/*.csv
sample_000.00.csv
$ head -999 work/*.csv
id,account,time,purchase,comment
1,32864,2015-01-27 19:23:49.000000 +0000,2015-01-27 00:00:00.000000 +0000,embulk
2,14824,2015-01-27 19:01:23.000000 +0000,2015-01-27 00:00:00.000000 +0000,embulk jruby
3,27559,2015-01-28 02:20:02.000000 +0000,2015-01-28 00:00:00.000000 +0000,"Embulk ""csv"" parser plugin"
4,11270,2015-01-29 11:54:36.000000 +0000,2015-01-29 00:00:00.000000 +0000,
```

# JRuby 実行

jruby をわざわざインストールしたくはないので、embulkに入っている
jruby を呼び出してみる

```console
$ java -classpath ~/.embulk/bin/embulk org.jruby.Main -v -e 'puts "Hello, Embulk"'
jruby 9.1.15.0 (2.3.3) 2017-12-07 929fde8 Java HotSpot(TM) 64-Bit Server VM 25.131-b11 on 1.8.0_131-b11 +jit [darwin-x86_64]
Hello, Embulk
```

# EmbulkEmbed を JRuby から実行する

```ruby:embulk_runner.rb
#! ruby

java_import "org.embulk.EmbulkEmbed"

JavaFile = java.io.File

bootstrap = EmbulkEmbed::Bootstrap.new
embulk = bootstrap.initializeCloseable

config_yml = ARGV.shift || "config.yml"

begin
  loader = embulk.newConfigLoader
  config = loader.fromYamlFile JavaFile.new(config_yml)
  embulk.run config
ensure
  embulk.destroy
end
```

```console
$ java -classpath ~/.embulk/bin/embulk org.jruby.Main embulk_runner.rb config.yml
〜省略〜

$ head -999 work/sample_000.00.csv
〜省略〜
```

> 注意: Windowsの場合、javaの文字コードがデフォルトだとMS932になってしまう。これを変更するには、`java -Dfile.encoding=UTF-8`が必要になる。あるいは、あらかじめ環境変数 `set JAVA_TOOLS_OPIONS=-Dfile.encoding=UTF-8`
を設定する。

# Embulk を連続実行してみる

```diff:embulk_runner2.rb
--- embulk_runner.rb    2018-02-11 14:38:19.000000000 +0900
+++ embulk_runner2.rb   2018-02-11 14:35:17.000000000 +0900
@@ -5,14 +5,29 @@
 JavaFile = java.io.File

 bootstrap = EmbulkEmbed::Bootstrap.new
+
+if File.exist?('systemConfig.yml')
+  systemConfig = bootstrap.getSystemConfigLoader().fromYamlFile(JavaFile.new("systemConfig.yml"))
+  bootstrap.setSystemConfig(systemConfig)
+end
+
 embulk = bootstrap.initializeCloseable

 config_yml = ARGV.shift || "config.yml"
+loop_count = (ARGV.shift || 10).to_i

 begin
   loader = embulk.newConfigLoader
   config = loader.fromYamlFile JavaFile.new(config_yml)
-  embulk.run config
+
+  config_in = config.getNested("in")
+  config_out = config.getNested("out")
+  config_out.set("type","file")
+  loop_count.times {|i|
+    config_in.set("path_prefix", "./work/csv/sample_")
+    config_out.set("path_prefix", "./work/sample_output_#{i}_")
+    embulk.run config
+  }
 ensure
   embulk.destroy
 end
```

```ruby:embulk_runner2.rb
#! ruby

java_import "org.embulk.EmbulkEmbed"

JavaFile = java.io.File

bootstrap = EmbulkEmbed::Bootstrap.new

if File.exists?('systemConfig.yml')
  systemConfig = bootstrap.getSystemConfigLoader().fromYamlFile(JavaFile.new("systemConfig.yml"))
  bootstrap.setSystemConfig(systemConfig)
end

embulk = bootstrap.initializeCloseable

config_yml = ARGV.shift || "config.yml"
loop_count = (ARGV.shift || 10).to_i

begin
  loader = embulk.newConfigLoader
  config = loader.fromYamlFile JavaFile.new(config_yml)

  config_in = config.getNested("in")
  config_out = config.getNested("out")
  config_out.set("type","file")
  loop_count.times {|i|
    config_in.set("path_prefix", "./work/csv/sample_")
    config_out.set("path_prefix", "./work/sample_output_#{i}_")
    embulk.run config
  }
ensure
  embulk.destroy
end
```

10回実行

```console
$ time java -classpath ~/.embulk/bin/embulk org.jruby.Main embulk_runner2.rb config.yml 10 >/dev/null

real    0m5.889s
user    0m16.196s
sys     0m0.579s
$ ls -l work/sample_output* | wc -l
     10
```

100回実行

```console
$ time java -classpath ~/.embulk/bin/embulk org.jruby.Main embulk_runner2.rb config.yml 100 >/dev/null

real    0m7.408s
user    0m21.114s
sys     0m0.814s

$ ls -l work/sample_output* | wc -l
     100
```

実行回数に依らず十分速い結果を得ることが出来た