tgrep(microsoft/tgrep・GitHubスター1,658・MIT)は、三グラム索引クライアント/サーバ構成で巨大なコードベースの正規表現検索を速くする、Microsoft製のRust製ツールです。READMEには「GitHub Copilot CLIに統合され、大規模リポジトリでの高速grep検索を担う」と書かれており、AIコーディングツールの検索基盤という顔も持ちます。

謳い文句は「ripgrepより最大52倍速い」。この手の主張はリポジトリの規模やクエリ次第で大きく変わるので、v1.0.4を実際に入れて、索引の構築から検索までを走らせました。結論を先に言うと、速さは「毎回すべてのファイルを走査しない」という索引の設計から来ており、その代わりに索引の常駐と初回構築というコストが付きます。得か損かはリポジトリの規模とヒット件数で決まりました。

tgrepの実測結果。1,613ファイルの索引化20.3秒・ピーク84.5MiB、サーバ常駐時のクエリ51ミリ秒、索引はマッチし得るファイルだけを触る仕組み

30秒でわかる tgrep

何をする? 三グラム索引で、正規表現検索がマッチし得るファイルだけを触るようにする
どう速い? 手元の1,613ファイルで、サーバ常駐時のクエリが51ミリ秒。全走査するgrepは同条件で数秒かかった
代償は? 索引の初回構築(手元で20.3秒・ピーク84.5 MiB)と、最速化にはサーバ常駐が要る
向く場面は? 10万ファイル級のモノレポを一日中検索する用途。小規模・使い捨て検索はripgrepが手軽
ライセンス/版: MIT・v1.0.4(2026-09-07)・Microsoft公式・活発に更新中

開発ワークフローを速くするツールの全体像は、AI自動化ツール|ノーコードからコードまで2026年版の比較と選び方で俯瞰しています。本記事はその中でも「コードベース検索」に絞り、実測で得失を切り分けます。

tgrepとは——三グラム索引で「触るファイル」を減らすgrep

grepripgrep は、検索のたびにファイルの中身を走査します。処理量は総バイト数に比例する(O(総バイト))ため、10万ファイルを超えるモノレポでは1回の検索が重くなります。tgrepの発想はシンプルで、事前に三グラム(連続する3文字の並び)の索引を作っておき、検索語に含まれる三グラムを持つファイルだけを候補として走査するというものです。

たとえば fn main を探すとき、fn n m mamaiain という三グラムをすべて含むファイルだけが候補になります。索引がその絞り込みを担うので、実際に正規表現でマッチングする対象は全体のごく一部で済みます。これが「毎回すべてを走査しない」の中身です。

三グラム索引の勘所:三グラムは「検索し得ないファイルを外す」ためのふるいです。マッチの有無を最終判定するのは従来どおり正規表現エンジンで、索引は候補を減らすだけ。だから精度は落ちず、速さだけが変わります。逆に、ヒットが数万件に達するようなクエリでは「結果を返す」処理自体が重くなり、索引で節約した分が相殺されます(公式もこの点を明記しています)。

なぜripgrepより速いのか——クライアント/サーバとハイブリッド索引

tgrepがripgrepと決定的に違うのは、常駐サーバを持つ点です。tgrep serve . を一度起動すると、索引がメモリに載ったまま複数のクライアントに応答します。検索コマンド(tgrep "pattern" .)は起動中のサーバを自動検出して接続するため、2回目以降のクエリは索引の読み込みコストを払いません。

サーバ内部は3つの層でできています。

