Apache Hive でクエリ実行結果を TSV や CSV で出力する

## 概要

- Apache Hive でクエリを記述したファイルを読み込んで、実行結果を TSV (タブ区切り) や CSV (カンマ区切り) で出力する

## 環境

- Apache Hive 3.1.2
- Apache Hadoop 3.2.0
- Java 8 (OpenJDK 8)
- Ubuntu 20.10 (Groovy Gorilla)

## hive コマンドのヘルプ

```
$ hive --help --service cli
Hive Session ID = 832c7cb9-5877-4937-b727-9cc47ac1d3e7
usage: hive
 -d,--define <key=value>          Variable substitution to apply to Hive
                                  commands. e.g. -d A=B or --define A=B
    --database <databasename>     Specify the database to use
 -e <quoted-query-string>         SQL from command line
 -f <filename>                    SQL from files
 -H,--help                        Print help information
    --hiveconf <property=value>   Use value for given property
    --hivevar <key=value>         Variable substitution to apply to Hive
                                  commands. e.g. --hivevar A=B
 -i <filename>                    Initialization SQL file
 -S,--silent                      Silent mode in interactive shell
 -v,--verbose                     Verbose mode (echo executed SQL to the
                                  console)
```

## 実行例

HiveQL クエリを記述した foo_query.hql ファイルを用意する。HiveQL クエリを複数記述しても問題ないが、出力結果は1つのファイルにまとめられる。

```sql
-- ひとつめのクエリ
select id, name,  updated_at from foo_database.foo_table;

-- ふたつめのクエリ
select id, jname, updated_at from foo_database.foo_table;
```

hive コマンドを実行して出力結果をファイルへリダイレクトする。 -f オプションでクエリ記述ファイルを指定。 --hiveconf hive.cli.print.header=true を指定するとクエリ結果にカラム名も出力される。また、 --silent オプションを指定すると Time taken などが出力されなくなる。

```
$ hive -f foo_query.hql --hiveconf hive.cli.print.header=true > foo_output.tsv
Hive Session ID = 2549fb11-cdd0-4b7f-b24f-52e041665dd5

Logging initialized using configuration in jar:file:/opt/hive-3.1.2/lib/hive-common-3.1.2.jar!/hive-log4j2.properties Async: true
Hive Session ID = 997d8102-9b7a-4231-a71d-77fc49b1409d
OK
Time taken: 9.027 seconds, Fetched: 4 row(s)
OK
Time taken: 0.515 seconds, Fetched: 4 row(s)
```

リダイレクト出力したファイルの中身を確認する。
出力値がタブ文字で区切られた TSV ファイルになっている。

```
$ cat foo_output.tsv
id	name	updated_at
100	Alice	2020-02-29 00:00:00
200	Bob	1999-12-31 23:59:59
300	Carol	2021-04-20 00:00:00
400	Dave	2022-02-22 02:22:22
id	jname	updated_at
100	アリス	2020-02-29 00:00:00
200	ボブ	1999-12-31 23:59:59
300	キャロル	2021-04-20 00:00:00
400	デイヴ	2022-02-22 02:22:22
```

タブを「^I」表示で可視化して確認する。

```
$ cat --show-tabs foo_output.tsv
id^Iname^Iupdated_at
100^IAlice^I2020-02-29 00:00:00
200^IBob^I1999-12-31 23:59:59
300^ICarol^I2021-04-20 00:00:00
400^IDave^I2022-02-22 02:22:22
id^Ijname^Iupdated_at
100^Iアリス^I2020-02-29 00:00:00
200^Iボブ^I1999-12-31 23:59:59
300^Iキャロル^I2021-04-20 00:00:00
400^Iデイヴ^I2022-02-22 02:22:22
```

関数などで工夫すれば CSV (カンマ区切り) や独自のフォーマットで出力することも可能になる。

HiveQL クエリを記述した bar_query.hql ファイルを用意する。
concat_ws 関数を使うと区切り文字を指定して文字列を連結できる。

```
-- ひとつめのクエリ
select concat_ws(',', cast(id as string), name) from foo_database.foo_table;

-- ふたつめのクエリ
select concat_ws(' | ', jname, date_format(updated_at, 'yyyy-MM-dd HH:mm:ss')) from foo_database.foo_table;
```

hive コマンドを実行して出力結果をファイルへリダイレクトする。

```
$ hive -f bar_query.hql --silent > bar_output.txt
Hive Session ID = bf559a06-69fe-45c0-8493-411aaf533cd1
Hive Session ID = fd435823-2722-4c49-bcca-54b2641c5c75
```

リダイレクト出力したファイルの中身を確認する。
出力値がタブ文字で区切られた CSV や独自のフォーマットになっている。

```
$ cat bar_output.txt
100,Alice
200,Bob
300,Carol
400,Dave
アリス | 2020-02-29 00:00:00
ボブ | 1999-12-31 23:59:59
キャロル | 2021-04-20 00:00:00
デイヴ | 2022-02-22 02:22:22
```

## 参考資料

- [Configuration Properties \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties)
- [LanguageManual Types \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types)
- [LanguageManual UDF \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF)
- [Apache Hive の split 関数でカンマ区切りの文字列を処理する \- Qiita](https://qiita.com/niwasawa/items/2c0eb4a2a4defe6815d9)