S3 Select(Preview)を試してみました #reinvent

2017.12.11

こんばんは、菅野です。 re:Invent で発表された S3 SELECT が Preview を受け付けていましたので早速申し込んで試しました。 あくまで preview 時点での情報ですので、今後変更される可能性があります

はじめに

S3 SELECT の話を聞いた時に誰もが「Amazon Athena との住み分けは?」という感想を持ったと思います。 その辺を確かめるためにもまずは使ってみましょう。今回は Python でスクリプトを作成します。

申し込みからスタート

S3 SELECT の Preview はこちらのページから申し込みができます。 Amazon S3 Select Preview

メールが届く

  • 受付完了メールの件名
  • 「Confirmation: Amazon S3 Select Preview」
  • まだ慌てる時間じゃない
  • 受付承認メールの件名
  • 「Approved: Amazon S3 Select Preview」
  • OK!
  • 次の日に届きました。Echo の招待メールもこれくらい早く届けばいいのに!

準備

データ

  • 前々回のブログエントリー「GoogleスプレッドシートのデータをS3へCSVとして保存する」で作成した CSV ファイルを使います
  • ただし、S3 Select の Preview は日本リージョンではできませんので、以下のどこかにファイルを作成しましょう
  • オハイオ(us-east-2)
  • バージニア(us-east-1)
  • オレゴン(us-west-2)
  • シンガポール(ap-southeast-1)
  • アイルランド(eu-west-1)
  • データはこんな感じです
"id","name","price"
1,"りんご",90
2,"みかん",30
3,"柿",60
4,"キウイ",70
5,"梨",120

IAM ポリシー

  • 安全のため、S3 の読み込みのみを許可として作成します
  • S3 オブジェクトが読めれば動くだろうという勘です

IAM ユーザー

  • 今回はローカル(Mac)から実行するので IAM ユーザーを作成します
  • アクセスキー、シークレットアクセスキーが必要ですのでコピーしておきましょう
  • ポリシーは先ほど作成した S3 オブジェクトが読めるだけのポリシーをアタッチ

boto3

  • AWS SDK for Python
  • 最新版を入れておきましょう
  • pip install boto3
  • 既にインストール済みの人は念のためアップデート
  • sudo pip install --upgrade boto3

Preview 用のライブラリ

  • 承認メールに記載されているリンクから飛んだページからダウンロードできます
  • zip ファイルなのでまずは解凍
  • 今回作成するスクリプトと同じディレクトリに以下の二つのディレクトリをコピーしておきます
  • models
  • s3select

~/.aws/credentials の設定

  • 実行する時に使うアクセスキーとシークレットアクセスキーを設定します
[TestUser]
aws_access_key_id = 【アクセスキー】
aws_secret_access_key = 【シークレットアクセスキー】
region=ap-northeast-1
  • スクリプトにリージョンを記載するので、ここでのリージョンは気にしなくてもOK
  • 以下のコマンドで有効にしましょう
  • export AWS_PROFILE=TestUser
  • 有効になっているかは以下のコマンドで確認します
  • aws sts get-caller-identity
{
"Account": "【AWSアカウントID】",
"UserId": "【ユーザーID】",
"Arn": "arn:aws:iam::【AWSアカウントID】:user/【IAM ユーザー名】"
}

スクリプトの作成

  • スクリプトのサンプルは送られてきたメールのリンクから飛んだ先にあります
  • 修正するのは以下
  • 先頭に2行追加して実行時に「python」を付けなくて済むようにします
  • リージョンをデータファイルのあるリージョンに変更します(16行目)
  • バケット名を入力します(18行目)
  • オブジェクト名を入力します(19行目)
  • Expression(SQL 文)を修正します(22行目)
  • データファイルの1行目を項目名として使うように修正します(26行目)
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3
from s3select import ResponseHandler
import os

class PrintingResponseHandler(ResponseHandler):
def handle_records(self, record_data):
print(record_data.decode('utf-8'))

CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
MODELS_DIR = os.path.join(CURRENT_DIR, 'models')
os.environ['AWS_DATA_PATH'] = MODELS_DIR

s3 = boto3.client('s3','【リージョン】')
response = s3.select_object_content(
Bucket='【バケット名】',
Key='test-data/price-list.csv',
SelectRequest={
'ExpressionType': 'SQL',
'Expression': 'Select s.id, s.name, s.price from S3Object s',
'InputSerialization': {
'CompressionType': 'NONE',
'CSV': {
'FileHeaderInfo': 'Use',
'RecordDelimiter': '\n',
'FieldDelimiter': ',',
}
},
'OutputSerialization': {
'CSV': {
'RecordDelimiter': '\n',
'FieldDelimiter': ',',
}
}
}
)

handler = PrintingResponseHandler()
handler.handle_response(response['Body'])

スクリプトを実行する

  • 以下のような結果が返ってきました。
1,りんご,90
2,みかん,30
3,柿,60
4,キウイ,70
5,梨,120

色々な SQL 文で試してみる

  • Select count(*) from S3Object s
5
  • Select s.id, s.name, s.price from S3Object s where cast(s.id as int) > 3
4,キウイ,70
5,梨,120
  • Select sum(cast(s.price as int)) from S3Object s
370
  • Select max(cast(s.price as int)), avg(cast(s.price as int)), min(cast(s.price as int)) from S3Object s
120,74,30

はまった話

このブログエントリーを読んでいる方は、ここまでスムーズに来れましたか? 実は私、数時間以下のエラーメッセージと格闘していました。

botocore.exceptions.ClientError: An error occurred (UnauthorizedAccessError) when calling the SelectObjectContent operation: You are not authorized to perform this operation

サンプルスクリプトは「オレゴン」だったのですが、 「何か試すならバージニアでしょ!」 という俺ポリシーが災いして上記エラーメッセージに何度も苦しめられました。 データもオレゴンのバケットに作成し、スクリプトも「us-east-1」から「us-west-2」に戻したらあっけなく動いたという・・・ もし同じようにはまった人がいて、「そういう事は先に書けよ!」と思ってくれたらちょっとだけ嬉しいです。 仲間っていいですよね。

さいごに

という感じで S3 Select Preview を試して堪能してました。 ちょっと残念なのは、S3 Select はまだ「group by」や「order by」がありません。Preview ですし。

また、CSV の場合は「cast」しないと数字として扱ってもらえず、計算や抽出条件がうまく動きません。 この点がわかっただけでも大きな収穫です。

Amazon Athena との使い分けですが、Amazon Athena のようにデータベースやテーブルを作る必要が無いので Lambda で S3 にある CSV や JSON のデータを使うなら S3 Select の方が手軽です。 また、比較や調査はしていませんが、高速との謳い文句なので「低速だが大容量の参照用DB」として使えるのではないでしょうか。 その辺も含め、今後色々と試したくなるサービスだと思うので東京リージョンでのサービス開始が楽しみです。

それでは、この記事が皆様のお役に立てば幸いです。

参考ページ

以下のページを参考にしました。 ありがとうございました。 SELECT Object Content (Preview) S3 Select and Glacier Select – Retrieving Subsets of Objects 【速報】新サービスS3 SELECTが発表されました!! #reinvent