17 ポイント 投稿者 GN⁺ 2026-03-28 | 3件のコメント | WhatsAppで共有
  • JSONドキュメントをパスベースで探索するRust CLIツールで、既存のjqjmespathjsonpath-rustjqlより検索速度が速い
  • クエリを正規言語として表現してDFAにコンパイルし、JSONツリーを単一パスで探索する構造により**O(n)**時間で処理
  • zero-copyパースをサポートするserde_json_borrowを使用してメモリ割り当てを最小化し、ripgrepの性能哲学を参考に設計
  • ベンチマーク結果では、大規模JSONでもエンドツーエンド性能が最も優秀で、検索中心のシンプルなクエリ言語を提供
  • MITライセンスで公開されており、DFAベースのクエリエンジンをRustライブラリとして再利用可能

jsongrep概要

  • jsongrepはJSONドキュメントでパスベースに値を検索するRust製CLIツールで、jqjmespathjsonpath-rustjqlより高速な性能を目指している
  • JSONドキュメントをツリーとして捉え、パス(path)正規言語(regular language) として表現し、DFA(Deterministic Finite Automaton) にコンパイルした後、単一パスで探索を行う
  • クエリ言語はシンプルで、検索中心に設計されており、変換や計算機能はない
  • serde_json_borrowを利用したzero-copyパースでメモリ割り当てを最小化
  • ripgrepの設計哲学と性能アプローチを参考に開発された

jsongrepの使用例

  • コマンドjgクエリJSON入力を受け取り、パスがクエリと一致するすべての値を出力する
  • ドット記法(dot path) でネストしたフィールドにアクセス
    • jg 'roommates[0].name'"Alice"
  • ワイルドカード(*, [*])ですべてのキーまたはインデックスにマッチ
  • Alternation(|)で複数のパスのうち1つを選択
  • 再帰探索((* | [*])*)で任意の深さのフィールドを検索
  • Optional(?)で0回または1回のマッチをサポート
  • -Fオプションで特定のフィールド名を高速に検索可能
  • パイプ(| less, | sort)を使うと自動的にパス出力を省略し、--with-pathで強制表示可能

jsongrepの中核概念

  • JSONはツリー構造であり、オブジェクトキーと配列インデックスがエッジ(edge) の役割を果たす
  • クエリはルートから特定ノードまでのパス集合を定義する
  • クエリ言語は正規言語として設計されているためDFAに変換可能
  • DFAは入力を1回だけ読み、バックトラッキングなしでO(n) 時間で探索を行う
  • 既存ツール(jqjmespathなど)はクエリをインタプリートして再帰的に探索するが、jsongrepは事前コンパイル済みのDFAで単一パス探索を行う

DFAベースのクエリエンジン構造

  • パイプラインは5段階で構成
    1. serde_json_borrowでJSONをツリーとしてパース
    2. クエリをASTとしてパース
    3. GlushkovアルゴリズムでNFAを生成
    4. Subset ConstructionでDFAに変換
    5. DFA遷移に従ってJSONツリーを単一DFSで探索
  • クエリパース

    • PEG文法(pestライブラリ使用)でクエリをQuery ASTに変換
    • 主な構文要素: Field, Index, Range, FieldWildcard, ArrayWildcard, Optional, KleeneStar, Disjunction, Sequence
    • 例: roommates[*].nameSequence(Field("roommates"), ArrayWildcard, Field("name"))
  • JSONツリーモデル

    • オブジェクトキーと配列インデックスはエッジ、値はノード
    • 例: roommates[*].nameroommates[0]nameのパスを探索
  • NFA構成 (Glushkovアルゴリズム)

    • ε遷移のないNFAを生成
    • 手順
      1. クエリシンボルに位置番号を付与
      2. First/Last/Follows集合を計算
      3. 各位置間の遷移を構成
    • 例のクエリroommates[*].nameのNFAは4状態で構成される単純な線形構造
  • DFA変換 (Subset Construction)

    • NFAの状態集合に基づいて決定性DFAを生成
    • 各状態は1つのNFA状態集合に対応
    • Otherシンボルを追加して不要なキーを効率よくスキップ
    • シンプルなクエリはNFAと同じ構造のDFAに変換される
  • DFSベースの探索

    • ルートから開始して各エッジに沿ってDFA遷移を実行
    • 遷移がなければそのサブツリーを枝刈り(prune)
    • DFA状態がacceptingならパスと値を記録
    • 各ノードは最大1回訪問され、全体の探索はO(n)
    • serde_json_borrowにより文字列コピーなしで元バッファを参照

