UwView Pro に、ターミナルから呼べる uvp コマンドが付きました。無料版にも uvf が付いています。
GUI のツールに CLI を足すとき、いちばん怖いのは「答えが違う」ことです。速いかどうかより先に、ripgrep と同じ行が出るかを、3GB・10GB・50GB の3ファイルで突き合わせました。不一致はゼロです。そのうえで速さを測ると、10GB から先は圧倒的に uvp、3GB はファイルがキャッシュに載っているかどうかで入れ替わります。
順に書きます。
何ができるか
uvp japan.osm '東京' # rg -n -F '東京' と同じ行が出る
uvp japan.osm tokyo -i # 大文字小文字を無視
uvp japan.osm 'v="(bus_stop|traffic_signals)"' -E # 正規表現
uvp japan.osm '^ +<' -E -v # 当てはまらない行(grep -v と同じ)
uvp japan.osm 'k="amenity"' 'v="parking"' # 2語で絞り込み(rg | rg と同じ)
uvp japan.osm 'k="amenity"' -uniq 'v="([^"]+)"' -head 20 # 値の頻度・上位20
uvp japan.osm 'k="amenity"' -C 3 'k="name"' # 前後3行の中に2語目があるもの
uvp japan.osm -seq 'k="amenity",k="name"' # この順に現れるもの
uvp japan.osm '東京' -out hits.txt.gz # 結果を圧縮して保存
uvp japan.osm '東京' -open # GUI に渡して続きを見る
終了コードは grep と同じ 0=あり、1=なし。それに加えて 2=上限に当たって打ち切ったがあります。if uvp log 'ERROR'; then がそのまま書けて、暴走もしません。
上限は既定では無制限です。-limit N を書いたときだけ N 件で止まり、2 を返します。これはメモリを守るための保険で、どの N 件が残るかは決まりません——先頭 N 件が欲しいときは -head N です(後述)。
uvp uvf の名前だけで打つには、アプリのヘルプにある「コマンドライン設定…」で登録します。
答えは同じか
| ファイル | 検索語 | rg | uvp | 一致 |
|---|---|---|---|---|
| 3GB | 東京 | 11,274件 | 11,274件 | ✅ |
| 10GB | 東京 | 11,393件 | 11,393件 | ✅ |
| 50GB | 東京 | 94,979件 | 94,979件 | ✅ |
件数だけでなく、出力の行を1行ずつ比べています。大小無視・正規表現・除外・2語絞り込み・頻度集計を含めて、不一致はゼロでした。もっと広く突き合わせた記録は 81項目の突き合わせログ にあります。
速さ — キャッシュが冷えているか、温まっているか
同じ秒数でも、条件を書かないと意味がありません。ここでは2つの状態を分けて測っています。
- コールド:
sudo purgeの直後。ファイルが OS のキャッシュに載っていない状態。しばらくぶりにそのファイルを触るときがこれです - ホット: その直後にもう一度。ファイルがメモリに載っている状態。同じファイルに続けて聞くときがこれです
計測は Mac(MacBook Air / Apple M4 / メモリ32GB / 外付け USB SSD)、ripgrep 15.2.0、uvp 1.6.3、対象は OpenStreetMap 日本データ(XML)です。Windows・Linux(非力なノートPC・VMware 上)では傾向が変わる可能性があります。そちらは別途計測して記事にします。
固定文字列「東京」の検索(.uwvz は作成済み)
| サイズ | rg コールド/ホット | uvp コールド/ホット | rg÷uvp コールド/ホット |
|---|---|---|---|
| 3GB | 3.26秒/0.33秒 | 1.25秒/1.01秒 | 2.6倍/1/3.1 |
| 10GB | 10.96秒/10.89秒 | 2.37秒/1.55秒 | 4.6倍/7.0倍 |
| 50GB | 54.76秒/55.15秒 | 7.76秒/6.34秒 | 7.1倍/8.7倍 |
10GB 以上は、状態によらず uvp です。 rg はコールドもホットも同じ秒数——10GB・50GB はメモリに収まらないので、何度読んでもディスクから読み直すことになります。uvp が読むのは .uwvz(元の 1/9 の大きさ)だけなので、そこで差が付きます。
3GB だけが入れ替わります。 3GB は 32GB のメモリに収まるので、一度読めば全体がキャッシュに載り、その上を素直に走る rg が 0.33秒。uvp は本体を起動してから索引を読む固定費があり、1.01秒。ここは rg です。
3GBで負けたと思っていたら、勝っていた(ただし冷えていれば)
以前この記事には「3GB では負けます」と書いていました。コールドで測り直したら、逆でした。
| 3GB・コールド | rg | uvp | rg÷uvp | 件数 |
|---|---|---|---|---|
| 検索「東京」 | 3.26秒 | 1.25秒 | 2.6倍 | 11,274 |
大小無視 -i |
3.30秒 | 1.58秒 | 2.1倍 | 940,482 |
正規表現 -E |
3.32秒 | 1.70秒 | 2.0倍 | 928,301 |
| 正規表現(行頭つき) | 3.24秒 | 1.47秒 | 2.2倍 | 222,072 |
| 正規表現+大小無視 | 3.29秒 | 1.69秒 | 1.9倍 | 491,643 |
除外 -E -v |
3.57秒 | 1.85秒 | 1.9倍 | 1 |
除外 -v(素の語) |
3.51秒 | 3.96秒 | 1/1.1 | 7,698,790 |
7つのうち6つで uvp が速く、だいたい2倍です。理由は 10GB・50GB と同じで、読むバイト数が 1/9 で済むからです。3GB のときだけこれが見えなくなっていたのは、測っていたのが全部ホットだったからでした。
ホットで測ると、この表はほぼ裏返ります(rg 0.33〜0.65秒 対 uvp 1.01〜1.40秒)。ただし -E -v(除外)だけはホットでも uvp が速い(1.74秒 対 3.13秒)——除外は全行を相手にするので、rg にキャッシュの利が効きにくい操作です。
どちらを使うかは、自分の状況で決まります。
- 同じファイルに続けて何度も聞く(=ホット)→ 3GB なら rg
- しばらくぶりに開く、ほかの作業をはさむ、複数のファイルを行き来する(=コールド)→ 3GB でも uvp
何問目で元が取れるか
uvp は初回に索引(.uwvz)を作ります。それを含めないと不公平なので、.uwvz を消した状態から積み上げました(1問目はコールド、2問目以降はホット)。
| 10GB | 1問 | 2問 | 3問 | 4問 | 5問 |
|---|---|---|---|---|---|
| rg | 10.96秒 | 21.85秒 | 32.74秒 | 43.63秒 | 54.52秒 |
| uvp | 14.84秒 | 16.39秒 | 17.94秒 | 19.49秒 | 21.04秒 |
| 50GB | 1問 | 2問 | 3問 | 4問 | 5問 |
|---|---|---|---|---|---|
| rg | 54.76秒 | 109.91秒 | 165.06秒 | 220.21秒 | 275.36秒 |
| uvp | 74.58秒 | 80.92秒 | 87.26秒 | 93.60秒 | 99.94秒 |
1問目は必ず負けます(索引を作っているので当然です)。2問目で逆転し、5問聞くと rg の 1/2.6〜1/2.8 になります。以前 258GB で測ったときも 分岐点は1.29問目でした。サイズが変わっても形は同じです。
索引を作る時間そのものは、3GB 4.64秒・10GB 14.84秒・50GB 74.58秒(いずれも1問目の検索を含む合計)です。
無料版の uvf — v1.6.3 で ripgrep 並みになりました
uvf も同じ答えを返します。速さも v1.6.3 で作り直しました。索引を作らず、ファイルを1回通しで読むだけ(行番号・一致・本文を同時に取る)にしたので、媒体の帯域がそのまま速度になります。メモリは 50MB 程度です。
| rg コールド/ホット | uvf コールド/ホット | |
|---|---|---|
| 3GB | 3.26秒/0.33秒 | 3.32秒/0.55秒 |
| 10GB | 10.96秒/10.89秒 | 10.48秒/10.25秒 |
| 50GB | 54.76秒/55.15秒 | 50.82秒/50.63秒 |
以前は 50GB で 205秒(rg の 3.7倍遅い)でした。いまは rg とほぼ同じか、わずかに速い。ただし索引を持たないので、何度聞いても毎回この秒数です——2問目以降の速さが欲しいなら uvp です。
uvf の値打ちは、速度に加えて終了コードと -open です。スクリプトで拾って、当たったら GUI で開く。その受け渡しのためにあります。
先頭 N 件が欲しいとき — -head N
「先頭 N 件だけ見たい」は -head N です。-limit N ではありません。
| 意味 | 50GB・「東京」 | |
|---|---|---|
-head N |
1スレッドで先頭から読み、N 件見つけた時点で止まる。rg \| head -N とバイト一致 |
-head 10 0.32秒 |
-limit N |
保持する最大件数。メモリを守る保険。exit 2。どの N 件かは決まらない | -limit 1000 0.43秒 |
| 既定 | 無制限 | 全件 29,114,490件 27.12秒(rg 60.35秒) |
uvp japan.osm '東京' -head 10 # 先頭10件。rg | head -10 と同じ結果
uvp japan.osm '東京' -limit 1000 # 1000件たまったら止める(保険・exit 2)
-head 10 の 0.32秒のうち、検索そのものは 0.03秒です。残りの約0.25秒は .NET の起動で、uvp --version だけでも 0.24秒かかります。rg | head の 0.05秒には届きません——先頭 N 件だけを、何度も、サブ秒でという用途は rg の領分です。
ほかに分かったこと
- 索引を作る時間は、GUI で「開く」時間と同じでした。50GB で CLI 59.6秒、GUI 59.78秒。同じものを作っています
.uwvzはもとのファイルより小さい。3GB→0.25GB、10GB→1.16GB、50GB→5.74GB(1/9〜1/12)。しかもuvp japan.osm.uwvz '東京'のように、元ファイルが無くても.uwvzだけで検索できます-extractで.uwvzから元ファイルをバイト一致で戻せます。これは無料機能です- 外付け SSD では rg 自身も ±20〜40% ぶれます。表の数字は1回の実測で、その幅を含みます
使い分け
- 3GB 前後で、同じファイルに続けて聞く(温まっている) → rg
- 3GB 前後でも、しばらくぶりに開く(冷えている) → uvp。2倍速い
- 10GB を超える → uvp。状態によらず 4.6〜8.7倍
- 1回だけ聞いて終わり → rg。索引を作る意味がありません
- 先頭 N 件だけをサブ秒で →
rg | head - スクリプトから呼んで、当たったら人が見る → uvf / uvp の
-open
使っている道具
uvp は UwView Pro に付属します。内部で UwView Pro 本体を起動する作りなので、ライセンスは Pro のものがそのまま適用されます(Windows・macOS・Linux、1ライセンスで全OS。買い切り/月額。14日間の無料試用あり——試用中も uvp は使えます)。uvf は無料版 UwView に付属します。
数値はすべて Mac(Apple M4 / メモリ32GB / 外付け USB SSD)での自社実測で、独立ベンチマークではありません。Windows・Linux は機器も保存先も違うため、同じ秒数にはなりません。ripgrep は多数ファイルの横断検索では最速の部類で、この記事はそこを争っていません。巨大な単一ファイルに、何度も聞く場面だけの話です。
リンク
- 3GBで負けたと思っていたら、勝っていた(ただし冷えていれば) — 3GB のコールド/ホットをさらに詳しく
- uvp と rg・sed の突き合わせ 81項目 — 出力が同じであることの記録
- 258GB・45億行に、5つの質問をする — grepとGUI、どこで逆転するか
- ripgrepは巨大単一ファイルでも最速なのか — 51GB・8.9億行で実測
- 実測まとめ — 巨大ファイル対応ツール 実測性能比較

