🐇
AWS Athena のクエリを同期的に実行するシェルスクリプト
以下をシェルスクリプトで実装します。
- Athenaにクエリを投げます。
- 出力結果のCSVをS3からダウンロードします。
尚、前提としてAthenaのworkspace
及びdatabase
,table
等のセットアップは済んでいるものとします。
ディレクトリ構造
run.sh
をDockerコンテナ内で実行することを想定以下のようなディレクトリ構成となっています
.
├── docker-compose.yml
├── Dockerfile
├── queries
├── run.sh
└── csv
queries
にはAthenaに投げるクエリのSQLファイルを配置します。csv
はCSVファイルの格納フォルダです。
準備
Athenaに投げるSQL
./queries
にSQLファイルを配置し、Athenaに投げるクエリを記載します。Athenaでは日付でパーティションが切られていることが多いと思うのでWHERE句を変数にして置換できるようにしておきます。
./queries/my_tables.sql
SELECT * FROM my_database.my_table WHERE date = :DATE_CONDITION
シェルスクリプト
シェルスクリプトを実装します。以下は完成したものです。
run.sh
#!/usr/bin/env bash
set -eu
# Athenaのworkspace及びdatabase
WORK_GROUP=myapp
DATABASE=my_database
# UNIX_TIMESTAMPをフォーマットした文字列(yyyy-mm-dd)
CURRENT_DATE=$(date --date=@${UNIX_TIMESTAMP} +%Y-%m-%d)
# Athenaのクエリ結果(CSV)を出力するパス
QUERY_RESULT_PATH="s3://${S3_BUCKET}/my_database/${UNIX_TIMESTAMP}"
# Athenaのクエリが完了するまで待機する
wait_until_query_done() {
QUERY_EXECUTION_ID=$1
while :
do
QUERY_STATUS=$(aws athena get-query-execution \
--query-execution-id ${QUERY_EXECUTION_ID} \
| jq -r .QueryExecution.Status.State)
echo "status of query which is executing on aws athena is $QUERY_STATUS"
if [[ ${QUERY_STATUS} = "SUCCEEDED" ]] || \
[[ ${QUERY_STATUS} = "FAILED" ]] || \
[[ ${QUERY_STATUS} = "CANCELLED" ]]; then
break;
fi
sleep 1
done
}
# Athenaにクエリを投げる
# 返り値: AthenaのQUERY_EXECUTION_ID
start_query_on_athena() {
TABLE=$1
QUERY=$(sed -e "s/:DATE_CONDITION/\'${CURRENT_DATE}\'/g" < ./queries/${TABLE}.sql)
QUERY_EXEC_ID=$(aws athena start-query-execution \
--query-string "${QUERY}" \
--query-execution-context Database=${DATABASE} \
--result-configuration OutputLocation=${QUERY_RESULT_PATH}/${TABLE} \
--work-group ${WORK_GROUP} \
| jq -r '.QueryExecutionId')
echo ${QUERY_EXEC_ID}
}
# Athenaにクエリを打って結果のCSVファイルをダウンロードする
download_files_from_s3() {
TABLE=$1
QUERY_EXEC_ID=$(start_query_on_athena $TABLE)
echo "query_execution_id of query which is executing on aws athena is ${QUERY_EXEC_ID}"
wait_until_query_done ${QUERY_EXEC_ID}
aws s3 cp ${QUERY_RESULT_PATH}/${TABLE}/${QUERY_EXEC_ID}.csv /tmp/csv/${TABLE}.csv
}
download_files_from_s3 my_table
以下、処理概要となります。
-
./queries/*.sql
からクエリを読み込みます。このときsed
コマンドで変数を置換します。 - 読み込んだクエリをAthenaに投げ、処理が完了するまで待機します。
- 処理が完了したらS3から実行結果のCSVファイルをダウンロードします。
Dockerfile
Dockerfile
です。用意したクエリとシェルスクリプト、必要なコマンドラインツールをインストールしておきます。また、AWSのサービスに依存したスクリプトなのでベースイメージはamazonlinux
にしました。
Dockerfile
FROM amazonlinux:2
RUN yum update -y
RUN yum install -y sudo date jq
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
unzip awscliv2.zip && \
sudo ./aws/install
COPY ./queries ./queries
COPY ./run.sh ./run.sh
ENV AWS_DEFAULT_REGION ap-northeast-1
ENV TZ Asia/Tokyo
ENTRYPOINT ["sh", "run.sh"]
docker-compose.yml
docker-compose.yml
です。volumes
にダウンロードしたCSVファイルの格納フォルダを指定します。また、環境変数には以下を指定します。
- S3_BUCKET: CSV出力先のS3バケット
- UNIX_TIMESTAMP: Athenaにクエリを投げる時に指定する日付パーティションの条件
- AWS...: AWSのクレデンシャル
docker-compose.yml
version: '3'
services:
download-athena-result:
build:
context: ./
dockerfile: ./Dockerfile
image: download-athena-result
environment:
- S3_BUCKET
- UNIX_TIMESTAMP
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_SESSION_TOKEN
volumes: ./csv:/tmp/csv
実行手順
環境変数をセットアップして実行します。
export S3_BUCKET=my-bucket
export UNIX_TIMESTAMP=xxx
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=xxx
export AWS_SESSION_TOKEN=xxx
docker-compose up
NOTE
クエリがシンプルで処理が軽いうちはいいですが、ちょっと凝ったことをしたくなったり並列実行などしたくなった場合は、素直にSDKを使って別の言語で対応したほうがいいと思います。
Discussion