HiveでJSONデータを処理するあれこれ(初級編)

こんなデータを簡単に集計したいって事。

```json
{"name":"hoge","age":30,"city":"tokyo"}
{"name":"huga","age":41,"city":"chiba"}
{"name":"hige","age":26,"city":"kanagawa"}
```

世の中的にはfluentdで飛んでくるログフォーマットがjsonだったりとかで、json形式で保存されたデータをHiveで集計したいってニーズは沢山あるみたい。例に漏れず当方もしたいので、やり方を調査。

Hiveではいくつかやり方があるみたいなので、それぞれをまとめてみる。

以降のサンプルは`json_tuple`, `get_json_object`を使う場合のtableは上記のようなjsonが1行1jsonという体で保存されていることとし、下記のように生成されている事とする。

```sql
CREATE TABLE raw_json(line STRING);
```

とりあえずこれをselectすると、

```
hive> select * from raw_json;
OK
{"name":"hoge","age":30,"city":"tokyo"}
{"name":"huga","age":41,"city":"chiba"}
{"name":"hige","age":26,"city":"kanagawa"}
Time taken: 0.415 seconds, Fetched: 3 row(s)
```
となる。

## json_tuple
jsonの構造をviewとして定義してselectする。このやり方を推奨する記述を結構目にする。

```sql
SELECT user.* FROM raw_json 
    LATERAL VIEW json_tuple(
        raw_json.line,
        'name',
        'age',
        'city'
    ) user as name, age, city;
```

この結果は、

```
Total MapReduce CPU Time Spent: 1 seconds 230 msec
OK
hoge    30      tokyo
huga    41      chiba
hige    26      kanagawa
Time taken: 8.9 seconds, Fetched: 3 row(s)
```
となる。指定したjsonのkeyがちゃんとFieldにバインドされた。
これを使ってwhere句も実行出来る。

```sql
SELECT user.* FROM raw_json 
    LATERAL VIEW json_tuple(
        raw_json.line,
        'name',
        'age',
        'city'
    ) user as name, age, city
WHERE user.age >= 30;
```
この結果が、

```
Total MapReduce CPU Time Spent: 1 seconds 580 msec
OK
hoge    30      tokyo
huga    41      chiba
```

うむ。簡単。

## get_json_object
任意のSTRINGデータをjson->object変換して利用する。

```sql
SELECT 
    get_json_object(raw_json.line, '$.name'),
    get_json_object(raw_json.line, '$.age'),
    get_json_object(raw_json.line, '$.city')
FROM raw_json;
```

結果は同じく

```
Total MapReduce CPU Time Spent: 1 seconds 650 msec
OK
hoge    30      tokyo
huga    41      chiba
hige    26      kanagawa
```

となる。
上記のselectのField一つづつjson->object変換しているっぽく見えるね。
この書き方でwhere句も付け加えてみると、

```sql
SELECT 
    get_json_object(raw_json.line, '$.name'),
    get_json_object(raw_json.line, '$.age'),
    get_json_object(raw_json.line, '$.city')
FROM raw_json
WHERE
    get_json_object(raw_json.line, '$.age') >=30;
```

となる。勿論結果は、

```
Total MapReduce CPU Time Spent: 1 seconds 560 msec
OK
hoge    30      tokyo
huga    41      chiba
```

となって正しい結果が得られる。
が、書き方も面倒な上におそらく効率は良くないと思われる。
json_tupleとの比較はまた後日。

## SerDe Hive-JSON-Serde
ここまでではとりあえずjson_tupleを使っておけばある程度は出来そうだなって感じなのだが、実は複雑なJSON構造を解析しようと思うと途端使えない。
特にListを持つJSONの場合、json_tupleやget_json_objectでは複雑な要求に答えるのは難しい(簡単なListであれば出来ないこともない)。

ということで最後はHive SerDe(Serialize/Deserialize)を使ったJSON解析。
いくつかあるようだったけど、これが良さそうだった。
https://github.com/rcongiu/Hive-JSON-Serde

cloneしてpackage。testでfailになるのでとりあえずテストをスキップ。
failになっている理由は後で調査。

```
git clone https://github.com/rcongiu/Hive-JSON-Serde.git
cd Hive-JSON-Serde
mvn -Dmaven.test.skip=true package
```

target以下に`json-serde-1.1.9.1-jar-with-dependencies.jar`が出来上がる。

このjarをhive実行環境でadd jarする。

```
hive> add jar /tmp/json-serde-1.1.9.1-jar-with-dependencies.jar
```

その後こんな感じでテーブルを定義。

```sql
CREATE TABLE serde_json(
    name STRING,
    age INT,
    city STRING
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
STORED AS TEXTFILE;
```

このうえでselectをすると、

```
hive> SELECT * FROM json_serde;
OK
hoge    30      tokyo
huga    41      chiba
hige    26      kanagawa

```

あら簡単。

とりあえず初級編はこんな感じかな。次はあんなJSONやこんなJSONをHiveで集計しちゃうぞ。