flowchart TD Q["tgrep pattern(クライアント)"] -->|"TCP / JSON-RPC 2.0"| S["tgrep serve(常駐サーバ)"] S --> H["HybridIndex(2層を統合)"] H --> R["IndexReader
mmap済みディスク索引
ゼロコピー・二分探索"] H --> L["LiveIndex
メモリ上のオーバーレイ
起動後に変更されたファイル"] W["File Watcher(notify)"] --> L B["Background Indexer
rayonで500件ずつ並列"] --> L L -.->|"5万件 or 5分ごとにフラッシュ"| R
  • IndexReader — ディスク上の索引をmmapで読む層。ソート済みの三グラム表を二分探索するだけなので、ファイルを開かずに候補を引けます。
  • LiveIndex — サーバ起動後に変更されたファイルや、まだ索引化途中のファイルを載せるメモリ上のオーバーレイ。
  • HybridIndex — この2層を統合し、オーバーレイを優先して「常に最新の索引」を見せます。

さらに、ファイル監視には notify クレートを使い、変更をリアルタイムでLiveIndexに反映します。背景の索引ビルダーはrayonで500件ずつ並列に索引を作り、索引が完成する前でも部分データから即座に検索に応答します。定期フラッシュ(5万件または5分ごと)でメモリ上の索引をディスクへ書き出し、メモリ使用量を一定に保ちます。

実測:tgrepの索引構築から検索まで

ここからは手元での実測です。検証環境はmacOS(Apple Silicon)、対象は当サイトのリポジトリ(git ls-files で7,410ファイル、うちバイナリ等を除いたテキスト1,613ファイル)。配布されているビルド済みバイナリ(v1.0.4)を使いました。

まず索引を作ります。

# ビルド済みバイナリを取得(macOS Apple Silicon の例)
gh release download --repo microsoft/tgrep -p '*aarch64-apple-darwin*'
tar xzf tgrep-*-aarch64-apple-darwin.tar.gz

# 索引を構築(node_modules と .git は除外)
./tgrep index . --index-path /tmp/idx --exclude node_modules --exclude .git

出力はこうでした。

Writing index (289348 trigrams, 1613 files, 2 spill segment(s))...
Index built successfully at /tmp/idx
Indexed in 20.3s using external strategy (peak memory 84.5 MiB)

28.9万三グラム・1,613ファイルの索引化に20.3秒、ピークメモリ84.5 MiB。tgrepは既定で外部マージソート(external 戦略)を使い、postingを固定サイズの領域に貯めては圧縮してディスクへ吐き、最後にk-wayマージします。これでピークメモリをリポジトリ規模にほぼ依存させません。全部をRAMでソートする --index-strategy=memory も選べますが、公式によればLinuxカーネル級では数GBに膨れます。

次に検索です。サーバを起動してからクエリを投げ、全走査型のgrepと比べました。

# サーバを常駐させる(索引はメモリに載ったまま)
./tgrep serve . --index-path /tmp/idx --no-watch &

# 正規表現で検索(起動中のサーバに自動接続)
./tgrep "def [a-z_]+\(self" . --index-path /tmp/idx

計測結果は次のとおりです。

手法 所要時間 触ったファイルの範囲
tgrep(サーバ常駐) 51 ms 索引で絞った候補ファイルのみ
grep -rE(全走査) 9,312 ms 対象ディレクトリ全ファイル

この数字の読み方に注意:grep側は .gitignore もバイナリ除外も見ずに全ファイルを走査したため、走査量そのものがtgrepより桁違いに多く、ヒット行数も一致しません(tgrepは索引が対象を絞る)。つまり「51ms対9.3秒」は同じ仕事の比較ではなく、索引で対象を絞る設計と全走査の設計の差を示す数字です。ripgrepのように .gitignore を尊重するツールとの差は、リポジトリが大きくヒットが多いほど開き、小さいリポジトリでは逆転もあり得ます——公式ベンチマークでも18ケース中1ケース(Kubernetes on Linux)はほぼ互角でした。

名前の衝突と、運用でハマる点

導入前に知っておくべき落とし穴が2つあります。

1つ目は名前の衝突です。tgrep という名前のコマンドは以前から複数存在します(ログを時刻で絞るツールなど)。日本語圏で「tgrep」を検索しても、しばらくは古い同名ツールの情報が混じります。Microsoft製を入れるつもりが別物を引かないよう、リポジトリURL(github.com/microsoft/tgrep)を確認してから導入してください。ソースからは cargo install --path tgrep-cli --locked、macOS/Linuxは brew install tgrep、各OS向けのビルド済みバイナリはGitHub Releasesにあります。

2つ目は索引と検索のフラグを揃えることです。「どのファイルが索引に含まれるか」を決めるフラグ——--no-require-git--no-ignore--max-filesize--exclude——は、tgrep indextgrep serve で一致させる必要があります。

たとえば上限なしで作った索引を --max-filesize 8M のサーバで配ると、サーバは8MiBを超える索引済みファイルを「見えない=削除された」と扱い、その索引から恒久的に落とします。両側とも既定は64 MiBなので、片側だけ上限を指定した時にだけ表面化します。索引を作る時と配る時で同じフラグを渡す、と覚えておけば避けられます。

なお .gitignore はgitリポジトリの中でしか効きません(ripgrepと同じ仕様)。Perforceや素のディレクトリで索引が想定より大きくなったら、これを疑ってください。tgrepはその状況を警告で知らせ、--no-require-git で明示的に有効化できます。

開発状況と、いま使うかの判断

tgrepはMicrosoft公式リポジトリで、更新は活発です。最新はv1.0.4(2026年9月7日)、既定ブランチへの最終pushは2026年9月8日、スターは1,658。GitHub Copilot CLIの検索基盤として実運用に乗っている点は、単なる実験プロジェクトではないことの傍証になります。

導入の損益分岐点ははっきりしています。

  • 向く:10万ファイルを超えるモノレポ、同じコードベースを一日中・何百回も検索する開発機、AIエージェントがリポジトリを繰り返し探索する基盤。索引を一度作れば以後の検索が桁違いに速くなり、常駐サーバがその効果を持続させます。
  • 向かない:小〜中規模のリポジトリ、たまに検索する程度の使い方、CIの使い捨てコンテナで一度だけ検索する場面。索引構築のコストを回収できず、ripgrepの「その場で走らせるだけ」の手軽さが総合的に勝ちます。

tgrepは「Rust製で既存のUnixツールを置き換える/速くする」系譜に連なります。ネットワーク診断で同じ立ち位置を取るのがtrippyとは|mtr コマンド相当をsudoなしで動かすRust製ネットワーク診断TUIを実測検証 で、mtr に対するtrippyは、grep に対するtgrepと同じ「定番コマンドの再実装」です。また「索引で検索を速くする」発想そのものはPostgreSQL用BM25全文検索拡張がv1.0.0でプロダクション化 のような全文検索の索引化とも地続きで、tgrepはそれをローカルのコードベース検索に持ち込んだツールだと捉えられます。

参照ソース

  • microsoft/tgrep — GitHubリポジトリ(README・アーキテクチャ・インストール手順。2026-09-09時点でv1.0.4を確認)
  • microsoft/tgrep — BENCHMARKS.md(ripgrepとの大規模リポジトリ比較・索引ビルド戦略の詳細)
  • 実測:当サイトのリポジトリ(1,613テキストファイル)でv1.0.4を用い、索引構築20.3秒/ピーク84.5 MiB、サーバ常駐時クエリ51ミリ秒を計測(2026-09-09)