Getting Started with SparkSQL on Amazon EMR


こちら([Apache Spark on Amazon EMR](http://aws.typepad.com/aws_japan/2015/06/apache-spark-on-amazon-emr.html))にあるようにめでたくEMRでSparkがサポートされたので、ちょっとGetting Started with Spark的な話を書こうと思った。

ということでまずはSparkSQLから！

## これからやること

SparkSQLとHive両方をインストールしたEMRクラスタ起動し、それぞれに同じクエリを投げてみて所要時間を比べてみる。

## クラスタセットアップ

冒頭のリンクのAWSブログにも書いてあるので詳細には触れないが、マネジメントコンソールから起動するのであれば、下記のSoftware ConfigurationでSparkを指定するだけ。

![Kobito.x6JsZM.png](https://qiita-image-store.s3.amazonaws.com/0/10292/24edeaad-7ee9-ebe8-f2f3-4d92314d4094.png "Kobito.x6JsZM.png")

Sparkへの引数として`-x`を渡すのを忘れずに。これがないとExecutorの数がデフォルト値になってしまい、立ち上がってくるインスタンスのコアやメモリを生かし切れない場合がある。（まあ、spark-submitとかするときに直接指定すりゃいいんだけど）

![Kobito.iDnI09.png](https://qiita-image-store.s3.amazonaws.com/0/10292/371b5eb8-b822-9d55-3375-64dbd943e1ef.png "Kobito.iDnI09.png")


## テーブルセットアップ

SparkSQLの特徴として、Hiveのメタデータをそのまま利用できるということがある（これはPrestoやImpalaも同じ）。なので、HiveでCREATE TABLEしてやればOK。

```

hive> CREATE EXTERNAL TABLE Rankings (
  pageURL STRING,
  pageRank STRING,
  avgDuration STRING
)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY ','
STORED AS SEQUENCEFILE
LOCATION 's3://big-data-benchmark/pavlo/sequence/1node/rankings/';

hive> select count(1) from rankings;
Status: Finished successfully
OK
17999999

```

## Hiveでクエリ

Hiveを起動

```
$ hive
```

クエリ実行

```
hive> select pagerank, count(1) from rankings group by pagerank

Launching Job 1 out of 1
Number of reduce tasks not specified. Estimated from input data size: 2
In order to change the average load for a reducer (in bytes):
  set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers:
  set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:
  set mapreduce.job.reduces=<number>
Starting Job = job_1434549201025_0002, Tracking URL = http://10.0.155.89:9046/proxy/application_1434549201025_0002/
Kill Command = /home/hadoop/bin/hadoop job  -kill job_1434549201025_0002
...


Time taken: 133.733 seconds, Fetched: 3213 row(s)
```

だいたい130秒。

## Sparkでクエリ

SparkSQLを起動

```
$ spark-sql
```

クエリ実行

```
spark-sql> select pagerank, count(1) from rankings group by pagerank;

15/06/17 14:11:34 INFO parse.ParseDriver: Parsing command: select pagerank, 
count(1) from rankings group by pagerank
15/06/17 14:11:34 INFO parse.ParseDriver: Parse Completed
15/06/17 14:11:34 INFO metastore.HiveMetaStore: 0: get_table : db=default tbl=rankings
...

Time taken: 44.218 seconds, Fetched 3213 row(s)
15/06/17 14:02:24 INFO CliDriver: Time taken: 44.218 seconds, Fetched 3213 row(s)
```

ということで40秒ちょっとで終了。通常の3倍の速度じゃないか！！！

## まとめ

SparkSQL、Hiveのメタデータが使えるので敷居は非常に低いし、[Tez](http://qiita.com/imaifactory/items/b1f551524323719d70db)のときと同じでクエリエンジンを取り替えるだけで大幅にクエリの性能があがるので、施策としては非常にコスト対効果が高いと思う。

しかし、Sparkはオンメモリで動くというしくみである以上、取り扱うデータがメモリに収まりきらないような状態になってくると速度が落ちるので注意。

また、Spark自体がメモリ大食い（ちゃんと自分で検証したわけではない。ごめんなさい。）という話なので、クエリというか作業並列度の観点で注意が必要だと思う。

とはいえ、こんなところからSparkを触り始めるひとが増えてきたらうれしいなと思って書いてみたわけです。

## おまけ

EMRのマスタノードで立ち上がるYARNのResource Manager上で、下記のようにSparkSQLのApplication Masterへのリンクをクリックすると、

![Kobito.az3KSg.png](https://qiita-image-store.s3.amazonaws.com/0/10292/d2a0bbdb-9fa3-2a14-c127-627ad215bee8.png "Kobito.az3KSg.png")

こんな感じにSparkのコンソールへ飛べるようになっている。便利！

![Kobito.RasjQQ.png](https://qiita-image-store.s3.amazonaws.com/0/10292/8c3fa77b-6928-7eed-598f-ba2131c12927.png "Kobito.RasjQQ.png")


## Disclaimer

この記事はわたしの個人のメモ/意見であり、わたしの雇用者を代表するものではありません。お約束。