このトピックでは、ビジネス要件に適したクエリ構文を迅速に見つけられるように、Nova BM25 の一般的なクエリシナリオについて説明します。
前提条件
このトピックの例はすべて、次のインデックス定義に基づいています。BM25 インデックスを作成していない場合は、次の SQL ステートメントを使用してサンプルインデックスを作成してください。インデックスの作成方法の詳細については、「インデックスとディクショナリの管理」をご参照ください。
CREATE INDEX docs_bm25_idx ON docs
USING nova_bm25 (body, title, category, rating, publish_at)
WITH (
text_fields = '{
"body": {"tokenizer": {"type": "jieba"}},
"title": {"tokenizer": {"type": "jieba"}},
"category": {"tokenizer": {"type": "keyword"}}
}',
numeric_fields = '{"rating": {}}',
datetime_fields = '{"publish_at": {}}'
);クエリ結果をソートする場合は、ORDER BY bm25.score(docs) DESC を明示的に使用し、LIMIT 句で返される結果数を制御することを推奨します。
基本的なクエリ
自然言語クエリ (BM25 ランキング)
自然言語テキストで関連度順に検索する場合は、次のクエリを使用します。デフォルトでは、bm25.match(text) は operator => 'or' と同等であり、いずれかのトークンが一致するとドキュメントが返されます。関数パラメータの詳細については、「関数 API リファレンス」をご参照ください。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.match('database search ranking')
ORDER BY bm25.score(docs) DESC
LIMIT 20;全トークンの一致 (AND マッチング)
クエリテキストのすべてのトークンを一致させる必要がある場合は、次のクエリを使用します。operator を 'and' に設定して AND マッチングを行います。&&& という簡略演算子も使用できます。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.match('database search', operator => 'and')
ORDER BY bm25.score(docs) DESC
LIMIT 20;簡略演算子を使用することもできます。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body &&& 'database search'
ORDER BY bm25.score(docs) DESC
LIMIT 20;中国語フレーズクエリ
連続した中国語フレーズを正確に一致させる必要がある場合は、次のクエリを使用します。bm25.phrase では、トークンが元の順序で連続して出現する必要があります。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.phrase('full-text search')
ORDER BY bm25.score(docs) DESC
LIMIT 20;高度なクエリ
ログと JSON コンテンツのクエリ
ログ、JSON、HTML などの非構造化テキストコンテンツで全文検索を実行する必要がある場合は、次のクエリを使用します。生のコンテンツをクエリパラメータとして bm25.match に直接渡すことを推奨します。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.match(
$q${"level":"error","msg":"full-text search failed","trace_id":"abc-123"}$q$,
operator => 'or'
)
ORDER BY bm25.score(docs) DESC
LIMIT 20;構造化フィルタリング (SQL 条件の組み合わせ)
全文検索と同時に、カテゴリ、評価、時間などの構造化フィールドで結果をさらにフィルタリングする必要がある場合は、次のクエリを使用します。@@@ 全文検索条件を WHERE 句内の標準的な SQL 条件と組み合わせます。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.match('database search')
AND category = 'tech'
AND rating >= 4
AND publish_at >= '2024-01-01'
ORDER BY bm25.score(docs) DESC
LIMIT 20;複数フィールドの重み付けクエリ
複数のフィールドを同時に検索し、各フィールドに異なる重みを割り当てる必要がある場合は、次のクエリを使用します。bm25.multi_match 関数を使用して、各フィールドの重み係数を指定します (例: title の重みを 5、body の重みを 2 とします)。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE docs @@@ bm25.multi_match(
ARRAY['title^5', 'body^2'],
query => 'full-text search',
operator => 'or'
)
AND category = 'tech'
ORDER BY bm25.score(docs) DESC
LIMIT 20;応用的な組み合わせ
BM25 + ベクトルハイブリッド検索 (RRF)
BM25 のキーワードマッチングとベクトルのセマンティック類似性を組み合わせたハイブリッド検索を行う場合は、次のクエリを使用します。Reciprocal Rank Fusion (RRF) アルゴリズムは、2つのランキング結果をマージし、より包括的な検索を可能にします。
WITH
bm25_top AS (
SELECT id, row_number() OVER (ORDER BY bm25.score(docs) DESC) AS bm25_rank
FROM docs
WHERE body @@@ bm25.match('database search ranking')
ORDER BY bm25.score(docs) DESC
LIMIT 100
),
vec_top AS (
SELECT id, row_number() OVER (ORDER BY embedding <#> :query_embedding) AS vec_rank
FROM docs
ORDER BY embedding <#> :query_embedding
LIMIT 100
),
rrf AS (
SELECT COALESCE(b.id, v.id) AS id,
COALESCE(1.0 / (60 + b.bm25_rank), 0) + COALESCE(1.0 / (60 + v.vec_rank), 0) AS rrf_score
FROM bm25_top b FULL JOIN vec_top v USING (id)
)
SELECT d.id, d.title, r.rrf_score
FROM rrf r JOIN docs d USING (id)
ORDER BY r.rrf_score DESC
LIMIT 20;BM25 + JOIN
BM25 全文検索結果を他のテーブルと結合する必要がある場合は、次のクエリを使用します。全文検索条件は、標準的な JOIN 構文と自由に組み合わせることができます。
SELECT d.id, d.title, c.label, bm25.score(d) AS score
FROM docs d
JOIN categories c ON d.category = c.category
WHERE d.body @@@ bm25.match('database search')
ORDER BY bm25.score(d) DESC
LIMIT 20;BM25 + GROUP BY 集計
BM25 の検索結果をグループ化して集計する必要がある場合は、次のクエリを使用します。全文検索条件は、GROUP BY および集計関数と自由に組み合わせることができます。
SELECT category, COUNT(*) AS cnt, SUM(rating) AS total_rating
FROM docs
WHERE body @@@ bm25.match('database')
GROUP BY category
ORDER BY cnt DESC;結果の表示
ハイライトとスニペット
検索結果で一致したキーワードフラグメントをハイライト表示する場合は、次のクエリを使用します。bm25.snippet は単一のハイライトされたフラグメントを返し、bm25.snippets は複数のハイライトされたフラグメントを返します。
SELECT id, title, bm25.score(docs) AS score,
bm25.snippet(body, '<em>', '</em>') AS snippet
FROM docs
WHERE body @@@ bm25.match('database search')
ORDER BY bm25.score(docs) DESC
LIMIT 20;複数のフラグメント:
SELECT id, bm25.snippets(body, '<em>', '</em>', 120, 3, 0, 'score') AS snippets
FROM docs
WHERE body @@@ bm25.match('full-text search')
ORDER BY bm25.score(docs) DESC
LIMIT 20;More Like This (類似コンテンツ検索)
既存のコンテンツに基づいて類似したドキュメントを見つける必要がある場合は、次のクエリを使用します。bm25.more_like_this 関数は、指定されたサンプルコンテンツからキーワードを抽出し、類似するドキュメントを検索します。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.more_like_this(
document => '{body:"machine learning neural network data"}',
min_term_frequency => 1,
min_doc_frequency => 1,
max_query_terms => 10
)
ORDER BY bm25.score(docs) DESC
LIMIT 20;