🏠 ホーム ニュース 📖 解説記事 📚 トピック解説 🏷️ タグ一覧 ℹ️ About
🔍 記事を検索
カテゴリ
📡 RSSフィード
Follow
X (Twitter) Threads
Quick Links
ニュース一覧 🏷️ タグから探す
🧠 Claude 🤖 Agent 💬 LLM 🔌 MCP 🛠️ Tool
Subscribe
📡 RSSフィード
Breaking News
2026.04.01 07:11 coding data devops

PostgreSQL用BM25全文検索拡張がv1.0.0でプロダクション化—Timescale開発

🔍 ニュース
🔍 AI Heartland News
TL;DR
TimescaleがPostgreSQL向けBM25検索拡張pg_textsearchをv1.0.0でリリース。高速ランキング検索、Block-Max WAND最適化、並列インデックス構築に対応。

何が起きたか

Timescaleが開発するPostgreSQL用拡張機能「pg_textsearch」がv1.0.0でリリースされ、プロダクション環境での利用が可能になった。BM25ランキング関数を使用した高速な全文検索機能を提供。シンプルなSQL構文で関連度の高いドキュメントを素早く検出できる。PostgreSQL 17・18に対応し、Linux・macOS(amd64/arm64)向けのプレビルドバイナリが配布されている。

RAGシステム(検索拡張生成)における文書検索の精度向上という観点では、RAGFlowによる検索パイプライン構築と組み合わせることで、PostgreSQLだけで完結した高品質な検索基盤が実現できる。

背景と経緯

PostgreSQLの標準全文検索機能は基本的なキーワードマッチングに限定されており、検索品質(ランキング精度)の面で不十分という課題があった。プロジェクトの元の名称「Tapir(Textual Analysis for Postgres Information Retrieval)」が示すように、情報検索技術をPostgreSQLに統合する試みから発展。BM25はElasticsearchやLuceneなど企業向け検索エンジンで標準的なランキング関数であり、これをPostgresで実装することで、複雑な外部検索システムなしに高品質な全文検索が可能になる。

主な機能と仕様

機能 詳細
BM25ランキング 調整可能なパラメータ(k1, b)でドキュメント関連度を計算
Block-Max WAND最適化 TOP-K検索時に競争力のないブロックをスキップして高速化
言語サポート English, French, German等PostgreSQL標準テキスト検索設定対応
並列インデックス構築 大規模テーブルで複数ワーカーを活用
パーティションテーブル対応 各パーティションが独立してインデックス構築

BM25全文検索の仕組み

BM25(Best Match 25)は、語頻度(TF)と逆文書頻度(IDF)を組み合わせたランキング関数だ。PostgreSQL標準の ts_rank よりも検索品質が高く、ElasticsearchやLuceneが採用する実績ある手法でもある。

pg_textsearchがクエリを受け取ってから結果を返すまでのフローは以下の通りだ。

flowchart TD
    A[SQLクエリ受信<br/>content &lt;@&gt; 'search terms'] --> B[BM25インデックスのスキャン開始]
    B --> C{Block-Max WAND最適化}
    C -->|スコアが閾値以上| D[ブロックを候補として処理]
    C -->|スコアが閾値未満| E[ブロックをスキップ<br/>処理コスト削減]
    D --> F[語頻度TFの計算<br/>k1パラメータで飽和調整]
    F --> G[逆文書頻度IDFの計算<br/>全体文書数から重み付け]
    G --> H[文書長正規化<br/>bパラメータで調整]
    H --> I[BM25スコア算出<br/>負値で返却]
    E --> J{TOP-K到達?}
    I --> J
    J -->|未到達| C
    J -->|到達| K[昇順ソートで結果返却<br/>低スコア=高関連度]

    style C fill:#fff3cd
    style E fill:#d4edda
    style K fill:#cce5ff

Block-Max WAND最適化(Block-Max Weak AND)は、上位K件の候補が確定した後に残りのブロックを積極的にスキップする技術だ。全文書をスコアリングする必要がなくなるため、大規模テーブルでの検索速度が大幅に向上する。

技術的な詳細

インデックス作成と検索構文

BM25インデックスの作成は以下のように行う:

-- テーブル作成
CREATE TABLE documents (
  id bigserial PRIMARY KEY,
  content text
);

-- インデックス作成
CREATE INDEX docs_idx ON documents 
  USING bm25(content) 
  WITH (text_config = 'english');

-- 検索実行(<@> オペレータ使用)
SELECT * FROM documents 
  ORDER BY content <@> 'database system' 
  LIMIT 5;

検索結果は負のBM25スコアで返される(PostgreSQLは昇順インデックススキャンのみサポートのため)。低いスコアほど関連度が高い。

明示的なインデックス指定

PL/pgSQLやストアドプロシージャ内では、自動インデックス検出が機能しないため、明示的に指定:

