月別パーティションの売上をクエリする

AWSBeginner
オンラインで実践に進む

はじめに

店舗は売上を月別に保存しています。September は登録済みで、October の新しいファイルはローカルにあります。月別 S3 プレフィックスへアップロードし、Glue パーティションを登録して、Athena で新月と両月を調べます。

先に Query S3 Data with Athena を完了してください。独立した環境に分割済みの sales テーブル、September のデータと登録、ローカル CSV、設定済み AWS ID が用意されます。個人アカウントや以前の VM リソースは不要です。Terminal で通常の S3/Glue/Athena コマンドを使い、AWS View でファイル、登録場所、実際の結果を比較します。

認定試験との関連

認定 試験タスク 実践内容
Cloud Practitioner (CLF-C02) Task 3.7 Glue メタデータによって月別 S3 データを Athena 分析に利用できる仕組みを説明します。

概念図:月別 Glue パーティションが二つの S3 場所を記述し、October と月別集計を支えます。

新しい月のファイルを追加する

このステップでは、September を変えずに October をアップロードします。パーティションは月などのキーでデータを分類します。sales/month=2026-09/ は September、sales/month=2026-10/ は October 用です。key=value の名前は分類を示しますが、アップロードだけでカタログ登録されるわけではありません。

プロジェクトで ID を確認します:

cd /home/labex/project
aws sts \
  get-caller-identity

ARN は labex-an03-operator で終わります。jq -r で JSON 文字列を取得し、$(...) で変数へ保存します:

INPUT_BUCKET=$(jq -r .input_bucket resources.json)
echo "$INPUT_BUCKET"
DATABASE=$(jq -r .database resources.json)
echo "$DATABASE"
SALES_LOCATION=$(jq -r .input_location resources.json)
echo "$SALES_LOCATION"
RESULT_LOCATION=$(jq -r .output_location resources.json)
echo "$RESULT_LOCATION"

--recursive で子プレフィックスのオブジェクトも一覧表示します:

aws s3 \
  ls "s3://$INPUT_BUCKET/sales/" \
  --recursive

sales/month=2026-09/orders.csv があるはずです。September は 1000、2000、500 セント、計 3500。このファイルと無関係な reference/notes.txt を保ちます。新しい CSV を確認します:

cat october.csv

O01/east/700、O02/west/900、O03/east/400 の三件、計 2000 セントです。September と同じ三列です。専用の月別場所へアップロードします:

aws s3 \
  cp october.csv "s3://$INPUT_BUCKET/sales/month=2026-10/orders.csv"

実際のオブジェクトを読み戻します:

aws s3 \
  cp "s3://$INPUT_BUCKET/sales/month=2026-10/orders.csv" -

末尾の - は内容を端末へ表示します。AWS View では S3 に二つのファイル、Glue に September だけが見えます。到着と登録は別です。

October をカタログに登録する

このステップでは、ファイル到着だけでは不十分な理由を確認し、メタデータを追加します。パーティション定義はキー値を S3 場所とスキーマに結び付けます。month は文字列のパーティションキーです。CSV には order_id、region、total_cents だけがあり、クエリの month は定義から得られます。

キーを確認します:

aws glue \
  get-table \
  --database-name "$DATABASE" \
  --name sales \
  --query 'Table.PartitionKeys'

month、型 string です。登録前に October を数えます。COUNT(*) は一致行数を数え、引用符付き heredoc は SQL をそのまま保持します:

cat > october-before.sql <<'EOF'
SELECT COUNT(*) AS orders
FROM sales
WHERE month = '2026-10';
EOF

用意されたデータベースと出力先で送信し、ID を表示します:

BEFORE_QUERY_ID=$(aws athena \
  start-query-execution \
  --query-string file://october-before.sql \
  --query-execution-context "Database=$DATABASE" \
  --result-configuration "OutputLocation=$RESULT_LOCATION" \
  --query QueryExecutionId \
  --output text)
echo "$BEFORE_QUERY_ID"

QUEUED、RUNNING なら繰り返し、SUCCEEDED で続けます。失敗なら Reason を読みます:

aws athena \
  get-query-execution \
  --query-execution-id "$BEFORE_QUERY_ID" \
  --query 'QueryExecution.{State:Status.State,Reason:Status.StateChangeReason}'

結果を読みます:

aws athena \
  get-query-results \
  --query-execution-id "$BEFORE_QUERY_ID" \
  --query 'ResultSet.Rows[*].Data[*].VarCharValue' \
  --output table

ファイルがあっても件数は 0 です。このテーブルは登録済みの場所を読み、ディレクトリ名だけではメタデータを作りません。

同じ列と CSV 形式を保つためストレージ記述子を再利用します。> は JSON をファイルへ書きます:

