
2025/12/17 0:39
ビスケットは高速パターンマッチング用に設計された、LIKE クエリ向けの特化型PostgreSQLインデックスです。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Biscuit は PostgreSQL のインデックスアクセスメソッド(IAM)で、
/LIKEクエリを高速化するように設計されており、複数列検索や集計カウントも含めトライグラム再確認を排除します。ILIKEこの拡張機能は前方/後方位置ビットマップと長さビットマップを RoaringBitmaps として格納し、別途再確認フェーズを経ずに直接ビットマップ交差を可能にします。サポート対象のデータ型は
、text(ソート可能文字列へ変換)、numeric(ソート可能タイムスタンプ)、およびdate/timeです。booleanBiscuit は 12 のパフォーマンス最適化 を組み込んでいます:不要なワイルドカード交差のスキップ、空結果時の早期終了、インプレースビットマップ操作、正確/接頭辞/接尾辞/部分文字列パターンに対する高速経路、TID ソート、バッチ挿入、直接 Roaring 反復、閾値クリーンアップ、集計検出、LIMIT‑aware コレクション、および選択性による予測子再順序付け。
100 万行のテーブルではインデックス作成に約 2.7 秒 がかかり、pg_trgm GIN の約 20 秒と比べて大幅に短縮されます。またワイルドカードを多用したパターンに対してはクエリ性能が顕著に向上します。書き込み操作は B‑tree と同様の挙動で、
はほぼ同等、INSERTは削除+挿入を行い、UPDATEはトゥームストーンをマークし定期的なバッチクリーンアップが実施されます。ビットマップはメモリ上に保持されるため、大きくなる場合は REINDEX が推奨されます。DELETE現行リリース(v2.1.4)はソースまたは PGXN 経由で入手可能で、診断ビュー (
) やbiscuit_status、biscuit_version()等の SQL 関数を提供します。biscuit_build_info()制限事項:正規表現や類似検索はサポートされず、バイトベースの文字列比較(ロケール照合順序なし)となります。また順序付きスキャンは利用できません (
)。amcanorder = falseBiscuit は e‑commerce の検索、ログ分析、CRM チケット検索、コードリポジトリ検索など
クエリを頻繁に使用するワークロードに適しています。著者はネイティブ順序付きスキャン、統計収集、追加データ型、並列ビルド、および圧縮機能の実装への貢献を歓迎します。LIKE
重要ポイント:
- キーポイントリストの全主要項目が改善された要約に含まれています。
- 元文で明示的に述べられていること以外に新たな推測はありません。
- 主旨は明確かつ簡潔で、曖昧または混乱を招く表現はありません。
本文
Biscuit – PostgreSQL 用高速パターンマッチングインデックス
バージョン 2.1.4
概要
Biscuit は、ワイルドカードが多いクエリでも圧倒的に高速な
LIKE / ILIKE パターンマッチを実現する専門的なインデックスアクセスメソッド(IAM)です。複数列検索をサポートし、trigram インデックスの再検証オーバーヘッドを排除します。
主な特徴
- ビットマップベースの文字位置インデックス
- Roaring ビットマップ圧縮(スパース/ダENSE への自動切替)
- 再検証不要 – 結果は決定的
- 内蔵診断・イントロスペクション機能
ビルドとパッケージング
- Makefile の CRoaring 検出 が複数の典型パスを確認するようになり、移植性が向上。
新しい SQL 関数
| 関数 | 戻り値 | 説明 |
|---|---|---|
| | 拡張機能のバージョン文字列 |
| | ビルド時の設定テーブル |
| | JSON 形式で同情報 |
| | CRoaring がコンパイル済みか |
| | CRoaring ライブラリのバージョン |
診断ビュー
– 単一行ビューで以下を表示biscuit_status- 拡張機能バージョン
- CRoaring 有効化状態
- 使用ビットマップバックエンド
- Biscuit インデックス総数
- 合計ディスク使用量
インストール方法
| ソース | コマンド |
|---|---|
| ソースから | |
| PGXN | |
必要条件
- ビルドツール:
,gcc
,makepg_config - 任意: 速度向上のため CRoaring ライブラリ
クイックスタート
基本的な使い方
-- Biscuit インデックス作成 CREATE INDEX idx_users_name ON users USING biscuit(name); -- ワイルドカードクエリ(再検証不要) SELECT * FROM users WHERE name LIKE '%john%'; SELECT * FROM users WHERE name NOT LIKE 'a%b%c';
複数列インデックス
CREATE INDEX idx_products_search ON products USING biscuit(name, description, category); SELECT * FROM products WHERE name LIKE '%widget%' AND description LIKE '%blue%' AND category LIKE 'electronics%' ORDER BY score DESC LIMIT 10;
対応データ型
| 型 | 例 | 備考 |
|---|---|---|
| Text | | ネイティブサポート |
| Numeric | | ソート可能文字列へ変換 |
| Date/Time | | タイムスタンプをソート |
| Boolean | | で保存 |
原理 – コアコンセプト
Biscuit は各文字列に対して 文字位置ビットマップ を構築します。
- 正方向(forward):
→ 文字 c が位置 p に出現する行を記録。c@p - 逆方向(backward):
→ 末尾から p-番目に c がある行を記録。c@-p - 大文字小文字無視 変種 (
等)。h@0 - 長さビットマップ による正確/最小長フィルタリング。
アルゴリズム例(LIKE '%abc%def'
)
LIKE '%abc%def'- パートに分割:
。["abc", "def"] - 接頭辞パート →
。pos[a@0] ∩ pos[b@1] ∩ pos[c@2] - 接尾辞パート →
。neg[f@-1] ∩ neg[e@-2] ∩ neg[d@-3] - 長さ ≥ 6 →
と交差。length_ge[6]
結果: 真陽性のみ、偽陽性は排除。
パフォーマンス最適化
| # | 最適化 | 効果 |
|---|---|---|
| 1 | ワイルドカード交差のスキップ () | 位置1で256文字全体を走査しない |
| 2 | 空ビットマップで早期終了 | 処理を即座に停止 |
| 3 | インプレース操作、冗長コピー回避 | メモリと CPU の節約 |
| 4 | 正確/接頭辞/接尾辞/サブ文字列の高速パス | よく使われるケースを迅速処理 |
| 5 | 不要な長さオペレーションを省略 | 完全ワイルドカードは長さフィルタのみ使用 |
| 6 | TID ソート(ラジックス/クイックソート) | ヒープへの連続アクセスを実現 |
| 7 | バッチ TID 挿入 | システムコールオーバーヘッド削減 |
| 8 | Roaring の直接反復 | 中間配列不要 |
| 9 | タンボーンクリーンアップの閾値ベース | ビットマップを軽量化 |
| 10 | 集計でソート省略 | COUNT, EXISTS を高速化 |
| 11 | LIMIT 対応収集 | リミットに到達したら早期終了 |
| 12 | 順序再配置(選択性) | 複数列クエリを最適実行 |
ベンチマークのハイライト
| インデックス | ビルド時間 |
|---|---|
| 20 358 ms |
| 2 734 ms |
単一列、シンプルパターン:
EXPLAIN ANALYZE SELECT * FROM benchmark WHERE name LIKE '%abc%' LIMIT 100;
複数列、複雑パターン:
SELECT * FROM benchmark WHERE name LIKE '%a%b' AND description LIKE '%bc%cd%' ORDER BY score DESC LIMIT 10;
利用事例
| ドメイン | 例 |
|---|---|
| 全文検索 | 商品カタログ: とブランド・説明フィルタ |
| ログ分析 | メッセージ、ソース、レベルでエラーログ検索 |
| CRM | 件名・顧客名・ステータスでチケット検索 |
| コード検索 | ファイル名、内容、著者でリポジトリ検索 |
| 分析 | パターンフィルタ付きイベント種別の高速 |
設定と制限
- CRoaring: 任意。ビットマップ操作を高速化。
- 順序スキャン不可 (
)。PostgreSQL のプランナーはamcanorder = false
を効率的に処理(フィルタ後の小規模メモリソート)。ORDER BY + LIMIT - メモリ使用量: ビットマップはメモリ上に保持。インデックスが大きくなったら
を実行。REINDEX
pg_trgm
との比較
pg_trgm| 機能 | Biscuit | pg_trgm (GIN) |
|---|---|---|
| ワイルドカードパターン | ネイティブ、正確 | 近似 |
| 再検証オーバーヘッド | なし | 必要 |
| 複数列 | 最適化済み | 経由 |
| 集計 | 最適化済み | 同等コスト |
| ORDER BY + LIMIT | 有効(順序スキャン不可) | 順序スキャン可 |
| 正規表現 | ❌ | ✅ |
| 類似検索 | ❌ | ✅ |
| ILIKE | ✔ | ✔ |
Biscuit を使うべきケース
- 重いワイルドカード
/LIKE
クエリ。ILIKE - 複数列パターンマッチ。
- 正確な結果と高速集計が必要。
pg_trgm に留めるべきケース
- 近似検索や類似検索。
- 正規表現使用。
- メモリ制限が厳しい環境。
開発
git clone https://github.com/Crystallinecore/biscuit.git cd biscuit make clean CFLAGS="-g -O0 -DDEBUG" make # デバッグビルド make installcheck # テスト実行 sudo make install # インストール
テスト例
CREATE EXTENSION biscuit; CREATE TABLE test (id SERIAL, name TEXT); INSERT INTO test(name) VALUES ('hello'), ('world'), ('test'); CREATE INDEX idx_test ON test USING biscuit(name); EXPLAIN ANALYZE SELECT * FROM test WHERE name LIKE '%ell%';
コントリビュート
- リポジトリをフォーク。
- 機能ブランチ作成 (
)。git checkout -b feature/... - テスト追加・コミット。
- PR を送信。
貢献可能領域
の実装(ネイティブ順序スキャン)。amcanorder- コスト推定の統計情報改善。
- さらに多いデータ型への対応(JSON, 配列等)。
- 並列インデックスビルド。
ライセンス
MIT – 詳細は LICENSE をご覧ください。
作者
Sivaprasad Murali
メール: sivaprasad.off@gmail.com
GitHub: @Crystallinecore
パターンマッチングを楽しんでください!pg_trgm が半熟のように感じるときは、ビスケット 🍪 を手に取ってみて。