SELECT * FROM documents 
  WHERE content <@> to_bm25query('database system', 'docs_idx') < -1.0
  ORDER BY content <@> 'database system'
  LIMIT 10;

パラメータ調整

BM25ランキングは調整可能なパラメータ(k1, b)をサポート。パラメータはインデックス作成時に指定できる。

CREATE INDEX docs_idx ON documents 
  USING bm25(content) 
  WITH (text_config = 'english');

text_configパラメータはPostgreSQL標準テキスト検索設定(english, french等)を指定する。

フィルタリング戦略

検索時のフィルタリングは2つのアプローチがある:

1. プリフィルタリング(推奨)

CREATE INDEX ON documents (category_id);
SELECT * FROM documents 
  WHERE category_id = 123
  ORDER BY content <@> 'search terms' 
  LIMIT 10;

行数が少なければBM25スコアリング負荷が軽減される。

2. ポストフィルタリング

SELECT * FROM documents 
  WHERE content <@> to_bm25query('search terms', 'docs_idx') < -5.0
  ORDER BY content <@> 'search terms'
  LIMIT 10;

インデックスが先に上位結果を返してからフィルタリング。結果数が要求値より少なくなる可能性あり。

対応環境とインストール

バージョン互換性

インストール手順

# ソースからコンパイル
cd /tmp
git clone https://github.com/timescale/pg_textsearch
cd pg_textsearch
make
make install  # sudoが必要な場合あり

# PostgreSQLの設定編集
# postgresql.conf に以下を追加
shared_preload_libraries = 'pg_textsearch'

# サーバー再起動後、拡張機能を有効化
CREATE EXTENSION pg_textsearch;

複数PostgreSQL版がある場合、PG_CONFIGを環境変数で指定してコンパイル対象を明示できる:

export PG_CONFIG=/path/to/pg_config
make clean && make && make install

開発ファイルのインストール

# Ubuntu/Debian
sudo apt install postgresql-server-dev-17  # PostgreSQL 17の場合
sudo apt install postgresql-server-dev-18  # PostgreSQL 18の場合

パフォーマンス最適化

インデックス構築時の設定

-- 並列ワーカー数を指定(デフォルト2)
SET max_parallel_maintenance_workers = 4;
SET maintenance_work_mem = '256MB';  -- 並列構築には最低64MB必須

-- インデックス構築
CREATE INDEX docs_idx ON documents 
  USING bm25(content) 
  WITH (text_config = 'english');

並列構築が有効な場合、ログに以下のノーティスが出力:

NOTICE: parallel index build: launched 4 of 4 requested workers

制限事項と回避策

フレーズクエリ非対応

BM25インデックスは語位置情報を保有しないため、”database system” のようなフレーズマッチに直接対応していない。回避策:

-- BM25で候補を取得、サブクエリでフレーズ検索
SELECT * FROM (
  SELECT *, content <@> 'database system' AS score 
  FROM documents 
  ORDER BY score 
  LIMIT 100  -- 過度にフェッチしてフィルタ損失に備える
) sub 
WHERE content ILIKE '%database system%' 
ORDER BY score 
LIMIT 10;

複数列インデックス非対応

インデックスは単一列限定。複数列検索には生成カラムを使用:

ALTER TABLE documents 
  ADD COLUMN search_text text 
  GENERATED ALWAYS AS (
    COALESCE(title, '') || ' ' || COALESCE(content, '')
  ) STORED;

CREATE INDEX ON documents USING bm25(search_text) 
  WITH (text_config = 'english');

パーティション間スコア比較不可

各パーティションは独立した統計情報(total_docs, avg_doc_len)を保有するため、クロスパーティション検索時のスコアは同一スケールでない:

-- 単一パーティション検索(推奨):スコア正確
SELECT * FROM docs 
  WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'
  ORDER BY content <@> 'search terms' 
  LIMIT 10;

-- クロスパーティション検索:パーティション別に独立計算
SELECT * FROM docs 
  ORDER BY content <@> 'search terms' 
  LIMIT 10;

語長制限

PostgreSQL標準の2047文字制限を継承。Base64やURLなど超長語は切り詰められる(INFOメッセージで通知)。

実装例:記事検索アプリケーション

CREATE TABLE articles (
  id serial PRIMARY KEY,
  title text,
  content text,
  category text,
  published_at timestamp
);

CREATE INDEX articles_content_idx ON articles 
  USING bm25(content) 
  WITH (text_config = 'english');

CREATE INDEX ON articles (category);  -- プリフィルタリング用

-- テストデータ
INSERT INTO articles (title, content, category) VALUES
  ('Database Systems', 
   'PostgreSQL is a powerful relational database system', 
   'technology'),
  ('Search Technology', 
   'Full text search enables finding relevant documents quickly', 
   'technology'),
  ('Information Retrieval', 
   'BM25 is a ranking function used in search engines', 
   'academic');

