Redshiftを試してみる


Redshift起動
--------------

バージニアRegionに作成する。

* Node Type: dw.hs1.xlarge
* Cluster Type: Single Node

2TBの容量でOnDemandなので $0.85/hour。
だいたい１０分くらいでセットアップ終わってたかな？？

Clientのセットアップ
-------------------

Amazon Linuxで。
redshiftのPostgresqlの近しいVersionは８らしいので、８のクライアントを入れる（それで良いのかはよく知らない）。

	sudo yum install postgresql8-devel  

redshift側のSecurityGroupで このクライアントマシンのIPからの接続を許可する。

その後こんな感じで接続できる

```
psql -h *******.us-east-1.redshift.amazonaws.com -p 5439 -d mydb -U root     
ユーザ root のパスワード:  ******************
psql (8.4.13, サーバ 8.0.2)
注意： psql バージョン 8.4, サーババージョン 8.0.
         psql の機能の中で、動作しないものがあるかもしれません。
SSL 接続 (暗号化方式: DHE-RSA-AES256-SHA, ビット長: 256)
"help" でヘルプを表示します.
	
mydb=# 
```

簡単なデータ入れてみる
--------

試しにこういうデータを考える

* id: int
* type: varchar(32)
* point: int
* event_datetime: datetime  # UTC

-
SQLの文法は[この辺](http://docs.aws.amazon.com/redshift/latest/dg/c_SQL_commands.html)を参照。見慣れないキーワードも出てきていますね。


```SQL
Create Table sample1 (
  id BIGINT IDENTITY(1,1) PRIMARY KEY,
  type VARCHAR(32) ENCODE TEXT255,
  point INT,
  event_datetime TIMESTAMP
)
DISTSTYLE EVEN
SORTKEY (event_datetime);
```

* **DISTSTYLE**: は分散のポリシー。*KEY* か *EVEN* である。*EVEN* はRoundRobin的に分散させる。KEYなら分散に使う列を指定する。まあ、今回は Single Node だからあまり関係ない。
* **SORTKEY**: はRangeで検索するときによく使う列を指定しておくと良いっぽい。

この辺のテーブル設計について詳しくは[この辺](http://docs.aws.amazon.com/redshift/latest/dg/t_Creating_tables.html)を参照

* **IDENTITY**: AUTO_INCREMENT みたいなものかな。

* **ENCODE** は列圧縮オプション。同様の文字列が出てくるような場合は TEXT255 とかを使うっぽい。[圧縮オプションの詳細](http://docs.aws.amazon.com/redshift/latest/dg/c_Compression_encodings.html) はこちら。

Insert とか Select とか
---

普通に Insert でデータを入れてみる。

```
mydb=# insert into sample1(type, point, event_datetime) values('hoge', 10, '2013/5/10 10:10:00');
INSERT 0 1
```

Select とかしてみる。

```
mydb=# select * from sample1 where event_datetime > '2013-5-2';
 id | type | point |   event_datetime    
----+------+-------+---------------------
  1 | hoge |    10 | 2013-05-10 10:10:00
(1 行)

mydb=# select * from sample1 where event_datetime < '2013-5-2';
 id | type | point | event_datetime 
----+------+-------+----------------
(0 行)
```


S3からデータのImport
-----------

S3にデータをUploadするために s3cmd を Installしておく


```shell
sudo yum -y --enablerepo epel install s3cmd 
s3cmd --configure
# ACCESS_KEY とか SECRET とかを入力
```

こんな感じで使うっぽい。

```
s3cmd ls s3://BUCKET/  
s3cmd put FILE FILE... s3://BUCKET/redshift/  
```

データを作成するスクリプトをかく。

```make_data.rb
# coding: utf-8
# make_data.rb

num = ARGV.shift.to_i
DELI = "\001"
	
TYPES = ["cat", "dog", "cow", "horse"]

num.times do |i|
  type = TYPES[i % TYPES.size]
  point = Random.rand(10) + 1
  dt = Time.now.utc
  puts [type, point, dt].join(DELI)
end
```

データを作成して、S3にUploadする。

```	
	ruby make_data.rb 20000 > 20000.data
	gzip 20000.data
	s3cmd put 20000.data.gz s3://BUCKET/redshift/sample1/  
```

データをCOPYで取り込んでみる。

```psql
COPY sample1
FROM 's3://BUCKET/redshift/sample1/20000.data.gz'
GZIP
DELIMITER '\001'
CREDENTIALS 'aws_access_key_id=***********;aws_secret_access_key=************'
;
ERROR:  S3ServiceException:The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.,StatusCode 301,ErrorCode PermanentRedirect,RequestId EC14D5D1453E517A,ExtendedRequestId QjHhcX8gv0D
DETAIL:
...
```

エラーが出た。

そういえば、そのBucketは東京Regionのものだったので、US Standardに別にBucketを作り直す
(COPYコマンドでS3からデータを取り込むときは同一リージョンでないといけない）

> Important: The Amazon S3 bucket that holds the data files must be created in the same region as your cluster.


再度データをUploadし直して、COPYを再実行すると今度は成功。いくつか select を試す。

```psql
mydb=# select count(*) from sample1;
 count
-------
 20001
(1 行)

mydb=# select * from sample1 limit 4;
 id |  type  | point |   event_datetime
----+--------+-------+---------------------
  1 | hoge   |    10 | 2013-05-10 10:10:00
  4 | dog    |     9 | 2013-05-10 06:20:32
  8 | horse  |     4 | 2013-05-10 06:20:32
 12 | dog    |     4 | 2013-05-10 06:20:32
(4 行)


mydb=# select type, count(*), sum(point) from sample1 group by type;
  type  | count |  sum  
--------+-------+-------
 hoge   |     1 |    10
 hourse |  5000 | 27270
 cat    |  5000 | 27386
 cow    |  5000 | 27529
 dog    |  5000 | 27501
(5 行)
```

3~4秒もしないうちに結果が戻ってくる。
全く同じQuery（Limitを変化させた程度では同じ、ような扱い）を投げると直後に戻ってくる。キャッシュされているのかな。