S3 Select の機能を awscli から使ってみた

S3 Select

S3 Select は去年の AWS re:Invent で話に上がっていて少し気になっていたものの忘れていました。

S3 Select と Glacier Select – オブジェクトのサブセットを取得 | Amazon Web Services ブログ

S3 Select(Preview)を試してみました #reinvent | Developers.IO

もう二ヶ月ぐらい前ですが今年の四月に一般公開で使えるようになっていました。

Amazon S3 Select が一般公開

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 更新しないと使えない可能性があります。

CSVJSON に対応していて、GZIP 圧縮されているファイルも対応されています。

select-object-content — AWS CLI 1.15.31 Command Reference

API もありました。

SELECT Object Content - Amazon Simple Storage Service

SQL の仕様はここにありました。SQL といってもかなり機能が限られていて、JOINGROUP 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 から試してみました。

コマンドの引数など色々あって面倒さはありますがドキュメントなど読めばすぐ使える感じでした。

ログからのデータ抽出など使いどころは色々とありそうなので機会があれば使っていきたいです。