LanceDB Node.js 全文检索 BooleanQuery 指南:用 Occur 组合子查询构建精准 FTS 查询
【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址: https://gitcode.com/gh_mirrors/la/lancedb
BooleanQuery 是 LanceDB Node.js SDK(@lancedb/lancedb)中用于组合全文检索(Full-Text Search, FTS)子查询的类。本文将深入讲解它的构造方式、Occur出现语义(Must / Should / MustNot)与queryType()方法,并结合 query.ts 的源码实现与 table.test.ts 中的真实测试用例,演示如何用它实现"必须包含 A、可以包含 B、不能包含 C"这类复杂检索需求。
1. BooleanQuery 是什么
从类型体系上看,BooleanQuery实现了FullTextQuery接口(见 FullTextQuery 接口文档),是 LanceDB FTS 查询家族的成员之一。它本身不直接执行搜索,而是把若干个子查询按照布尔出现语义组合成一个复合查询对象,再交给Table.search()执行。
在 query.ts 中可以看到其完整定义:
export class BooleanQuery implements FullTextQuery { /** @ignore */ public readonly inner: JsFullTextQuery; constructor(queries: [Occur, FullTextQuery][]) { this.inner = JsFullTextQuery.booleanQuery( queries.map(([occur, query]) => [occur, query.inner]), ); } queryType(): FullTextQueryType { return FullTextQueryType.Boolean; } }与MatchQuery、PhraseQuery、BoostQuery、MultiMatchQuery一样,BooleanQuery通过inner字段持有底层原生查询对象(napi 绑定中的JsFullTextQuery),并在构造时把每个子查询的inner解包后一并传给原生层。
2. 构造函数:queries 参数与 Occur 语义
BooleanQuery的构造函数签名如下:
new BooleanQuery(queries): BooleanQuery其中:
- queries:
[Occur, FullTextQuery][],即一组"出现语义 + 子查询"的二元组数组。Occur决定该子查询在整体匹配中的权重与约束,子查询可以是MatchQuery、PhraseQuery、MultiMatchQuery、BoostQuery甚至嵌套的BooleanQuery。
2.1 Occur 枚举:MUST / SHOULD / MUST_NOT
Occur枚举定义在 query.ts,其语义对应 Lucene 风格的布尔查询:
| 成员 | 值 | 语义 |
|---|---|---|
Should | "SHOULD" | 子查询匹配时计入相关性得分,但不是必须匹配 |
Must | "MUST" | 子查询必须匹配,否则文档不会进入结果集 |
MustNot | "MUST_NOT" | 子查询必须不匹配,匹配则该文档被排除 |
三种语义组合起来就能表达绝大多数布尔检索需求:
Must + Must:所有条件都满足(逻辑 AND);Should + Should:至少一个条件满足即可(逻辑 OR,并影响得分排序);Must + MustNot:满足 A 且不满足 B(排除式过滤)。
完整枚举定义可参考 Occur 枚举文档。
2.2 子查询类型:FullTextQueryType
BooleanQuery的queryType()固定返回FullTextQueryType.Boolean(值为"boolean")。整个FullTextQueryType枚举(FullTextQueryType 枚举文档)如下:
export enum FullTextQueryType { Match = "match", MatchPhrase = "match_phrase", Boost = "boost", MultiMatch = "multi_match", Boolean = "boolean", }也就是说,一个BooleanQuery内部可以自由混合MatchQuery(match)、PhraseQuery(match_phrase)、BoostQuery(boost)和MultiMatchQuery(multi_match)等任意子查询类型,从而构造出层级化的查询树。
3. 源码级原理:从 TypeScript 到原生查询
BooleanQuery只是门面,真正的组合逻辑发生在 Rust 侧。在 nodejs/src/query.rs 中,napi 工厂方法boolean_query接收Vec<(String, &JsFullTextQuery)>(即从 TypeScript 传入的[Occur 字符串值, 子查询对象]列表),逐个把Occur字符串解析为 Rust 枚举,再克隆子查询的inner:
pub fn boolean_query(queries: Vec<(String, &JsFullTextQuery)>) -> napi::Result<Self> { let mut sub_queries = Vec::with_capacity(queries.len()); for (occur, q) in queries { let occur = Occur::try_from(occur.as_str()) .map_err(|e| napi::Error::from_reason(e.to_string()))?; sub_queries.push((occur, q.inner.clone())); } Ok(Self { inner: BooleanQuery::new(sub_queries).into(), }) }从源码结构可以看出:
Occur的字符串值("SHOULD"、"MUST"、"MUST_NOT")是跨语言传递的契约,TypeScript 层与 Rust 层必须保持一致;- 每个子查询在进入 Rust 层前先通过
query.inner解包,因此子查询可以是任意FullTextQuery实现,包括嵌套的BooleanQuery; - 底层
BooleanQuery::new直接构造复合查询对象,随后在真正的 FTS 执行器(tantivy 引擎)中按Occur语义求值。
4. 实战示例:把 BooleanQuery 用于 Table.search()
BooleanQuery的典型用法是将其作为Table.search()的参数。Query.fullTextSearch()与Query.nearestToText()都接受string | FullTextQuery,当传入BooleanQuery这类对象时,SDK 会走"结构化查询"分支(见 query.ts),把查询对象整体交给原生层,而不是把字符串当作普通词项处理。
下面是一个完整可运行的示例(数据与断言改编自仓库测试 table.test.ts):
import { connect, Index, BooleanQuery, Occur, MatchQuery } from "@lancedb/lancedb"; const db = await connect("/tmp/lancedb-boolean-demo"); const data = [ { text: "The cat and dog are playing" }, { text: "The cat is sleeping" }, { text: "The dog is barking" }, { text: "The dog chases the cat" }, ]; const table = await db.createTable("test", data); // FTS 需要先在目标列上创建全文索引 await table.createIndex("text", { config: Index.fts({ withPosition: false }), }); // 1) SHOULD + SHOULD:命中 cat 或 dog 的文档都返回(逻辑 OR) const shouldResults = await table .search( new BooleanQuery([ [Occur.Should, new MatchQuery("cat", "text")], [Occur.Should, new MatchQuery("dog", "text")], ]), ) .toArray(); // 4 条文档全部命中(4 条里要么含 cat 要么含 dog) // 2) MUST + MUST:同时包含 cat 和 dog 的文档才返回(逻辑 AND) const mustResults = await table .search( new BooleanQuery([ [Occur.Must, new MatchQuery("cat", "text")], [Occur.Must, new MatchQuery("dog", "text")], ]), ) .toArray(); // 命中 "The cat and dog are playing" 和 "The dog chases the cat",共 2 条 // 3) MUST + MUST_NOT:包含 cat 但不包含 dog 的文档才返回 const mustNotResults = await table .search( new BooleanQuery([ [Occur.Must, new MatchQuery("cat", "text")], [Occur.MustNot, new MatchQuery("dog", "text")], ]), ) .toArray(); // 命中 "The cat is sleeping",共 1 条4.1 关键使用前提
- 必须先建 FTS 索引:对
text列执行createIndex并配置Index.fts(...)后,全文检索(含布尔组合)才能工作; - 子查询必须落在同一类查询语义上:
MatchQuery构造时的column参数指定检索列,布尔组合通常针对同一文本列进行; - 结果仍走
.toArray()/ 迭代器:search()返回链式Query对象,最终通过.toArray()或异步迭代消费结果,与普通 FTS 一致。
5. 在查询家族中的位置
BooleanQuery不是孤立存在的,它与另外四个查询类共同构成FullTextQuery体系,全部定义在 query.ts 中,并从 index.ts 对外导出:
MatchQuery(match):单列词项检索,支持boost、fuzziness、maxExpansions、operator、prefixLength;PhraseQuery(match_phrase):精确短语检索,支持slop;BoostQuery(boost):正/负查询加权,negativeBoost控制负查询惩罚力度;MultiMatchQuery(multi_match):跨多列检索,支持逐列boosts;BooleanQuery(boolean):用Occur组合上述任意查询。
由于FullTextQuery接口只要求实现queryType()并持有inner,BooleanQuery的构造参数类型是FullTextQuery[],因此你完全可以在布尔查询里嵌套BoostQuery或另一个BooleanQuery,构造出"(A 必须 且 B 应该)但不能 C"这类高精度检索表达式。
6. 小结
BooleanQuery是 LanceDB Node.js SDK 中构造复合全文检索的核心工具:
- 构造函数接收
[Occur, FullTextQuery][]数组,用MUST/SHOULD/MUST_NOT表达每个子查询的约束强度; queryType()固定返回FullTextQueryType.Boolean,标识这是一个布尔组合查询;- 内部通过 napi 把
Occur与子查询inner转发到 Rust 层(query.rs),由底层 FTS 引擎统一求值; - 实际使用时,将它传给
Table.search(),配合createIndex建立的 FTS 索引即可执行"AND / OR / NOT"组合检索,仓库测试 table.test.ts 提供了可直接对照验证的完整用例。
对需要精确控制命中条件与排除规则的全文检索场景(如搜索包含某关键词但排除另一关键词的文档),BooleanQuery是比普通字符串搜索更可靠、语义更明确的方案。
【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址: https://gitcode.com/gh_mirrors/la/lancedb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考