jqを活用したJSONデータの高度なグループ化と集計の自動化手法

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

jqを活用したJSONデータの高度なグループ化と集計の自動化手法

【導入と前提】

APIレスポンスやログ等のJSON配列を、特定のキーで集計・要約してSREのモニタリング効率を向上させます。

  • 実行環境: Linux (Ubuntu/RHEL等), jq 1.6以上, curl

【処理フローと設計】

graph TD
A["Raw JSON Data"] -->|jq 'group_by'| B["Nested Arrays by Key"]
B -->|jq 'map/reduce'| C["Aggregated Object"]
C -->|STDOUT| D["Summary Report / Alerting"]

group_by で対象キーごとに配列を分割し、mapreduce を組み合わせて「合計」「平均」「カウント」などの集計処理を一括で行う設計です。

【実装:堅牢な自動化スクリプト】

以下は、クラウドのリソース使用量ログ(JSON)を取得し、サービス単位でコストを集計するスクリプトの例です。

#!/usr/bin/env bash

# ---------------------------------------------------------


# script: aggregate_resource_costs.sh


# description: JSON配列をサービス名でグループ化し、合計コストを算出する


# ---------------------------------------------------------

set -euo pipefail # エラー発生で停止、未定義変数参照禁止、パイプエラーの伝播
trap 'rm -f "$TMP_DATA"' EXIT # 終了時に一時ファイルを確実に削除

# 設定

readonly API_ENDPOINT="https://api.example.com/v1/billing/usage"
readonly TMP_DATA=$(mktemp) # セキュアな一時ファイルの作成

# 1. データ取得(リトライ処理付き)

echo "Fetching usage data..."
curl -s -S -L \
  --retry 3 \
  --retry-delay 2 \
  -H "Authorization: Bearer ${API_TOKEN:-}" \
  "$API_ENDPOINT" -o "$TMP_DATA" || { echo "Error: Failed to fetch data"; exit 1; }

# 2. jqによる高度な集計処理


# group_by(.service) : サービス名ごとに配列を分割


# map({...})        : 各グループに対して集計オブジェクトを作成


# reduce            : (オプション) 更に大きな集計を行う場合に利用

echo "Aggregating data..."
jq -r '
  group_by(.service) | 
  map({
    service: .[0].service,
    total_cost: (map(.amount) | add),
    count: length,
    average_usage: (if length > 0 then (map(.amount) | add) / length else 0 end)
  }) |
  sort_by(.total_cost) | reverse
' "$TMP_DATA"

# 3. 特定条件でのフィルタリング例 (reduce活用)


# 全サービスの総計を1つのオブジェクトで出す場合

echo "Calculating grand total..."
jq -r '
  reduce .[] as $item (0; . + $item.amount) | 
  {grand_total: .}
' "$TMP_DATA"

【検証と運用】

正常系の確認

スクリプトを実行し、標準出力に整形されたJSONが表示されるか確認します。

./aggregate_resource_costs.sh | jq .

ログ確認と異常検知

システム構成に組み込む場合、systemd-cat を経由させることで journalctl での追跡が可能になります。

# systemdタイマー等で実行する場合のログ確認

journalctl -u resource-aggregation.service -f

【トラブルシューティングと落とし穴】

  1. メモリ消費量: group_by は入力全体をメモリ上に展開するため、数GB単位の巨大なJSONファイルを扱うとOOM(Out Of Memory)が発生する可能性があります。その場合は、jq -c '.[]' でストリーム処理を検討してください。

  2. 型変換の失敗: 数値フィールドに文字列が混入している場合、add 演算子がエラーになります。(.amount | tonumber) のように明示的なキャストを推奨します。

  3. 環境変数の保護: API_TOKEN などの機密情報はスクリプト内にハードコードせず、export するか、CI/CDのSecretマネージャーから注入してください。

【まとめ】

運用の冪等性と堅牢性を維持するための3つのポイント:

  1. 型安全性の確保: tonumberdefault(0) を使い、不正なJSON入力でもスクリプトを落とさない。

  2. 一時ファイルの管理: trap コマンドを使用して、異常終了時でもゴミを残さない。

  3. リトライロジック: ネットワークの瞬断に備え、curl--retry オプションを適切に設定する。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました