自前でHadoopをインストールせずとも、
AmazonWebService(AWS)で手軽にHadoopを利用する事ができるということで、
Elastic MapReduce(EMR)環境でHiveを利用してみました。

ここでは、以下のような手順でHiveを利用する手順を示します。

  1. S3にHive用のbucketを作成
  2. Amazon Elastic MapReduce Ruby Clientのセットアップ
  3. S3にデータを配置
  4. HiveインタラクティブモードでElastic MapReduceを起動
  5. 作成したHiveスクリプトをバッチ処理で実行

S3にHive用のbucketを作成

Hive用のデータを保存するため、S3にbucketを作ります。

「AWS Management Console」でS3を選び、
「Buckets」の「Create Bucket」を選択して、
「Bucket Name」を指定し「Create」を押下すればBucketを作成できます。

Amazon Elastic MapReduce Ruby Clientのセットアップ

次に、EMRを制御するためのRuby Clientをセットアップします。

Amazon Elastic MapReduce Ruby Client
 http://aws.amazon.com/developertools/2264

EMRを制御するマシンにRuby1.9がインストールされているとして、
以下のコマンドを入力し、Ruby Clientをインストールします。

$ gem install elastic-mapreduce

EMRにアクセスするための認証情報を記載します。
access_id,private_key,keypair,key-pair-file,log_urlは自分の環境のものを記載してください。
以下の例では、regionをtokyo regionで指定しています。

credentials.json

{
"access_id": "<access_key_idをここに>",
"private_key": "<secret_access_keyをここに>",
"keypair": "<key pair名をここに>",
"key-pair-file": "<key pairに対応するpemファイルをフルパスでここに>",
"log_uri": "s3n://<作成したbucket名をここに>/emr-log",
"region": "ap-northeast-1"
}

カレントディレクトリを、credential.jsonを配置したディレクトリにして、
以下のコマンドを実行し、認証エラーとならなければセットアップ完了です。

$ elastic-mapreduce --list

S3にデータを配置

次に、Hiveでの処理対象となるデータをS3に配置します。

データは何でも良いのですが、
とりあえず、以下のように「日時」「支店」「金額」がタブ区切りで入力された、
店舗別の売り上げデータがあるとします。

2012-11-20 10:35:00 東京店 1000
2012-12-05 19:07:00 大阪店 1200
2012-12-07 12:42:00 京都店 2200
2012-12-10 13:05:00 東京店 1800

このファイルを作成したS3 bucketの以下のパスに配置します。
 /hive/external/sales/sales001

HiveインタラクティブモードでElastic MapReduceを起動

次に、インタラクティブモードでHiveが使えるようにEMRを起動します。
# 通常のバッチ処理では、実行するHiveスクリプトを指定してEMRを起動しますが、
# Hiveスクリプトを作成・検証するため、
# 最初はインタラクティブモードで起動することにします。

credential.jsonを配置したディレクトリで以下を実行します。
成功するとJobFlow番号が表示されます。

$ elastic-mapreduce --create --name hdp --num-instances 1 --instance-type m1.small --hive-interactive --hive-versions 0.8.1.6 --hadoop-version 1.0.3 --alive
Created job flow j-XXXXXXXXXXXX

ここで指定しているオプションは以下の意味です。
–createの部分でインスタンスの作成を指定
–nameの部分はインスタンス識別用の名称
–num-instancesの部分は起動するインスタンス数
–instance-typeの部分は起動するインスタンスの種別
–hive-interactiveの部分はインタラクティブモードの指定
–hive-versions/–hadoop-versionの部分は起動するバージョン
–aliveの部分でインスタンスが自動終了しないよう指定
 (通常のバッチ処理では、処理終了後にインスタンスが自動終了するため)

ここでは、timestamp型を利用するのでHive0.8.1.6を指定して起動しています。
EMRで利用可能なバージョンは以下を参照。

Supported Hive Versions
 http://docs.amazonwebservices.com/ElasticMapReduce/latest/DeveloperGuide/UsingEMR_SupportedHiveVersions.html

上記のコマンド実行後しばらくして、以下のコマンドを入力し、インスタンスの状態を確認します。

$ elastic-mapreduce --list

起動したインスタンスが「COMPLETED Setup Hive」となっている事を確認して、
以下のコマンドを実行します。

$ elastic-mapreduce --jobflow <起動したJobFlow番号> --ssh