ベンチマーク方法論

  • Criterion.rsで統計ベースのベンチマークを実施
  • データセット

    • simple.json (106B), kubernetes-definitions.json (~992KB), kestra-0.19.0.json (~7.6MB), citylots.json (~190MB)
  • 比較対象ツール

    • jsongrep, jsonpath-rust, jmespath, jaq, jql
  • ベンチマークグループ

    1. document_parse: JSONパース速度
    2. query_compile: クエリコンパイル時間
    3. query_search: 探索のみ実行
    4. end_to_end: 全体パイプライン
  • 公平性への配慮

    • zero-copyパースの利点は別途測定
    • DFAコンパイルコストは分離して測定
    • 機能のないツールは該当テストから除外
    • データ複製コストは分離処理

ベンチマーク結果

  • ドキュメントパース時間: serde_json_borrowが最速
  • クエリコンパイル時間: jsongrepはDFA生成のため最も大きなコストが発生し、jmespathははるかに高速
  • 検索時間: jsongrepがすべてのツールの中で最速
  • エンドツーエンド性能: 190MBデータセットでもjqjmespathjsonpath-rustjqlより圧倒的に高速
  • 全結果はライブベンチマークサイトで確認可能

ライセンスと活用

  • MITライセンスのオープンソースソフトウェア
  • GitHub、Crates.io、Docs.rsで利用可能
  • DFAベースのクエリエンジンはライブラリ形式で再利用可能で、Rustプロジェクトに直接統合できる

参考文献

  • Glushkov, V. M. (1961), The Abstract Theory of Automata
  • Rabin, M. O., & Scott, D. (1959), Finite Automata and Their Decision Problems

3件のコメント

 
roxie 28 일 전

すてきですね

 
lamanus 2026-03-28

