[Embulk] Built-in JSON Parser plugin の新機能のご紹介

## TL;DR
2019/03/11 (JST) にリリースされたEmbulk 0.9.16から、組み込みのJSON parser pluginにいくつかの新機能が正式に追加されました。

これにより、Filter pluginや、既存のOSS JSON parser pluginである[embulk-parser-jsonpath](https://github.com/hiroyuki-sato/embulk-parser-jsonpath), [embulk-parser-jsonl](https://github.com/shun0102/embulk-parser-jsonl) で行っていたいくつかの処理を組み込みのプラグインだけで実施できるようになりました。それらの新機能や既存のOSSのプラグインとの違いを解説します。

## (おさらい) 既存のJSON parser pluginの挙動
複数のJSON objectを入力として、1オブジェクトをEmbulkにおけるJSON型1カラムを持つレコードとして読み込みます。

```json
{"id": 1, "name": "Alice"}
{"id": 2, "name": "Bob"}
```
```yaml
in:
  type: ...
  parser:
    type: json
```
```
+-------------------------+
|             record:json |
+-------------------------+
| {"id":1,"name":"Alice"} |
|   {"id":2,"name":"Bob"} |
+-------------------------+
```

## JSON pointer to root
`root` を指定することで、[JSON Pointer](https://tools.ietf.org/html/rfc6901) の形式で各JSON object内で読み取るレコードのRootを指定することができるようになりました。

```json
{"user": {"id": 1, "name": "Alice"}}
{"user": {"id": 2, "name": "Bob"}}
```
```yaml
in:
  type: ...
  parser:
    type: json
    root: /user

```
```
+-------------------------+
|             record:json |
+-------------------------+
| {"id":1,"name":"Alice"} |
|   {"id":2,"name":"Bob"} |
+-------------------------+
```

## 任意のキーをカラムとして指定する
各JSONオブジェクト内の任意のキーをEmbulkのカラムとして指定できるようになりました。

```json
{"id": 1, "name": "Alice"}
{"id": 2, "name": "Bob"}
```
```yaml
in:
  type: ...
  parser:
    type: json
    columns:
      - {name: id, type: long}
      - {name: name, type: string}
```
```
+---------+-------------+
| id:long | name:string |
+---------+-------------+
|       1 |       Alice |
|       2 |         Bob |
+---------+-------------+
```

また、`element_at `を用いて、JSONオブジェクト内の任意パスをJSON Pointer形式で指定できます。このとき、Rootポインターからの相対パスを指定します。

### 
```json
{"id": 1, "name": "Alice", "tags": ["a", "b", "c"]}
{"id": 2, "name": "Bob", "tags": ["d", "e"]}
```
```yaml
in:
  type: ...
  parser:
    type: json
    columns:
      - {name: id, type: long}
      - {name: name, type: string}
      - {name: first_tag, type: string, element_at: /tags/0}
```
```
+---------+-------------+------------------+
| id:long | name:string | first_tag:string |
+---------+-------------+------------------+
|       1 |       Alice |                a |
|       2 |         Bob |                d |
+---------+-------------+------------------+
```

## Flattening JSON array
`flatten_json_array` オプション(デフォルトfalse)を`true`に設定することで、JSON arrayを複数のEmbulkレコードとして展開することができます。

```json
[
  {"id": 1, "name": "Alice"},
  {"id": 2, "name": "Bob"}
]
```
```yaml
in:
  type: ...
  parser:
    type: json
    flatten_json_array: true
```
```
+-------------------------+
|             record:json |
+-------------------------+
| {"id":1,"name":"Alice"} |
|   {"id":2,"name":"Bob"} |
+-------------------------+
```

これは、 `root`と併用し、以下のようにJSONオブジェクト内の配列を展開する事もできます。

```json
{
  "results": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ]
}
```
```yaml
in:
  type: ...
  parser:
    type: json
    flatten_json_array: true
    root: /results
```
```
+-------------------------+
|             record:json |
+-------------------------+
| {"id":1,"name":"Alice"} |
|   {"id":2,"name":"Bob"} |
+-------------------------+
```

## 既存のOSS JSON parser pluginとの違い
これらのプラグインの基本的な機能は同等のことができるようになっているので、未対応の機能を使ってない場合はbuilt-inのプラグインに移行可能です。

### [embulk-parser-jsonl](https://github.com/shun0102/embulk-parser-jsonl)
* `columns`オプションによるカラムを指定は同じ事ができるようになりました。
* `default_typecast`オプションによる型の自動変換は対応していません。[^3]

[^3]: 型変換に関してはParserではなく、Filterで対応するべきという方針から公式では非対応としています。

### [embulk-parser-jsonpath](https://github.com/hiroyuki-sato/embulk-parser-jsonpath)
* `root` オプションによる展開元の指定は `root` と 
 `flatten_json_array ` で同等の事ができるようになりました。
* `path` オプションによる値のJSONPathによる指定は、JSON Pointerで同等のことができるようになりました。
* ただし、JSON PointerはJSONPathほど複雑なことができる訳では無いので、単に値をポイントする以上のことをJSONPathで行っている場合は引き続きこちらのParserが必要になります。[^4]
* `1`, `yes`, `on` などの文字列のboolean型への型変換は対応していません。

[^4]: JSONPathはRFCで定義された仕様がなく挙動がライブラリによってまちまちな背景から、手堅いJSON Pointerを採用しています。また、Embulkが依存しているJacksonがJSON Pointerをサポートしていることも理由のひとつです。