ちょっと話題の記事

Amazon S3 Select が一般公開されたので使ってみた(Python)

東京リージョンも含め、全リージョンで使えるようになった S3 Select ですが、S3 に置いてあるデータを簡単なコーディングで取得できるかなり強力なサービスです。Lambda で使う時の参考になるように Python でサンプルコードを作成しました。
2018.04.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんばんは、菅野です。 Amazon S3 Select が一般公開されました。しかも全リージョンで使えます。 Preview 時のブログエントリーでは Python で試したので、違いを確認するために今回も Python でいってみます。

必要なポリシーって?

菅野はぎりぎりのポリシーで運用するのが好きです。 なので今回も最低限のポリシーからスタートしてみました。 試した結果、「GetObject」だけあれば S3 Select は動きます。

データの準備

いつものデータを使います。

"id","name","price"
1,"りんご",90
2,"みかん",30
3,"柿",60
4,"キウイ",70
5,"梨",120

このデータを S3 にアップロードしておきましょう。

boto3

Python を使って AWS を操作するなら絶対必要です。

  • AWS SDK for Python
  • 最新版にしておきましょう
  • sudo pip install --upgrade boto3

~/.aws/credentials の設定

【鍵管理】~/.aws/credentials を唯一のAPIキー管理場所とすべし【大指針】 | Developers.IO

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

スクリプトの準備

S3 Select and Glacier Select – Retrieving Subsets of Objects | AWS News Blog

  • Preview からの変更点(あまり意味ないですが)
  • SelectRequest の中にあったものが Bucket や Key と同じ書き方となった
  • 以下のスクリプトを「test.py」として保存してください
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3
s3 = boto3.client( 's3', 'ap-northeast-1' )

response_s3select = s3.select_object_content(
Bucket = '【バケット名】',
Key = 'test-data/price-list.csv',
ExpressionType = 'SQL',
Expression = 'Select s.id, s.name, s.price from S3Object s',
# Expression = 'Select count(*) from S3Object s',
# Expression = 'Select s.id, s.name, s.price from S3Object s where cast(s.id as int) > 3',
# Expression = 'Select sum(cast(s.price as int)) from S3Object s',
# Expression = 'Select max(cast(s.price as int)), avg(cast(s.price as int)), min(cast(s.price as int)) from S3Object s',
# Expression = '',
InputSerialization = {
'CompressionType': 'NONE',
'CSV' : {
'FileHeaderInfo' : 'Use',
'RecordDelimiter' : '\n',
'FieldDelimiter' : ','
}
},
OutputSerialization = {
'CSV' : {
'RecordDelimiter' : '\n',
'FieldDelimiter' : ','
}
}
)

for event in response_s3select[ 'Payload' ]:
if 'Records' in event:
records = event[ 'Records' ][ 'Payload' ].decode( 'utf-8' )
print( records )
  • Bucket
  • バケット名です
  • Key
  • データの入っている S3 オブジェクトのパスとファイル名です
  • Expression
  • SQL 文をここに書きます
  • Preview の時にテストで使った5つを用意しておきました
  • InputSerialization
  • データの情報です
  • FileHeaderInfo
  • データの1行目をヘッダとして使うかを指定します
  • USE / IGNORE / NONE のどれかを指定します
  • RecordDelimiter
  • レコードとレコードの区切りを指定します
  • 今回は改行コードを指定してあります
  • FieldDelimiter
  • 項目と項目の区切りを指定します
  • 今回は「,(カンマ)」を指定してあります
  • OutputSerialization
  • 出力に関する設定です
  • InputSerialization と同様なので説明は省略します

スクリプトを実行する

それでは準備ができましたので実行してみましょう。

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

準備していた他の SQL も前回と同様に動くのかチェックします

  • レコード数を取得します
  • Select count(*) from S3Object s
5
  • 項目「id」が 3 より大きいレコードを取得します
  • 用意したデータの1行目で指定した項目名を使ってデータを取得しています
  • Select s.id, s.name, s.price from S3Object s where cast(s.id as int) > 3
4,キウイ,70
5,梨,120
  • 全レコードの項目「price」の合計を取得します
  • int 型にキャストしてから sum によって合計を計算しています
  • Select sum(cast(s.price as int)) from S3Object s
370
  • 項目「price」の最大値、平均値、最小値 を取得しています
  • 先ほどと同様、int 型にキャストしてから計算しています
  • 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

まとめ

取得方法が若干変更になってましたが、Preview の時よりも使いやすく、可読性も良くなったと思います。

さいごに

いかがでしたでしょうか。 お手軽に S3 に置いたデータを取得、検索できる S3 Select は東京リージョンでも使えるようになりましたし、これから活躍の場が大いに増えるのではないでしょうか。 Amazon S3 Select で使える SQL の情報は以下にありますので、皆さんも色々と試してみてください。 Amazon S3 Select および Amazon Glacier Select の SQL リファレンス - Amazon Simple Storage Service

参考ページ

以下のページを参考にしました。 ありがとうございました。 S3 — Boto 3 Docs 1.7.4 documentation S3 Select and Glacier Select – Retrieving Subsets of Objects | AWS News Blog