Nova BM25常用查询场景
本文档涵盖 Nova BM25 的常见查询场景,帮助您根据业务需求快速找到适合的查询写法。
前提说明
本文的所有示例基于以下索引定义。如果您尚未创建 BM25 索引,请参考以下 SQL 创建示例索引。关于索引创建的详细说明,请参见Nova BM25索引和词典管理。
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',即任意分词命中即返回。更多函数参数说明,请参见Nova BM25 Function API参考。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.match('数据库检索排序')
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('数据库检索', operator => 'and')
ORDER BY bm25.score(docs) DESC
LIMIT 20;也可以使用操作符简写:
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body &&& '数据库检索'
ORDER BY bm25.score(docs) DESC
LIMIT 20;中文短语查询
当您需要精确匹配连续的中文短语时,使用以下查询写法。bm25.phrase 要求分词结果按原始顺序连续出现。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.phrase('全文检索')
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":"全文检索失败","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('数据库 检索')
AND category = 'tech'
AND rating >= 4
AND publish_at >= '2024-01-01'
ORDER BY bm25.score(docs) DESC
LIMIT 20;多字段加权查询
当您需要同时在多个字段中检索并为不同字段设置不同权重时,使用以下查询写法。通过 bm25.multi_match 函数,您可以指定各字段的权重系数(如标题权重为 5、正文权重为 2)。
SELECT id, title, bm25.score(docs) AS score
FROM docs
WHERE body @@@ bm25.multi_match(
ARRAY['title^5', 'body^2'],
query => '全文检索',
operator => 'or'
)
AND category = 'tech'
ORDER BY bm25.score(docs) DESC
LIMIT 20;组合应用
BM25 + 向量混合检索(RRF)
当您需要同时利用 BM25 关键词匹配和向量语义相似度进行混合检索时,使用以下查询写法。通过 Reciprocal Rank Fusion(RRF)算法融合两路排序结果,获得更全面的检索效果。
WITH
bm25_top AS (
SELECT id, row_number() OVER (ORDER BY bm25.score(docs) DESC) AS bm25_rank
FROM docs
WHERE body @@@ bm25.match('数据库 检索 排序')
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('数据库检索')
ORDER BY bm25.score(docs) 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('数据库')
GROUP BY category
ORDER BY cnt DESC;结果展示
高亮和片段(snippet/snippets)
当您需要在检索结果中高亮显示匹配的关键词片段时,使用以下查询写法。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('数据库检索')
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('全文检索')
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:"机器学习 神经网络 数据"}',
min_term_frequency => 1,
min_doc_frequency => 1,
max_query_terms => 10
)
ORDER BY bm25.score(docs) DESC
LIMIT 20;