AWSのEMRで分散クエリエンジンPrestoクラスタ作成→rubyから接続してS3の大量ファイル操作体験をしてみよう！

この記事は[フロムスクラッチ Advent Calendar 2016](http://qiita.com/advent-calendar/2016/fromscratch)の9日目の記事です。

筋トレ大好き！プログラミング大好き！
あれ？そうすると、、、
筋肉系カレンダーにも投稿しないと、自称筋肉プログラマー失格なのでは！！
と本気で悩んでいます。
mixです。

# 最近の事件
そう！___AWS、[ATHENA](https://aws.amazon.com/jp/blogs/news/amazon-athena-interactive-sql-queries-for-data-in-amazon-s3/)が発表されました！___
Presto信者としては血湧き肉躍るニュースです！

簡単に説明すると、[Presto](https://prestodb.io/)というfacebookの作ったフレームワークを
AWSで__サーバーレスに使える__という画期的かつ凄すぎる新サービスです！

カレンダー2日連続になっていますが、
AWSの回し者とかじゃないです。。。(>_<)

# そもそもPrestoってなんじゃい？？
下の説明を正確にしていくと、
分類も定義によったり、
テラバイト処理には対応する大規模構成が必要になったり、
クエリがSQLなのはPrestoの特徴だったりします。__が！__

__難しい説明は頭脳系エンジニアに任せます！__
細かいところは__筋肉で感じて下さい！__


端的かつ__極端に__いうと、
__テラ単位データを、オンラインで爆速に集計、検索できる基盤です__。
分類的にはhadoop、sparkに代表される分散処理の一つです。

の中でも！分散クエリエンジンに分類されるPrestoは、
__SQL投げる感覚で分散処理をできちゃうでござる__系基盤なんです。

hiveとかご存知の方、使い方は同じです。
ただし中身はhadoopキッカーじゃなくて自前の実装を持っています。

# SQL投げるって、、、対象はRDB？
なんと、実はコネクタ(catalogとよく呼びます)さえあれば、
MySQLでもS3でも、__複数の結合でも__なんでも可能です。画期的！！

現在、メジャーなカタログはあります。
作ることも可能ですが、
結構時間かかりそうですので気軽に作る感じではありません。

さて、結合可能と書きましたが、使ってみた感じ、
__異なるデータソースのデータを結合すると信じられない位遅くなります。__

あまり詳しく調査していませんが、
気軽に使うならデータソースは１種類が良いです。
大量データを扱うと思いますので、S3とかファイルサーバになると思います。

# 記事でどこまで書くかの苦悩
・・・hadoopとかsparkとかhiveとか説明したい、but長いと読みにくい。。。
いろんな人が違いを書いてくれているから興味あればぜひググってね。

じゃあATHENA使ってみるか、と思ったのですが、めっちゃGUIあるし
すでに記事あったので、どうしよう。。。

macに立てる、、のも記事あるし、、、書いてる通りで動きますし。
じゃあAWSのEMRにPresto立てて使ってみましょう。

で終わるとAWSのドキュメントみたいになるので、
rubyで外部から接続するとこまで行きましょう。

# 想定読者
* 分散処理やってみたい人
* facebookのフレームワークなんで(=・ω・=)キリッ！をしてみたい人
* オンラインで大量のデータをある程度リアルタイムに集計する要件を持っている人
* Prestoってなんだかかっこいい響き！と思って読んでくれている人


# やってみよう！
* ほんとはAws cliでコマンド投げて作るのですが、今回は画面で
* 設定も詳細設定とかなしでシンプルにします
* セキュリティも適当にいきます。サンプルなので。

大丈夫！使って問題なければOkですし、
問題あればきっとあなたは調べてカスタマイズして好きな構成を作れるようにいつの間にかなります。
※セキュリティは別途調べてみて下さい。

## まずはAWSのアカウントを作りましょう
これはすみません。
ご自身で登録してアカウントを用意してください。

## S3にバケット作ります
下記の記事でやってみて下さいね★
http://qiita.com/idobee/items/416b81982944f6068f47

## EMRクラスタを作成します
### EMR画面に移動
![1.png](https://qiita-image-store.s3.amazonaws.com/0/70346/a3b0a973-60b5-818f-ef29-59508b3afb57.png)


### 「クラスターを作成」を選択して登録
キーペアはEC2のサービスのサイドメニューに作るところあるので作ってpemファイルを
ダウンロードしておきましょう！
SSH接続で使います！
![2.png](https://qiita-image-store.s3.amazonaws.com/0/70346/991401bd-0e42-15b9-3911-c1d229dee93a.png)

### 開始中になるので待ちます
![3.png](https://qiita-image-store.s3.amazonaws.com/0/70346/2bcc6dc7-e97b-b5fb-6a90-499defc6dfe1.png)

### マスターのセキュリティグループの設定
忘れてました。。。先にやっとく方法もあったかもです。
マスタノードのセキュリティグループをクリックして、
①インバウンド→編集→ルールの追加→8889ポートをMYIPに開放します。アプリからの通信用。
①インバウンド→編集→ルールの追加→22ポートをMYIPに開放します。SSH用。
![4.png](https://qiita-image-store.s3.amazonaws.com/0/70346/be43eb15-aeb6-be5d-5974-f13e0d13b12b.png)

## SSHで接続！
キーペアの権限適切に設定して下さいね。
例) sudo chmod 600 ~/.ssh/hoge.pem

EMRのクラスター情報の画面の
「マスターパブリック DNS」の右端にSSHというリンクがあるはずなのでクリックして下さい。
そうするとコマンドの例が載っています。

例)ssh -i ~/.ssh/hoge.pem hadoop@ec2-xx-xxx-x-xx.ap-northeast-1.compute.amazonaws.com

つながりました！！
<img width="436" alt="5.png" src="https://qiita-image-store.s3.amazonaws.com/0/70346/69443b63-dcf5-0fd9-100b-e7cc85355b1f.png">


## ターミナルでそのままPresto体験

Prestoクライアントから操作してみます！

```terminal
$ presto-cli
presto>show catalogs;
 Catalog 
---------
 hive    
 system  
(2 rows)

Query 20161209_053659_00001_5e39d, FINISHED, 1 node
Splits: 1 total, 1 done (100.00%)
0:02 [0 rows, 0B] [0 rows/s, 0B/s]
```

デフォルトではhiveのカタログがあるのでhiveで作成したデータを操作できます。
ただ、今はHDFSにもS3にもデータがありません。
S3にファイルをおいてhiveからアクセスできるようにしましょう。

## S3にファイル配置
作ったバケットに以下のサンプルファイルをアップロードします。

```sample.csv
1000,mix
1,mix2,fs
2,mix3,test
33,fromscratch,mi
333,bdash,aaa
```

適当にデータ増やしてみて下さいね。

## hiveでテーブル作成
じゃあ置いたファイル読み込むテーブルを作成しましょう。

```terminal
$ hive
```

これでhiveが起動します。
ファイルおいたS3の階層を使います。
今回は「バケット名/presto」以下においたとします。

```
CREATE EXTERNAL TABLE sample
(
  id INT,
  first_name STRING,
  last_name STRING
)
  ROW FORMAT DELIMITED
  FIELDS TERMINATED BY ','
  LINES TERMINATED BY '\n'
  LOCATION 's3n://バケット名/presto';
```

S3に実体を持つhiveテーブルができました。

実運用ではパーティションとかつけると良いです★
例) PARTITIONED BY (ts INT)

## hiveでselectしてみよう！

```
hive> select * from sample;
OK
1000	mix	NULL
1	mix2	fs
2	mix3	test
33	fromscratch	mi
333	bdash	aaa
Time taken: 2.0 seconds, Fetched: 5 row(s)
```

## prestoでselectしてみよう！

```
$ presto-cli
presto> select * from hive.default.sample;
  id  | first_name  | last_name 
------+-------------+-----------
 1000 | mix         | NULL      
    1 | mix2        | fs        
    2 | mix3        | test      
   33 | fromscratch | mi        
  333 | bdash       | aaa       
(5 rows)

Query 20161209_062527_00022_5e39d, FINISHED, 1 node
Splits: 2 total, 2 done (100.00%)
0:03 [5 rows, 63B] [1 rows/s, 22B/s]
```

カタログ.スキーマ.テーブルと設定します。
presto-cli立ち上げの際にカタログなどを設定しておくこともできます。

prestoくんの力を見るためにはデフォルトのしょぼいマシンじゃだめですね。
本番は作るテーブルもORC形式にして、圧縮すると高速になります。
ま、今回はサンプルなので。

## 最後にrubyから接続してみよう！


[presto-client](https://github.com/treasure-data/presto-client-ruby)を使うと簡単です。

```ruby
require 'presto-client'

client = Presto::Client.new(
                           server: 'パブリックIP:8889',
                           catalog: 'hive',
                           schema: 'default',
                           user: 'ec2-user', #or hadoop
                           time_zone: 'US/Pacific',
                           language: 'English',
                           #http_debug: true,これ設定すると結構ログが出る
)

# 全テーブル名表示
columns, rows = client.run("show tables")
rows.each {|row|
  p row  # row is an array
}

# sampleテーブルの全件表示
columns, rows = client.run("SELECT * FRoM sample")
rows.each {|row|
  p row  # row is an array
}
```

javaもクライアントあるので使ってみて下さい。
あっさり動きます！

# まとめ
な、長くなってしまった。。。
すみません！！！！

最後に、Prestoは適切にクラスターを構成すると爆速になります。
大量データの処理に対して、富豪的アプローチが可能なんです。

例えば1テラのデータを
RedShift、Bigquery、RDBなどで爆速に処理したい！
といっても限界があります。それはどうしようもない限界です。

逆に、Prestoは使うメモリ量に耐えきれて、
更にCPU性能の高いサーバーを与えれば与えるほど、純粋に高速化できます。

プロテインを飲んで筋トレすればするほど強くなる
筋肉プログラマーのために作られたフレームワークといっても過言じゃないですね！
(これが言いたかった！)

# 結論
こじつけてごめんなさい。
メリクリまであと16日！