| パイプ記号がなぜ本文では違って見えるのでしょうか? 不思議ですね..

 
GN⁺ 2026-03-28
Hacker News の意見
  • jqの文法があまりに難解で、毎回単純なJSONの値を1つ取り出すだけでも検索しないといけない

    • 興味深い。私はjqの文法は直感的だと感じていて、シェルのパイプラインのようにドット、パイプ、角括弧だけを使うのに慣れている
      主に一回限りのフィルタを書くので、読む時間より書く時間のほうが長い
      たぶん自分のユースケースが単純か、jqが自分の思考に合っているのだと思う
      すべてのCLIツールがJSONを入出力してjqでつながる世界を夢見ているが、あなたにとっては悪夢だろう
    • jqは頻繁には使わないので、**「学習の谷」**にとどまるツールだ
      使うたびに学び直す必要があり、直感的ではない
      sedもTuring完全ではあるが、ほとんどの人は正規表現による置換くらいしか使わない
    • 私が作ったcelqを勧めたい
      jqは好きだが、以前自分で書いたクエリを理解できないことがあった
      celqはよりなじみのあるCEL言語を使う
    • 私も似た理由でdqというツールを自作した
      単にJavaScriptでJSONを扱う方式だが、驚いたことにjqより速い
      $ cat package.json | dq 'Object.keys(data).slice(0, 5)' のように使う
    • JSON自体に不要な構文ノイズが多くて煩わしい
      私はClojureを学んだおかげで、今ではJSONの代わりにEDNを使っている
      より簡潔で読みやすく、構造的にも扱いやすい
      最近はborkdude/jetやbabashkaでデータを扱い、djblue/portalで可視化している
      jqの複雑な演算子にこだわる理由が理解できない
  • 性能は重要だと思うが、ナノ秒単位の比較は見せびらかしのパフォーマンスのように感じる
    ほとんどの場合、今使っているツールで十分だ
    例えば私は、大きなファイルのときだけgrepの代わりにrgを使う

    • そう思うなら「自分はターゲットユーザーではない」と考えればよい
      2msと0.2msの差は些細に見えても、TB単位のストリームを処理する人には重要だ
    • だが皆がそう考えるなら、結局は小さな非効率が積み重なり、全体が遅くなる
      ハードウェアは速くなったのに、ソフトウェアはむしろ遅くなっているのが現実だ
    • jqが差別化されるには、直感的な文法と実践的な例がもっと必要だ
    • 「十分に速い」という言葉にはいつも引っかかる
      最適化を拒むのは怠慢と想像力不足のように感じる
      ネットワーク遅延より速いからと安心するのは言い訳に聞こえる
    • 私も速度より使いやすさと機能を重視する
      もしJSONが大きすぎるなら、JSONではなくバイナリ形式を使うべきだ
      CLIで複雑なパイプラインを組む必要があるなら、むしろプログラムを書くほうがよいと思う
  • 多くの新しいCLIツールは「より速い」を売りにしているが、実際にjqが遅いと感じたことはほとんどない

    • 私はTB単位のndjsonファイルを扱う
      jqでフィールド名を変えるだけの単純な作業でも遅すぎるので、NodeやRustのスクリプトで直接処理している
    • 超巨大なログファイルを扱う場合、jqが遅く感じられることはある
      ハイパースケーラー環境では、数TBのログを直接ダウンロードして分析する
    • 私たちは数千台のノードからのJSONレスポンスをパースしている
      モニタリングの解像度によっては性能差を実感することがある
    • 新しいツールが出るたびに「Rustで作り直したより速い版」というパターンが繰り返される
      機能の一部しか実装せず、ベンチマークで勝利を主張するやり方だ
      今回のプロジェクトも、そうした**「部分集合のほうが速い」**トレンドの一環に見える
    • あるツールが遅いということは、実際に遅くなる瞬間になって初めて気づくものだ
      そこからは何もかも遅く感じられる
      ripgrepのように一度速いツールを使うと、元には戻りにくい
  • jqとyqを両方使ったことがあるが、yqはずっと遅いのに不満はなかった
    jqより速いツールがあるなら素晴らしいが、それを必要とするのは特定のユーザー層だけだ
    それでも最適化を愛する者として敬意を表したい

    • どのyqのことか気になる — Go版なのかPython版なのか?
    • サーバー統合環境では性能が重要だが、CLIではたいてい十分に速い
    • 私はArcGISからエクスポートした数GBのGeoJSONをjqで処理している
      ETL段階ではかなり時間がかかる
    • すべての人が同じようにツールを使うわけではない
  • ページを最初に開いたとき、ライトモードの色崩れがあった
    ダークモードに切り替えてから戻すと直る

    • サイトもツールのように**「vibe-coded」**された感じだ
    • 作者の自分はライトモードを使わないのでテストを忘れていた、すぐ直す予定だ
    • CSSでダークモードのスタイルが一部漏れていた問題だった
    • Android Firefoxでは問題なかったが、グラフのスケールがばらばらで比較しづらい
    • もう修正済みだ
  • 私は正確性のためにJaqへ乗り換えた
    性能もjqよりよいらしい

    • 推薦ありがとう。jaqはjsongrepより正しい方向にさらに進化しているようだ
    • ただしjaq 3.0はディストリビューション版のjqより速いが、自分でビルドしたjqのほうが速い
      jqが遅いという評判は、配布パッケージングの問題によるものに見える
  • 仕事で**newline-delimited JSON(jsonl)**をよく扱う
    各行が完全なJSONオブジェクトだが、主要なCLIツールがこの形式をサポートしているのか気になる

  • jq、mlr、htmlq、xsv、yqなど、さまざまなデータ処理CLIツールを使ってきたが、
    Nushellを見つけてからは全部置き換えられた
    1つの文法ですべてのフォーマットを扱えるのが新鮮だった

    • 私も2023年半ばからNushellをメインのシェルとして使っている
      同僚と協業するときだけjq、yq、mlrも併用する
    • 私もNushellで大半を置き換えた
      自動補完の設定やコマンドの見つけやすさに少し不便はあるが、oh-my-zshよりずっとまし
      型注釈の強制、静的バイナリのコンパイル、TUIライブラリまでそろえば、小規模アプリを書くのにも使えそうだ
    • 私も同意する。Nushellは直感的で一貫した文法のおかげで、自動化がずっと簡単になる
  • 素晴らしいツールだ! ただ、ベンチマークの可視化が少し惜しい
    すべてのツールが同じ色なので、jsongrepがどこにあるのか見つけにくい
    jq自体もグラフにないので混乱した
    xLargeファイルは190MiBで小さめだが、私は400MiB〜1GiBのJSONをよく扱う

    • 作者の自分から返答する。現在のベンチマーク範囲は106B〜190MBほどだ
      もっと大きな公開JSON文書があるなら教えてほしい
  • ベンチマークの可視化が粗く感じられる
    色や形を活用して、より多くの次元を表現できるとよい
    ファイルパスを直接読まないと結果を理解できないのは不便だ