Nova BM25常用查询场景

更新时间:
复制 MD 格式

本文档涵盖 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;