S3 Select の機能を awscli から使ってみた
S3 Select
S3 Select は去年の AWS re:Invent で話に上がっていて少し気になっていたものの忘れていました。
S3 Select と Glacier Select – オブジェクトのサブセットを取得 | Amazon Web Services ブログ
S3 Select(Preview)を試してみました #reinvent | Developers.IO
もう二ヶ月ぐらい前ですが今年の四月に一般公開で使えるようになっていました。
S3 Select は S3 に保存しているログなどから SQL で必要なデータを絞り込んで検索したり、集計したりに使えるようです。
ログの量が膨大で全てダウンロードして処理すると時間がかかってしまうようなケースで使えるのかなと思います。
この S3 Select を awscli から少し試してみました。
Amazon Athena
似たようなサービスとして Amazon Athena というものもあります。
Amazon Athena (サーバーレスのインタラクティブなクエリサービス) | AWS
Athena は S3 を内部で使っている別のサービスで、機能としては Athena の方が色々と充実していてできることが多いのかなと思います。
ただ S3 Select は S3 に組み込まれているので単純な処理を素早くすませたいという場合には使えるのではないかと思います。
awscli からの利用
select-object-content
というのが S3 Select の機能にあたるようです。
新し目の機能なので awscli 更新しないと使えない可能性があります。
CSV と JSON に対応していて、GZIP 圧縮されているファイルも対応されています。
select-object-content — AWS CLI 1.15.31 Command Reference
API もありました。
SELECT Object Content - Amazon Simple Storage Service
SQL の仕様はここにありました。SQL といってもかなり機能が限られていて、JOIN
や GROUP BY
などは使えません。
Amazon S3 Select および Amazon Glacier Select の SQL リファレンス - Amazon Simple Storage Service
単純な例: ログの検索
CSVファイルから ERROR
という文字列を含む行だけを絞り込んで取得するという例です。
下のコマンドで実行できました。
aws s3api select-object-content \ --bucket=[バケット名] --key=[オブジェクトキー] \ --input-serialization '{"CSV":{"QuoteEscapeCharacter":"\\"}}' \ --output-serialization '{"CSV":{"QuoteFields":"ALWAYS","QuoteEscapeCharacter":"\\"}}' \ --expression "select * from s3object s where _3 LIKE '%ERROR%'" \ --expression-type SQL tmp.txt
そこまで複雑では無いもののこの書き方を覚えて毎回打ち込むというのはつらいので 実際使うときはシェルスクリプトなどを書いてフォーマットなどは決め打ちで使うのが楽かなと思います。
S3 に置いたテストデータ
1,2018-06-04T10:00:01,"hello, world" 2,2018-06-04T10:00:02,"log1" 3,2018-06-04T10:00:03,"log2" 4,2018-06-04T10:00:04,"aaa" 5,2018-06-04T10:00:05,"bbb" 6,2018-06-04T10:00:06,"ERROR: unknown error" 7,2018-06-04T10:00:07,"ERROR: timeout" 8,2018-06-04T10:00:08,"INFO: xxx" 9,2018-06-04T10:00:09,"ERROR: some error" 10,2018-06-04T10:00:10,"\"hello, world\""
取得された結果
"6","2018-06-04T10:00:06","ERROR: unknown error" "7","2018-06-04T10:00:07","ERROR: timeout" "9","2018-06-04T10:00:09","ERROR: some error"
集計関数
GROUP BY
は無いですが AVG, COUNT, MAX, MIN, SUM の集計関数がありました。where で絞り込んだ範囲全体で集計するようです。
集計関数 (Amazon S3 Select のみ) - Amazon Simple Storage Service
どうも集計関数を使う場合は数値型に cast しないとエラーになってしまうようでした。下の記事がとても参考になりました。
Amazon S3 Select で扱う JSON データの形式と Type 指定について | Developers.IO
複数ファイルから検索する例
複数ファイルから検索するには list-objects-v2
などと組み合わせてパイプでつなげれば一応はできそうです。
ただこれもかなり長くなるのでスクリプトなどを書いておくか python などから使うほうが簡単かもしれません。
下のような感じでスクリプトを書いてみました。
#!/bin/bash if [ $# -lt 3 ]; then echo "$0 [BUCKET] [KEY_PREFIX] [OUTPATH]" exit 1 fi bucket=$1 prefix=$2 outpath=$3 aws s3api list-objects-v2 --bucket $bucket --prefix $prefix \ --query 'Contents[].[Key]' --output text 2>/dev/null |\。 xargs -n1 bash -c "aws s3api select-object-content \ --bucket=\"$bucket\" --key=\"\$0\" \ --input-serialization '{\"CSV\":{\"QuoteEscapeCharacter\":\"\\\\\"}}' \ --output-serialization '{\"CSV\":{\"QuoteFields\":\"ALWAYS\",\"QuoteEscapeCharacter\":\"\\\\\"}}' \ --expression \"select * from s3object s\" \ --expression-type SQL \"$outpath/\$0.select\" || true"
まとめ
S3 Select の機能を awscli から試してみました。
コマンドの引数など色々あって面倒さはありますがドキュメントなど読めばすぐ使える感じでした。
ログからのデータ抽出など使いどころは色々とありそうなので機会があれば使っていきたいです。