ベンチマークTPC-HをAmazon EMRのHiveで実行する方法

# TL;DR

* RDBベンチマークTPC-HをAmazon EMRのクエリエンジン Hiveで実行する手順を紹介します
    * [Amazon EMRでHiveのセットアップ](https://qiita.com/myoshimi/items/1ce78757a9f05d476bbb)の続編です

# 実験概要

* デフォルト設定のAmazon EMRで，TPC-Hベンチマークを一部修正して実行します
    * Hive HPL/SQLに合わせて，データの格納手順などが若干変わります
* EMRのセットアップ方法は，[Amazon EMRでHiveのセットアップ](https://qiita.com/myoshimi/items/1ce78757a9f05d476bbb)を参照してください

# TPC-Hベンチマークの実行手順

* ベンチマークの実行は，以下の手続きで実施します．
* [データベースベンチマークTPC-HをMySQLで実行する(TPC-H v2.18.0)](https://qiita.com/myoshimi/items/bd460164af48ece1ab2d)と同様の手順ですが，Hive用に

1. TPC-Hのデータとクエリを生成するツールのダウンロード
1. Hive向けの修正
1. テーブルの作成
1. データの生成
1. データの登録
1. インデックスの作成
1. 実行クエリの生成
1. クエリを実行して性能計測

## 1. ベンチマークツールのダウンロード

* デフォルト設定のままでEMRクラスタを作ると，```/```パーティションが10GBくらいしかないので，```/mnt```パーティションに，データを置くようにします

```bash
# hadoop ユーザで実行
$ sudo mkdir /mnt/hadoop
$ sudo chown -R hadoop:hadoop /mnt/hadoop
$ cd /home/hadoop
$ ln -s /mnt/hadoop .
```

* TPC-H_Toolsの[Download]から，TPC-Toolsを入手します
    * 入力するメールアドレスにダウンロードキー付きのURLが送付されるので，それをクリックしてダウンロードします
    * TPC-H_Tools_v2.18.0を入手しました
* scpコマンドなどで，EMRのマスターノード(SSHでログインするノード)に,tpc-h-tools.zipにリネームしてコピーします

## 2. Hive向けにツールを修正

* [データベースベンチマークTPC-HをMySQLで実行する(TPC-H v2.18.0)](https://qiita.com/myoshimi/items/bd460164af48ece1ab2d)に加えて，いくつかの修正をする必要があります．
* この記事では，パッチのダウンロードからの手順を紹介します．

## tpch-patchesのダウンロードと修正(MySQL版と同じ)

* hadoopユーザでEMRマスターノードにsshした後，下記のコマンドでディレクトリを作成し，[tpch-patches](https://github.com/itiut/tpch-patches)を```git clone```します
* 前項でダウンロードしたtpc-h-tool.zipを配置します

```bash
$ mkdir -p ~/{src,bin,share}
$ cd ~/src
$ git clone https://github.com/itiut/tpch-patches
$ cp ~/tpc-h-tool.zip ~/src/
```

* src/tpch-patches/install.shを以下のように修正します(MySQL版と同じ)

```patch
diff --git a/install.sh b/install.sh
index 9d81955..bb0b6f5 100755
--- a/install.sh
+++ b/install.sh
@@ -22,7 +22,8 @@ esac

 BASE_DIR=$PWD
 DATABASE=$1
-TPCH_PROG=tpch_2_17_0
+TPCH_PROG=tpc-h-tool
+TPCH_VER=2.18.0_rc2
 : ${PREFIX:=$HOME}
 PREFIX=$(readlink -f $PREFIX)
 BIN_DIR=$PREFIX/bin
@@ -40,14 +41,11 @@ ensure_directories() {

 download_and_extract_dbgen() {
     pushd $SRC_DIR
-    if [ ! -f $TPCH_PROG.zip ]; then
-        echo "Download $TPCH_PROG.zip ..."
-        curl -LO http://www.tpc.org/tpch/spec/$TPCH_PROG.zip
-    fi
     if [ ! -d $TPCH_PROG ]; then
         echo "Extract $TPCH_PROG.zip ..."
-        unzip $TPCH_PROG
+        unzip $TPCH_PROG.zip
         rm -rf __MACOSX
+       mv $TPCH_VER $SRC_DIR/$TPCH_PROG
     fi
     popd
 }
```

* tpch-patches/install.shを実行して，{データ,クエリ}生成プログラムを生成する

```bash
$ ./install.sh mysql
```

## 3. テーブルの作成(スキーマの登録)

* スキーマ設定 ```~/share/dbgen/dss.ddl```を，Hive用に修正します
    * 各テーブルの作成コマンド```CREATE TABLE```について，最後の閉じカッコとセミコロンの間に，下記の例のように３行追加します．
        * ロードするファイルの区切り文字に関する設定です
        * MySQLではロード時に区切り文字を設定しますが，Hiveではスキーマ設定のときに設定します
    * 8つのテーブルがあるので，それぞれ記載します

```sql
CREATE TABLE nation  ( N_NATIONKEY  INTEGER ,
                            N_NAME       CHAR(25) ,
                            N_REGIONKEY  INTEGER ,
                            N_COMMENT    VARCHAR(152))
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
LINES TERMINATED BY '\n';
```

* EMRのHiveに，```sf1```などのデータベースを作成します
* その後，```dss.ddl```をクエリとして実行します

```bash
$ cd ~/share/dbgen
$ hive -e "create database sf1;"
$ hive --database sf1 -f dss.ddl
```

## 4. データの生成(MySQLと同じ)

* ```dbgen```コマンドで，データテーブルを作成します
    * テーブルデータは大きくなるので，```/mnt``` パーティションに置くとよいです

```shell
$ mkdir ~/hadoop/sf1 && cd ~/hadoop/sf1
$ ~/bin/dbgen -s 1
$ ls
-rw-rw-r-- 1 hadoop hadoop  24346144  4月 12 01:40 customer.tbl
-rw-rw-r-- 1 hadoop hadoop 759863287  4月 12 01:40 lineitem.tbl
-rw-rw-r-- 1 hadoop hadoop      2224  4月 12 01:40 nation.tbl
-rw-rw-r-- 1 hadoop hadoop 171952161  4月 12 01:40 orders.tbl
-rw-rw-r-- 1 hadoop hadoop  24135125  4月 12 01:40 part.tbl
-rw-rw-r-- 1 hadoop hadoop 118984616  4月 12 01:40 partsupp.tbl
-rw-rw-r-- 1 hadoop hadoop       389  4月 12 01:40 region.tbl
-rw-rw-r-- 1 hadoop hadoop   1409184  4月 12 01:40 supplier.tbl
```

## 5. テーブルへデータの登録

* テーブルファイルを，Hiveに登録するコマンドを実行します
    * MySQL版と似ていますが，若干異なるので注意が必要です

```bash
$ cd ~/hadoop/sf1
# データベースsf1に，各テーブルの内容を登録する
$ for tbl_file in *.tbl;
do
hive --database sf1 -e \
"LOAD DATA LOCAL INPATH '$tbl_file' OVERWRITE INTO TABLE $(basename $tbl_file .tbl);"
done
```

## 6. インデックスの作成

* インデックス指定ファイルを作成し，テーブルのインデックスを登録します
    * gistの[dss.ri.tpch](https://gist.github.com/myoshimi/60618b6e1da084e10b9c739f8ea55a55)をダウンロードします
    * tpch-patchesで生成されたdss.riと基本的には同じですが，Hive用の修正をしています
        * 主キー，外部キーの指定で，```disable novalidate```（データ検証しない）の指定をしています
        * 主キー，外部キーの制約名を，データベース名ごとに別にするように修正しています
    * 以下のコマンドで，データベース名ごとのインデックス指定ファイルを生成して，テーブルのインデックスを作成します

```bash
sed -e 's/tpch/sf1/g' dss.ri.tpch > dss.ri.sf1
hive --database sf1 -f dss.ri.sf1
```

## 7. クエリファイルの作成(MySQLと同じ)

* ```qgen``` コマンドで，TPC-Hのクエリファイルを生成します．
    * ```-s``` オプションで，実行するScale Factorを指定してください

```
$ cd ~/bin
$ mkdir -p ~/bin/sf1query && cd ~/bin/sf1query
$ for i in $(seq 1 22); do ~/bin/qgen -s 1 $i > $i.sql; done
```

## 8. クエリを実行して性能計測

* 下記コマンドで，Hive上のデータベースに対してクエリ（1.sql）を実行できます．
    * 実行時間をファイル（sf1_1.log）に書き出しています

```bash
$ (time hive --database sf1 -f ~/sf1query/1.sql) >& sf1_1.log

Logging initialized using configuration in file:/etc/hive/conf.dist/hive-log4j2.properties Async: false
OK
Time taken: 0.93 seconds
Query ID = hadoop_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Total jobs = 1
Launching Job 1 out of 1
Status: Running (Executing on YARN cluster with App id application_XXXXX_XXXXXX)

----------------------------------------------------------------------------------------------
        VERTICES      MODE        STATUS  TOTAL  COMPLETED  RUNNING  PENDING  FAILED  KILLED
----------------------------------------------------------------------------------------------
Map 1 .......... container     SUCCEEDED     15         15        0        0       0       0
Reducer 2 ...... container     SUCCEEDED      1          1        0        0       0       0
Reducer 3 ...... container     SUCCEEDED      1          1        0        0       0       0
----------------------------------------------------------------------------------------------
VERTICES: 03/03  [==========================>>] 100%  ELAPSED TIME: 46.16 s
----------------------------------------------------------------------------------------------
OK
A       F       37734107.00     56586554400.73  53758257134.8700        55909065222.827692      25.522006       38273.129735    0.049985    1478493
N       F       991417.00       1487504710.38   1413082168.0541 1469649223.194375       25.516472       38284.467761    0.050093        38854
N       O       73589282.00     110371877742.86 104854991266.2109       109053028629.140947     25.502061       38248.916868    0.049995    2885621
R       F       37719753.00     56568041380.90  53741292684.6040        55889619119.831932      25.505794       38250.854626    0.050009    1478870
Time taken: 56.439 seconds, Fetched: 4 row(s)

$ hive -e "RESET QUERY CACHE;"
```

* ScaleFactor=1 (1GB)のデータでは，Query1の実行に約56.4秒要しました．
* [AuroraとEC2の比較](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925#aurora%E3%81%A8ec2%E3%81%AE%E6%AF%94%E8%BC%83)の結果と比べると，だいぶ遅い（３倍程度の計算時間）です．

# 参考

* [データベースベンチマークTPC-HをMySQLで実行する(TPC-H v2.18.0)](https://qiita.com/myoshimi/items/bd460164af48ece1ab2d)
* [Auroraの性能検証（EC2との比較，データ量と計算時間の関係](https://qiita.com/myoshimi/items/3fc65bb7e29ecd25f925)
* [Amazon EMRでHiveのセットアップ](https://qiita.com/myoshimi/items/1ce78757a9f05d476bbb)
* [TPC-H patches](https://github.com/itiut/tpch-patches)