超巨大JSONを最小メモリで走査する:POSIX awkによるSAX型ストリーミング解析の自動化

Linux・CLI・DevOpsカテゴリを表すパンダのイラスト Linux・CLI・DevOps

ギガバイト単位の巨大なJSONログを、システムメモリを圧迫せずに高速抽出・フィルタリングするストリーム処理基盤の構築手順を解説します。

導入と前提条件

  • OS/実行環境: Linux (Debian / RHEL系)
  • 必須ツール: POSIX準拠 awk (mawk / gawk), bash 4.0+, curl

処理フローと設計

データ全体をメモリにロードせず、ストリームから1トークンずつ読み進めるSAX(Simple API for XML)ライクなアプローチを採用します。全体の構造をパースせずに特定のキーと値のペアだけを省メモリで抽出できます。

graph TD
A["JSON Data Source / API"] -->|curl --silent| B["POSIX awk SAX Stream"]
B -->|Match Key/Value| C["Data Extraction"]
C -->|Output| D["Local Log / Pipe"]
B -->|Error State| E["Trap / Alert"]

実装:自動化シェルスクリプト

以下は、jq などによる全データドキュメントのオンメモリ構築を行わず、awk のレコードセパレータとフィールドセパレータを活用して特定キーの値を抽出するスクリプトです。

#!/bin/bash
set -euo pipefail
trap 'echo "[ERROR] Line $LINENO: Command failed with exit code $?" >&2' ERR

API_URL="${1:-'http://localhost:8080/large-data.json'}"

parse_json_stream() {
    awk -v target_key="id" '
    BEGIN {
        RS = "[
,]"
        FS = ":"
    }
    {
        if ($1 ~ "\[?{\?[	 ]*\"" target_key "\"" || $1 ~ "	 *\"" target_key "\"") {
            val = $2
            gsub(/^[ 	"'
']+|[ 	"'
']+$/, "", val)
            if (length(val) > 0) {
                print val
            }
        }
    }'
}

main() {
    echo "[INFO] Starting stream parsing..." >&2
    if [ "$API_URL" = "/dev/stdin" ] || [ "$API_URL" = "-" ]; then
        parse_json_stream
    else
        curl -fLSs "$API_URL" | parse_json_stream
    fi
    echo "[INFO] Stream processing completed successfully." >&2
}

main

systemd ユニットファイル設定例

定期的なログ抽出を自動化する場合のタイマー設定例です。

# /etc/systemd/system/json-parser.service
[Unit]
Description=Stream JSON Parser Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/stream_json_parser.sh "https://api.example.com/metrics"
User=parser-user
Group=parser-user

# /etc/systemd/system/json-parser.timer
[Unit]
Description=Run JSON Parser every 5 minutes

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target

検証手順

  1. 標準入力テスト:
    echo '{"status":"ok", "items":[{"id":"A1"}, {"id":"B2"}]}' | ./stream_json_parser.sh -
    
    出力例:
    A1
    B2
    
  2. systemd ログの確認:
    journalctl -u json-parser.service -f
    

注意点と落とし穴

  • JSONのエスケープ・改行: 改行が含まれる複雑な文字列値を厳密にパースする場合は、標準 awk 単体では難しいため、C言語製ストリームパーサー(jq --streamyajl)の導入を検討してください。
  • メモリ上限の保護: ネットワーク経由の取得でパイプラインが停止しないよう、curl --max-time 300 等のタイムアウト設定を追加することを推奨します。

まとめ

  1. 全件ロードの回避: 巨大ファイル解析時には DOM 型の全件パースを行うツールをパイプラインの途中に挟まない。
  2. エラー制御: Bash の set -euo pipefail および trap を用いてパイプライン途中の失敗を確実に捕捉する。

この記事の更新履歴

この記事は、生成AIを活用した自動レビュー・更新フローにより内容を見直し、必要な修正を反映しています。

2026年9月20日

  • 削除冒頭に露出していたプロンプト作成時のメタデータJSONおよびドラフト表記を削除しました。
  • 変更全JSONをメモリにロードしてしまうjqコマンドのパイプライン依存を除去し、純粋なストリーム解析処理に修正しました。

文書情報

記事タイトル
超巨大JSONを最小メモリで走査する:POSIX awkによるSAX型ストリーミング解析の自動化
作成日
更新日
Source URL
https://papanda925.com/?p=6324

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

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