-- 検索例:テクノロジーカテゴリから"database search"に関連する記事
SELECT 
  title, 
  content <@> 'database search' AS relevance_score
FROM articles 
WHERE category = 'technology'
ORDER BY relevance_score
LIMIT 5;

クエリ計画の確認

EXPLAIN SELECT * FROM documents 
  ORDER BY content <@> 'database system' 
  LIMIT 5;

小規模データセットではPostgreSQLがシーケンシャルスキャンを選択する場合がある。強制的にインデックス使用:

SET enable_seqscan = off;

ただし、BM25スコアリングに必要な統計情報(文書数、平均文書長)は常にインデックスから取得される。

デバッグと統計

インデックス利用状況の確認

SELECT 
  schemaname, 
  tablename, 
  indexname, 
  idx_scan, 
  idx_tup_read, 
  idx_tup_fetch
FROM pg_stat_user_indexes 
WHERE indexrelid::regclass::text ~ 'pg_textsearch';

今後の展望

プロジェクトのROADMAP.mdに記載されている計画中の機能により、全文検索性能の継続的な向上が予定されている。

pg_textsearchのような拡張機能によってPostgreSQL単体での検索品質が高まることで、ElasticsearchやOpenSearchといった専用検索エンジンへの依存を減らす選択肢が現実的になる。特にインフラを簡素化したいチームにとって、Apache Airflowによるデータパイプラインと組み合わせてPostgreSQL中心のアーキテクチャを構築する意義は大きい。

参照ソース


この記事はAI業界の最新動向を速報でお届けする「AI Heartland ニュース」です。

よくある質問
Q. BM25ランキングとは何ですか?
BM25はElasticsearchやLuceneでも使用される標準的なランキング関数。語頻度と文書長を考慮して関連度を計算。k1(語頻飽和)とb(長さ正規化)の2つのパラメータで動作を調整可能。
Q. PostgreSQL 16以前では使用できますか?
いいえ。pg_textsearchはPostgreSQL 17・18のみ対応。16以前での使用は未サポート。
Q. インデックス作成後、どのくらい時間がかかりますか?
記事本文に具体的な時間や自動有効化の条件に関する情報がないため、本FAQは削除すべき
Q. 複数の言語で検索する場合はどうしますか?
言語ごとに別のインデックスを作成。例:english設定、french設定、german設定の3つのインデックスを別々にBM25で構築。クエリ時に言語別インデックスを指定。
Q. PL/pgSQLで使用する際の注意点は何ですか?
暗黙的な<@> 'query'構文は使用不可。必ず明示的にto_bm25query('query', 'index_name')でインデックス名を指定する必要がある。
🔔 AI速報、毎日Xで配信中
Claude Code・MCP・AIエージェントの最新ニュースをいち早くお届け
@peaks2314 をフォロー
🔥 Popular
#1 POPULAR
🔓 Claude Codeのソースコード流出、npmソースマップに51万行が丸見えだった件
Anthropic Claude Codeのnpmパッケージにソースマップが含まれ、1,902ファイル・51万行超のTypeScriptソースが公開状態に。未公開プロジェクト「KAIROS」や107個のフィーチャーフラグなど、内部コードの全貌を解説する。
#2 POPULAR
🚨 【速報】JavaScript主流ライブラリAxios、NPM供給チェーン攻撃でRAT配布
JavaScriptの週間1億DL HTTPクライアント「Axios」がNPM供給チェーン攻撃の被害に。[email protected]と0.30.4に悪意あるパッケージplain-crypto-jsが注入され、クロスプラットフォーム対応RATが配布。証拠自動削除機能を備えた高度な攻撃。
#3 POPULAR
⚠️ Anthropic、Claude Codeで予想外の高速クォータ枯渇認める。キャッシュバグで料金10〜20倍
Claude Codeでプロンプトキャッシュを破壊する2つのバグが発見され、API利用料が10〜20倍に跳ね上がる問題が発生。Anthropicは「チームの最優先事項」と認める。Pro/Maxユーザーから月間の大半で使用不可との報告多数。
#4 POPULAR
🔍 Claude Codeセキュリティ事件を切り分ける:ソース漏洩とaxios攻撃の違いと対処法
3月31日にClaude Codeで起きたソース漏洩とaxiosマルウェア。感染チェックコマンド・対策コードを交えて、2つの別事件の実態と具体的な対応手順を解説。
#5 POPULAR
🚀 ソフトウェア開発者ではない人が400ドルから年7M達成。AI時代の先発者優位性
AI技術を活用して短期間で大規模な収益を生み出した事例から、開発経験がなくても可能な起業の実態と、AI知識の先発者優位性について解説する。
← Forkrun、GNU Parallelから最大400倍高速化。NUMA対応シェル並列化ツール公開 OpenCode:13万超のスターを集めたAIコード生成・検証フレームワーク →