JSONを扱う開発者なら jq は必携ツールだ。しかし「もっと速いものはないか」と思ったことはないだろうか。jsongrep(jg)は、Rustで書かれたJSONクエリツールで、jq・jmespath・jsonpath-rustを速度面で上回ると主張している。作者はあのripgrepに触発されてこのツールを作ったと明言しており、その設計思想も似通っている。
なぜjsongreーpは速いのか?DFAという設計の核心
jqをはじめとする既存ツールは、JSONツリーを走査する際にパス式をインタープリタ方式で評価する。再帰探索(..)が絡むと、部分木を何度も訪問したり、ワークリストを管理したりと、処理コストが膨らむ。
jsongrepはこれを根本から変えた。クエリを正規言語として扱い、それをDFA(決定性有限オートマトン)にコンパイルする。DFAは入力シンボル1つにつき O(1) で状態遷移し、バックトラックも再帰スタックも不要。クエリのコストはコンパイル時に一度払えば、検索はほぼノーコストになる。
内部パイプラインは以下のステップで動く:
- クエリをパース
- JSONをツリーとして構築
- GlushkovのアルゴリズムでNFAを構築
- サブセット構成法でNFA→DFAへ変換
- DFA遷移を使ったDFS(深さ優先探索)で検索
インストールと基本的な使い方
cargo経由で即インストールできる:
cargo install jsongrep
バイナリ(jg)はクロスプラットフォーム対応で、LinuxもmacOSもWindowsも動く。
クエリ言語はシンプルかつ強力だ:
# ネストフィールドの取得
cat sample.json | jg 'roommates[0].name'
# ワイルドカードで配列全要素
cat sample.json | jg 'favorite_drinks[*]'
# 交差(どちらかにマッチ)
cat sample.json | jg 'name | roommates'
# 任意の深さで name フィールドを再帰探索
cat sample.json | jg '(* | [*])*.name'
# 再帰探索のショートハンド(-F フラグ)
cat sample.json | jg -F name
?(0または1回マッチ)や *(任意キー)、[*](任意インデックス)、正規表現ライクな|(交差)まで揃っており、使い勝手はjqに近い。パイプ先がless/sortの場合はパス表示を自動省略するなど、CLI UXへの気配りも光る。
ベンチマーク結果と公平性
作者はドキュメントパース時間・クエリコンパイル時間・検索時間・エンドツーエンド時間の4軸でjq、jmespath、jsonpath-rust、jqlと比較している。等価なクエリを各ツールで書き直して公正な比較を心がけている点も評価できる。結果はjsongreーpが全カテゴリで優位に立つとのことだ(詳細は元記事のグラフを参照)。
まとめ:jqの代替として試す価値あり
「JSON検索をもっと速くしたい」「大きなJSONを頻繁に解析する」という用途には刺さるツールだ。オートマトン理論を実用ツールに昇華させたというエンジニアリング的な面白さもある。クエリ言語の学習コストはjqと大差なく、cargo install jsongrep 一発で試せるのも魅力。jqに慣れ親しんだ開発者ほど、違いが体感しやすいはずだ。