
2026/09/19 22:52
Tin:Postgres フルテキスト検索
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Summary:
Neki から TIN(「Text INdex」)という一般利用可能な Postgres エキステンションがリリースされました。これは既存のデータベースへのドロップイン置換としてすぐに使用できる、高パフォーマンスな全文検索のための拡張機能です。ブール式・フレーズ・スパンクエリー、フッジー/ワイルドカード/正規表現一致、ケース/アクセントフォールディング、COUNT(*) と BM25 スコア付き top-k 結果、およびジョイン、複雑な WHERE クロース、更新、レプリケーション、バックアップ、MVCC トランザクション可視性と互換性があります。Postgres 18.6 を実行する AWS i7i.8xlarge でのベンチマーク結果は以下の通りです:
- パレード DB より 25 倍、Postgres GIN より 541 倍も多く、混合された conjunction/disjunction/phrase top-10 ランククエリーで p99 レイテンシーはパレード DB より 26 倍低い性能を示しました。
- 並行書込みを対象とした disjunction クエリー(目標:1,000 UPDATEs/sec)では、pg_textsearch より 36 倍、パレード DB より 57 倍多くのクエリを処理し、10 分間に 27 万回以上の更新を完了させました。対照的に競合他社はそれ以下の更新数でした。
- インデックスが共有バッファーに収まる場合、8 GB の Wikipedia コーパスに対する COUNT(*) disjunction クエリーでは 10,260 QPS を達成し、パレード DB は 291 QPS、Postgres GIN は 1.4 QPS にとどまりました。
本文
PostgreSQL 用高速全文検索拡張機能「TIN」が正式に発表
PostgreSQL で最も要望の多い機能が全文検索。それをさらに高速化・高機能化した拡張機能**「TIN(Text INdex)」**が正式にリリースされました。
TIN の概要と即時利用
TIN は現在、すべての PostgreSQL および Neki データベースにおいてGA(General Availability)版として利用可能です。
基本的な使用法
以下の SQL コマンドでインデックスを作成・クエリを実行できます。
-- インデックス作成 CREATE INDEX an_index_name ON table_name USING tin(text_column_name); -- 検索クエリ(BM25 スコアを含む) SELECT * FROM table_name WHERE text_column_name ==> 'some words';
サポートされる主要機能
優れた全文索引として、以下の機能をすべてサポートしています。
- 論理演算式:Boolean expressions の対応
- 高度なクエリ:フレーズクエリ、スパンクエリの対応
- マッチング精度:
- 単語に対する模糊一致(Fuzzy matching)
- ワイルドカードマッチング
- 正規表現マッチング
- 文字列処理:大文字小文字不区別、アクセント記号の無視(Case and accent folding)
- スコアリング:
クエリと BM25 スコアに基づく Top-K クエリの対応COUNT(*)
既存インデックスとの差別化
PostgreSQL には既存の全文検索インデックスがいくつか存在しますが、それらは以下のような要件をすべて満たしていませんでした。TIN はそれらを達成しました。
- JOIN 処理への完全な対応
- 複雑な WHERE クロウズ(全文検索列を含む)の高速化
- 継続的なデータ更新への耐性
- レプリケーション、バックアップ、トランザクションの可視性との共存
TIN の主な使用ケース
アプリケーション開発者は TIN を多様な検索機能構築に利用します。
1. E コマースプラットフォーム
検索キーワードをすべて含む上位 10 件の商品を返す必要时有効です。
SELECT * FROM products WHERE description ==> 'stretch denim jeans' ORDER BY tin.score(ctid) DESC LIMIT 10;
2. 法的証拠収集プラットフォーム
特定のキーワードのいずれかを包含する文書を検索し、ランキングは不要な場合にも対応します。
SELECT * FROM emails WHERE body ==> '[insider trading conspiracy]';
3. ファイルタグ付けプラットフォーム
特定のタグを持つファイルの正確な件数を表示する際などに利用します。
SELECT COUNT(*) FROM photos WHERE tags ==> '"san francisco"';
注意点:検索クエリは、新しい行や変更された行がコミットされた直後に一致結果を返す必要があります。TIN はこのリアルタイム性を満たします。
パフォーマンスベンチマーク
TIN は以下の負荷条件でテストが行われました。
- クエリ種別:
- 連語(AND)、論理和(OR)、フレーズクエリの単独使用
- これらを組み合わせた混合クエリ
- Top-K ランキングおよび
COUNT(*)
- 同時書き込み負荷:
- クライアントがインデックスに新たなデータを書き込む場合
- 書き込まない(読み取り専用)場合
- 使用コーパス:
- 全ての Wikipedia コーパス
- Reddit コメント集(合計 2.3 TB)
- Stack Exchange Q&A(85 GB、1.5 億件文書)※人工的にクエリ生成
テスト環境
- インフラ:AWS i7i.8xlarge EC2 インスタンス(NVMe ストレージ、AVX-512 CPU)
- 設定:PostgreSQL 18.6、vCPU 8 コア、RAM 32 GB
- ツール:ParadeDB Benchmarker(フォーク版を使用)
: 40 → 8max_parallel_workers
: 128 MB → 24 GBshared_buffers
: 64 MB → 24 GBmaintenance_work_mem
インデックス構築時間の比較(総時間 / サイズ / RAM)
| インデックス | 総時間 | インデックスサイズ | 必要な RAM |
|---|---|---|---|
| TIN | 8m10s | 50.7 GB | 32 GB |
| ParadeDB | 19m20s | 52.1 GB | 64 GB |
| pg_textsearch | 26m49s | 41.5 GB | 128 GB |
| Postgres GIN | 2h09m04s | 28.0 GB | 64 GB |
主要ベンチマーク結果(読み込み専用環境)
- 混合クエリ負荷:TIN は ParadeDB に比べて25 倍高速。p99 レイテンシは26 倍低減。
- 論理積・フレーズクエリ:
- TIN vs ParadeDB:10 倍高速(p99: 6 倍低減)
- TIN vs GIN:541 倍高速(p99: 1,356 倍低減)
同時書き込み負荷環境での結果
- 論理和クエリ + UPDATE 処理:
- TIN: pg_textsearch に比べて36 倍、ParadeDB に比べて57 倍高速。
- p99 レイテンシはそれぞれ 24 倍、36 倍低減。
- 10 分間の更新件数:TIN(27 万) vs ParadeDB(18 万) vs pg_textsearch(735)。
- メモリー不足の問題:
- ParadeDB は読み取りスループットとレイテンシを犠牲にして書き込みを受け付ける。
- pg_textsearch は継続的な読み込みにより書き込みが停止する(ロック競合)。
- GIN は論理和クエリ時にメモリ不足となりベンチマーク完了できなかった。
完全な比較結果表
論理積・フレーズクエリ(Top-10)
| エンジン | モード | QPS | p99 レイテンシ | MB/query |
|---|---|---|---|---|
| TIN | 読み取り専用 | 242 | 212ms | 73 |
| ParadeDB | 読み取り専用 | 24 | 1,279ms | 668 |
| Postgres GIN | 読み取り専用 | 0.4 | 288,066ms | 595 |
論理和クエリ(Top-10)
| エンジン | モード | QPS | p99 レイテンシ | MB/query | アップデート数 (10 分間) |
|---|---|---|---|---|---|
| TIN | 読み取り専用 | 148 | 324ms | 48 | - |
| TIN | 同時更新あり | 125 | 354ms | 77 | 270,279 |
| ParadeDB | 読み取り専用 | 17 | 2,385ms | 303 | - |
| ParadeDB | 同時更新あり | 2.2 | 12,634ms | 394 | 185,584 |
| pg_textsearch | 読み取り専用 | 3.5 | 8,646ms | 11,639 | - |
Wikipedia コーパスでの COUNT(*)(論理和)
| エンジン | QPS | p99 レイテンシ | MB/query |
|---|---|---|---|
| TIN | 10,260 | 2ms | 1.7 |
| ParadeDB | 291 | 95ms | 22 |
| Postgres GIN | 1.4 | 30,292ms | 2.5 |
結論:多様なシナリオにおいて、TIN はスループットが少なくとも8 倍高く、ディスク読み取りデータ量は大幅に少なく、高速な更新処理も可能です。
TIN がなぜこれほど高速なのか(アーキテクチャ解説)
TIN の高速性は以下のアーキテクチャ選択によるものです。
1. ドキュメントの識別:ctid の直接使用
多くのテキスト検索システムは「セグメント」と「連続した ID(1〜n)」を使用し、ID を ctid に変換する必要があります(マッピング維持)。これにより大量のメモリと処理が発生します。
- TIN のアプローチ:PostgreSQL の**
(現在のタプル識別子)**をそのままドキュメント ID として使用します。ctid - 利点:
- ctid は PostgreSQL 内部で既に使われているため、追加のデータ構造が不要。
- ヒープ上の物理位置
を直接参照できるため、O(1) の即時アクセスが可能。(ページ番号,オフセット) - 巨大な一致結果(千万件以上)を ctid マッピングなしで処理可能。
2. 48 ビット識別子の効率化
通常、非連続な 48 ビットの数字を圧縮するデルタ符号化やビットマップは不向きですが、PostgreSQL のページ構造により最適化されます。
- 仕組み:8KB ページ内には最大 291 タプルしか収まりません(実際のテキスト表ではさらに少ない)。
- 結果:
- ページ番号とオフセットのリストは、高密度なビットマップとして圧縮可能。
- 高頻度用語:ポスティングあたり約 1 ビット。
- 低頻度用語:約 25 ビット。
- 一度出現しない用語:保存不要。
3. ワークエリジョンとベクトル化(AVX-512/AVX2)
TIN は CPU のベクトルレジスタをフル活用しています。
- ビットマップサイズ:ページレベルのビットマップは 256 ビットで収まり、AVX2 レジスタに完全に適合。
- 演算加速:
/AND
命令により、一度に 256 ビット分のデータを処理。OR- 共通ビットがない場合、詳細なオフセット情報を参照するコストを回避可能(カウントクエリの高速化)。
- I/O 最適化:ディスクからランダムアクセスせず、シーケンシャルアクセスでページを読み取るため、NVMe でも非常に高速。
4. MVCC(マルチバージョンコンカレンシー)の正しい扱い
TIN はトランザクションの可視性を尊重し、消去された行や未確定な変更を返さないよう設計されています。
- ヒープチェック:データ列を含むクエリは、ctid 照合後に実際にヘープからデータを取得し、スナップショット可視性を確認。
- 可視性マップとのインターセクション:
クエリなどで、ページレベルのビットマップと PostgreSQL の可視性マップを直接演算し、不要なヘープアクセスを削減。COUNT(*) - ライブネスビットマップ:VACUUM で削除された ctid を管理し、古いデータが混入しないよう即時に除外。
5. セグメントとマージ戦略(書き込み増幅の回避)
一般的なシステムはマージ時にすべての ID を再番号付けし、データを再圧縮する必要があります(ストレージ使用量増加)。
- TIN のアプローチ:ctid は不変であるため、セグメント統合時にID 変更が不要。
- メリット:
- ビットマップをそのまま再利用可能(再圧縮なし)。
- データのコピー・書き換え量が極めて少ない。
- メモリ使用量とディスク I/O が大幅に削減。
まとめ
TIN は、以下の理由によりすべてのベンチマークで少なくとも 8 倍高速の性能を発揮しています。
- ctid のネイティブ活用:追加のマッピングなしで高速な物理アドレス参照を実現。
- 高度な圧縮技術:Postgres ページ構造を exploited し、48 ビットデータを極限まで圧縮。
- ベクトル化処理:現代 CPU(AVX-512)の全機能を活用した並列演算。
- 正確な MVCC 実装:トランザクション整合性下でも高速な読み書きを提供。
- ゼロコストマージ戦略:セグメント統合時のオーバーヘッドを排除。
TIN をご活用いただくことを心から期待しております。詳しくは公式ドキュメントをご覧ください。