embulk ruby-filter を書いてみる - column名のprefixやsuffixにtypeをつけてDynamicFieldに使いたい

きっかけ
==

embulk で mysql にLivedoorグルメDatasetを入れてたときにふと思いました。

column名にtypeがついてたら Elasticsearch や Solr の DynamicField に使いやすんじゃないかと。

rename filter ではできなそうで、twitterにポロッと書いたら助言を頂いて、plugin書いてみようかなと思った次第です。

普段はbash書いたり、ちょこっとPythonを書くくらいですが、たしかに書けそうな気がするなー、文字列連結するだけだもんなー、と思ったのでやってみることにしました。rubyはchefでちょっとだけ書いたことがある程度です。


embulk plugin を作ってみる
===

設計
---

|column|type   |output          |
|:---- |:---   |:----           |
|name  |string |name_s とか s_name とか |
|id    |long   |id_l とか l_id とか |


プラグインテンプレートを作る
---

```
$ embulk new ruby-filter affix
```

```
$ tree embulk-filter-affix/
embulk-filter-affix/
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── embulk-filter-affix.gemspec
└── lib
    └── embulk
        └── filter
            └── affix.rb

3 directories, 6 files
$
```

動作確認できるようにしておく
---

* restaurants.csv: Livedoorグルメデータセットのレストラン情報
* seed.yml: embulk guess で使うやつ


```yaml:seed.yml
in:
  type: file
  path_prefix: restaurants.csv
filters:
  - type: affix
    affix: prefix
out:
  type: stdout
```

filters はこんなふうに使えたらいいかな、という希望で書いてみた。

```
$ embulk guess seed.yml
```

で確認して

```
$ embulk guess seed.yml -o config.yml
```

で config.ymlを出力

試しにembulk preview
---

試しにpreviewしてみようとすると

```
$ embulk preview config.yml -L embulk-filter-affix -G
(略)
Error: Required field "option1" is not set
$
```

embulk-filter-affix/lib/embulk/filter/affix.rb を見ると option1 が integer で required みたいなので


```yml
(略)
filters:
  - type: affix
    affix: prefix
    option1: 10
(略)
```

こんな感じにして再実行してみると


```
$ embulk preview config.yml -L embulk-filter-affix -G
（省略）
*************************** 60 ***************************
（省略）
          example (   string) : example
           column (     long) : 1
            value (   double) : 1.0
```

csvに無いカラムが３つ追加され、とりあえずサンプルは動くことが確認できる。


本題：column名のprefixやsuffixにtypeをつけてたい
----

### code


```ruby:embulk-filter-affix/lib/embulk/filter/affix.rb
module Embulk
  module Filter

    class Affix < FilterPlugin
      Plugin.register_filter("affix", self)

      def self.transaction(config, in_schema, &control)
        task = {
          "affix" => config.param("affix", :string, default: "suffix"),
        }

        columns = []

        in_schema.each do |record|
          if task['affix'] == "suffix" then
            name = record.name + "_" + record.type.to_s[0]
          elsif task['affix'] == "prefix" then
            name = record.type.to_s[0]  + "_" + record.name
          else
            name = record.name
          end
          column = Column.new(nil, name, record.type)
          columns.push(column)
        end

        out_columns = columns

        yield(task, out_columns)
      end

      def init
        # initialization code:
        @affix = task["affix"]
      end

      def close
      end

      def add(page)
        page.each do |record|
          page_builder.add(record)
        end
      end

      def finish
        page_builder.finish
      end
    end

  end
end
```

### 実行結果

```yml:config.yml
(略)
filters:
  - type: affix
    affix: suffix
(略)
```

だと

```
$ embulk preview config.yml -L embulk-filter-affix -G
（略）
*************************** 62 ***************************
               id_l (     long) : 65
             name_s (   string) : 備長
（略）
     access_count_l (     long) : 2,370
       created_on_t (timestamp) : 2000-09-10 11:22:02 UTC
      modified_on_t (timestamp) : 2011-04-21 12:00:19 UTC
           closed_l (     long) : 0
```



```yml:config.yml
(略)
filters:
  - type: affix
    affix: prefix
(略)
```

だと

```
$ embulk preview config.yml -L embulk-filter-affix -G
（略）
*************************** 62 ***************************
               l_id (     long) : 65
             s_name (   string) : 備長
（略）
       t_created_on (timestamp) : 2000-09-10 11:22:02 UTC
      t_modified_on (timestamp) : 2011-04-21 12:00:19 UTC
           l_closed (     long) : 0
```

できたー！


### gem を作る

```
$ cd embulk-filter-affix
$ rbenv install jruby-9.1.5.0
$ rbenv exec gem install bundler
$ bundle install
$ rake
embulk-filter-affix 0.1.0 built to pkg/embulk-filter-affix-0.1.0.gem.
$
```

とりあえずのgithub
---

https://github.com/imura81gt/embulk-filter-affix

公開してみる
------

### gemspec 修正

gemspecファイルを修正する。

```
$ git diff embulk-filter-affix.gemspec
diff --git a/embulk-filter-affix.gemspec b/embulk-filter-affix.gemspec
index 11d2dfe..e8c8c5e 100644
--- a/embulk-filter-affix.gemspec
+++ b/embulk-filter-affix.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
   spec.description   = "Affix"
   spec.email         = ["imura81gt@gmail.com"]
   spec.licenses      = ["MIT"]
-  # TODO set this: spec.homepage      = "https://github.com/imura81gt/embulk-filter-affix"
+  spec.homepage      = "https://github.com/imura81gt/embulk-filter-affix"

   spec.files         = `git ls-files`.split("\n") + Dir["classpath/*.jar"]
   spec.test_files    = spec.files.grep(%r{^(test|spec)/})
$
```

git commit しておく。

rubygems.org にアカウントを作っておく。

```
$ gem push
```

で認証情報を入れておく。

リリース!!!!!!!!!

```
$ rake release
embulk-filter-affix 0.1.0 built to pkg/embulk-filter-affix-0.1.0.gem.
Tag v0.1.0 has already been created.
Pushed embulk-filter-affix 0.1.0 to rubygems.org.
$
```

```
$ embulk gem search embulk-filter-affix
2017-04-09 10:59:20.013 +0900: Embulk v0.8.17

*** REMOTE GEMS ***

embulk-filter-affix (0.1.0)
$
```

> Customization — Embulk 0.8 documentation
> > http://www.embulk.org/docs/customization.html#creating-plugins