aws glue \
  get-table \
  --database-name "$DATABASE" \
  --name sales \
  --query 'Table.StorageDescriptor' \
  --output json > storage-descriptor.json

jq --arg は実際の場所を文字列で渡します。.Location = $location が October の場所に置換し、Values が単一キーの値を指定します:

jq --arg location "${SALES_LOCATION}month=2026-10/" \
  '{Values:["2026-10"],StorageDescriptor:(. | .Location = $location)}' \
  storage-descriptor.json > october-partition.json

通常の JSON を確認します:

cat october-partition.json

Values が 2026-10、列が CSV と一致、場所が /sales/month=2026-10/ で終わることを確認します。${SALES_LOCATION} の波括弧は変数名と追加文字列を区切ります。file:// で JSON を読み、登録します:

aws glue \
  create-partition \
  --database-name "$DATABASE" \
  --table-name sales \
  --partition-input file://october-partition.json

両パーティションを一覧表示します:

aws glue \
  get-partitions \
  --database-name "$DATABASE" \
  --table-name sales \
  --query 'Partitions[*].{Month:Values[0],Location:StorageDescriptor.Location}'

各月がそれぞれの S3 場所を指し、AWS View に二つの対応が表示されます。登録はメタデータを変え、CSV をコピー・書き換えません。

新しい月と両月の合計を調べる

このステップでは、October を照会でき、September が正しいことを確認します。キーへの WHERE で月を選びます。記録の検証であり、本番速度やスキャン料金の測定ではありません。

October のクエリを書きます:

cat > october-sales.sql <<'EOF'
SELECT order_id, total_cents
FROM sales
WHERE month = '2026-10'
ORDER BY order_id;
EOF

新しい実行を送ります。登録しても以前のゼロ件という結果は書き換わりません:

OCTOBER_QUERY_ID=$(aws athena \
  start-query-execution \
  --query-string file://october-sales.sql \
  --query-execution-context "Database=$DATABASE" \
  --result-configuration "OutputLocation=$RESULT_LOCATION" \
  --query QueryExecutionId \
  --output text)
echo "$OCTOBER_QUERY_ID"

状態を確認し、待機中・実行中は繰り返し、成功後に進み、失敗なら理由を読みます:

aws athena \
  get-query-execution \
  --query-execution-id "$OCTOBER_QUERY_ID" \
  --query 'QueryExecution.{State:Status.State,Reason:Status.StateChangeReason}'

行を読みます:

aws athena \
  get-query-results \
  --query-execution-id "$OCTOBER_QUERY_ID" \
  --query 'ResultSet.Rows[*].Data[*].VarCharValue' \
  --output table

ヘッダー後に O01/700、O02/900、O03/400 が続きます。登録前に見えなかった同じファイルから三件を取得できました。

両月を集計します。SUM は金額、COUNT(*) は各 GROUP BY month の注文数を計算します:

cat > monthly-summary.sql <<'EOF'
SELECT month, SUM(total_cents) AS revenue_cents, COUNT(*) AS orders
FROM sales
GROUP BY month
ORDER BY month;
EOF

別の実行 ID を表示します:

MONTHLY_QUERY_ID=$(aws athena \
  start-query-execution \
  --query-string file://monthly-summary.sql \
  --query-execution-context "Database=$DATABASE" \
  --result-configuration "OutputLocation=$RESULT_LOCATION" \
  --query QueryExecutionId \
  --output text)
echo "$MONTHLY_QUERY_ID"

成功を確認します。必要なら繰り返し、失敗理由を調べます:

aws athena \
  get-query-execution \
  --query-execution-id "$MONTHLY_QUERY_ID" \
  --query 'QueryExecution.{State:Status.State,Reason:Status.StateChangeReason}'

集計結果を取得します:

aws athena \
  get-query-results \
  --query-execution-id "$MONTHLY_QUERY_ID" \
  --query 'ResultSet.Rows[*].Data[*].VarCharValue' \
  --output table

September は 3500 セント・3 件、October は 2000 セント・3 件です。September を変更せず October を追加しました。AWS View で Glue の場所、SQL、行を比較します。

実際の AWS View 例:二つの月別 S3 場所と September=3500、October=2000。バケット名と ID は異なります。

以前のゼロ件結果は、以前のカタログ状態に対する別の出力として残ります。

まとめ

月別 CSV をアップロードし、未登録では行が返らないことを確認し、Glue の場所とスキーマを登録して October と両月の合計を検証しました。ファイルとメタデータは別で、このテーブルは正しい登録後に新規場所を読めます。次は実際の結果を再利用できる集計ファイルにします。

詳しくは、AWS 公式ドキュメントを参照してください:パーティションキー、場所、登録。