SSHでEMRのインスタンスに接続できたことを確認し、Hiveのコマンドを実行します。

$ hive

Hiveのコマンドプロンプトで以下を実行し、
店舗別の売り上げデータをHiveの外部テーブルとして定義します。

hive> create external table sales (
saletime timestamp,
shop string,
amount int
)
row format delimited
fields terminated by '\t' lines terminated by '\n'
stored as textfile location 's3://<作成したbucket名をここに>/hive/external/sales';

店舗別の売り上げテーブルに対して、
月別の集計、店舗別の集計を行うHiveスクリプトを実行します。

hive> select month(saletime), sum(amount) from sales group by month(saletime);
Total MapReduce jobs = 1
Launching Job 1 out of 1
- 省略 -
2012-12-28 02:38:02,592 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.85 sec
2012-12-28 02:38:03,602 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.85 sec
2012-12-28 02:38:04,668 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.85 sec
- 省略 -
OK
11	1000
12	5200
Time taken: 62.534 seconds

hive> select shop, sum(amount) from sales group by shop;
Total MapReduce jobs = 1
Launching Job 1 out of 1
- 省略 -
2012-12-28 02:41:12,370 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.17 sec
2012-12-28 02:41:13,385 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.17 sec
2012-12-28 02:41:14,395 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 4.17 sec
- 省略 -
OK
京都店	2200
大阪店	1200
東京店	2800
Time taken: 57.147 seconds

このようにインタラクティブにHiveスクリプトを実行して試す事ができます。
# この例ではわざわざHive/Hadoopを利用するメリットが無いですが、

Hiveの利用が終わったら、
credential.jsonを配置したディレクトリで以下のコマンドを入力してインスタンスを終了します。

$ elastic-mapreduce --terminate <起動したJobFlow番号>

作成したHiveスクリプトをバッチ処理で実行

最後に作成したスクリプトをバッチ処理として実行してみます。

先ほどインタラクティブに実行したスクリプトの内容を記載したファイルを作成し、
作成したS3 Bucketの以下のパスに配置します。
 /hive/scripts/sales_summary.hql

create external table sales (
saletime timestamp,
shop string,
amount int
)
row format delimited
fields terminated by '\t' lines terminated by '\n'
stored as textfile location 's3://<作成したbucket名をここに>/hive/external/sales';

create external table sales_month (
month int,
amount int
)
row format delimited
fields terminated by '\t' lines terminated by '\n'
stored as textfile location 's3://<作成したbucket名をここに>/hive/summary/sales_month';

create external table sales_shop (
shop string,
amount int
)
row format delimited
fields terminated by '\t' lines terminated by '\n'
stored as textfile location 's3://<作成したbucket名をここに>/hive/summary/sales_shop';

insert overwrite table sales_month
select month(saletime), sum(amount) from sales group by month(saletime);

insert overwrite table sales_shop
select shop, sum(amount) from sales group by shop;

次に、credential.jsonを配置したディレクトリで以下のコマンドを入力し、
Hiveスクリプトを実行します。成功するとJobFlow番号が表示されます。

$ elastic-mapreduce --create --name hdp --num-instances 1 --instance-type m1.small --hive-script "s3://palcommonstore/hive/scripts/sales_summary.hql" --hive-versions 0.8.1.6 --hadoop-version 1.0.3
Created job flow j-XXXXXXXXXXXX

ここで指定しているオプションは以下の意味です。
–hive-scriptの部分で実行するHiveスクリプトのパスを指定

上記のコマンド実行後しばらくして、以下のコマンドを入力し、インスタンスの状態を確認します。

$ elastic-mapreduce --list

起動したインスタンスが「COMPLETE Run Hive Script」となっている事を確認します。

作成したS3 Bucketの以下のパスを確認して実行結果が格納されていることを確認します。
 /hive/summary/sales_month
 /hive/summary/sales_shop

成功した場合は、上記ディレクトリ配下のファイルに、
インタラクティブに実行した結果と同じ内容が格納されています。
上手くいかない場合は、
作成したS3 Bucketの/emr-log配下にログが格納されているので確認します。

上記のコマンドをcronなどで指定することで、バッチ処理を定時実行することもできます。

このようにAWSのElastic MapReduceを利用するとHadoopのインストールをせずとも、
Hive/Hadoopを利用したデータ処理を行う事が出来ます。
またS3上のデータを分析対象にできるため、S3にデータを溜めておくことで集計業務の効率化もできそうです。