恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Lance 全文检索(Full-Text Search)实战指南:从倒排索引构建到 BM25 高级查询

  • 首页
  • 资讯中心
  • /
  • Lance 全文检索(Full-Text Search)实战指南:从倒排索引构建到 BM25 高级查询

相关资讯

Flower 模拟引擎退出码 701 SIMULATION_MISSING_EXTRA:成因排查与在 pyproject.toml 中的标准修复方案 2026/9/17 10:09:32
汽车电子PCBA应力测试实战:焊点暗裂预防与关键点位全解析 2026/9/17 10:04:32
n8n 一行命令自托管部署完整指南 2026/9/17 10:04:32

最新资讯

嵌入式软件架构实战:四层架构与事件驱动设计
PeopleSoft Application Engine 批处理执行与重启排错
泛微Ecology9接口对接实战:Java获取Token与调用流程审批API
故意改错Linux内核QEMU图形驱动:四个实验看透VGA显示链路
LY-E252国产EtherCAT从站芯片:同封装替换LAN9252实战指南
淘宝扫码登录与Cookie持久化:避开异地风控,用Python稳定复用登录态

今日推荐

每日热评|13% 的 Agent 技能带严重漏洞,这个注册表想用“验证+签名”解决信任危机
即梦AI保姆级教程:从生图到数字人,一站式搞定AI视频创作
BERT+LLM混合架构:突破NER长尾实体抽取瓶颈的工程实践

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Lance 全文检索(Full-Text Search)实战指南:从倒排索引构建到 BM25 高级查询

发布时间:2026/9/17 10:09:32
Lance 全文检索(Full-Text Search)实战指南:从倒排索引构建到 BM25 高级查询 Lance 全文检索Full-Text Search实战指南从倒排索引构建到 BM25 高级查询【免费下载链接】lanceOpen Lakehouse Format for Multimodal AI. Convert from Parquet in 2 lines of code for 100x faster random access, vector index, and data versioning. Compatible with Pandas, DuckDB, Polars, Pyarrow, and PyTorch with more integrations coming..项目地址: https://gitcode.com/GitHub_Trending/la/lanceLance 通过倒排索引Inverted Index提供开箱即用的全文检索能力基于 BM25 相关性评分实现接近工业级搜索引擎的召回与排序效果。本文以docs/src/quickstart/full-text-search.md为骨架结合仓库中的索引规范文档与源码实现完整讲解如何在 Lance 数据集中构建INVERTED/NGRAM标量索引、配置分词与语言处理参数、编写布尔/短语/模糊查询并给出索引维护与性能调优的实操建议。读完本文你将能够从零搭建一个支持多语言分词、元数据过滤、近似拼写容错的高性能文本搜索管道。环境准备安装 Python SDK全文检索能力通过 Python SDK 暴露首先安装运行依赖pip install pylance pyarrow然后导入库Lance 的 Python 绑定与 PyArrow 协同工作数据集以 Arrow 表形式读写import lance import pyarrow as pa准备文本数据并写入数据集全文检索索引作用于某一文本列因此第一步是准备文档数据并写入 Lance 数据集。以下示例创建三条包含重叠关键词的文本记录便于后续演示不同查询场景table pa.table( { id: [1, 2, 3], text: [ I left my umbrella on the evening train to Boston, This ramen recipe simmers the broth for three hours with dried mushrooms., This train is scheduled to leave for Edinburgh at 9:30 in the morning, ], } ) # Write to a new Lance dataset lance.write_dataset(table, /tmp/fts.lance, modeoverwrite)写入完成后可以用lance.dataset打开数据集并查看其 PyArrow schemads lance.dataset(/tmp/fts.lance) print(ds.schema)输出id: int64 text: large_string可以看到文本列被推断为large_string即 Arrow 的Utf8大字符串类型这是全文检索索引的典型输入类型。构建倒排索引create_scalar_index基础用法Lance 的全文检索通过倒排标量索引INVERTED实现它把每个词token映射到包含该词的文档集合从而支持海量文本上的高性能关键词检索。创建索引只需在文本列上调用create_scalar_index并指定index_typeINVERTEDds.create_scalar_index( columntext, index_typeINVERTED )索引创建后查询结果会按 BM25 相关性评分自动排序分数越高表示匹配越相关。在 Rust 核心实现中倒排索引由rust/lance/src/index/scalar/inverted.rs承载创建完成后数据集上会挂载一个独立的索引文件集合详见下文「存储布局」小节。警告索引创建耗时索引构建时间取决于文本数据规模大数据集上可能需要数分钟但查询阶段的性能收益是显著的。高级配置参数create_scalar_index支持丰富的参数来针对具体场景优化索引行为完整参数如下ds.create_scalar_index( columntext, index_typeINVERTED, nametext_idx, # Optional index name (if omitted, default is text_idx) with_positionFalse, # Set True to enable phrase queries (stores token positions) base_tokenizersimple, # Tokenizer: simple, icu, icu/split, whitespace, raw, or ngram languageEnglish, # Language used for stemming stop words (only used if stem or remove_stop_words is True) max_token_length40, # Drop tokens longer than this length lower_caseTrue, # Lowercase text before tokenization stemTrue, # Stem tokens (language-dependent) remove_stop_wordsTrue, # Remove stop words (language-dependent) custom_stop_wordsNone, # Optional additional stop words (only used if remove_stop_wordsTrue) ascii_foldingTrue, # Fold accents to ASCII when possible (e.g., é - e) block_size128, # Posting block size: 128 or 256; 256 is experimental )这些参数与索引规范文档docs/src/format/index/scalar/fts.md中定义的InvertedIndexParams一一对应其默认值如下表字段类型默认值说明base_tokenizerStringsimple基础分词器类型languageStringEnglish用于词干提取与停用词的语言with_positionBooleanfalse是否存储词位置以支持短语查询会显著增大索引max_token_lengthUInt32?None超过该长度的 token 会被丢弃lower_caseBooleantrue分词前统一转为小写stemBooleanfalse是否应用语言相关的词干提取remove_stop_wordsBooleanfalse是否移除指定语言的常见停用词ascii_foldingBooleantrue将重音字符折叠为 ASCII 等价形式min_gramUInt322仅 ngram 分词器使用最小 n-gram 长度max_gramUInt3215仅 ngram 分词器使用最大 n-gram 长度prefix_onlyBooleanfalse仅 ngram 分词器使用只生成前缀 n-gramblock_sizeUInt32128每个压缩 posting 块包含的文档数必须为 128 或 256256尚属实验特性注意Python 层快速入门文档中stem、remove_stop_words的示例值为True而规范文档记录的服务端默认值分别为false/falselower_case与ascii_folding默认true。在不确定时建议显式传参避免依赖隐式默认值。分词器与语言处理选项索引质量在很大程度上取决于分词与文本规范化策略。Lance 支持多套分词器基础分词器simple按空白与标点切分并剔除非字母数字字符通用文本的默认选择whitespace仅按空白切分保留标点符号raw不做分词将整个文本视为单一 token适合精确匹配场景ngram将文本切分为重叠的字符序列面向子串/模糊检索见下文 N-gram 小节多语言分词器icu基于内置 ICU 词典的 Unicode 分词适合中日韩泰等复杂脚本与混合语言文本无需下载外部语言模型使用icu/split可进一步在非字母数字分隔符如下划线、标点处再次切分jieba/default使用 Jieba 对中文文本进行分词模型需放置在 Lance 主目录下的jieba/目录并通过config.json配置主词典与用户词典lindera/ipadic、lindera/unidic使用 Lindera 对日语进行形态分析模型放置于lindera/目录通过config.yml配置lindera/ko-dic使用 Lindera 搭配 Ko-dic 词典对韩语分词分词过滤器基础分词器输出之后按顺序应用以下过滤器——RemoveLong依据max_token_length丢弃超长 token、LowerCase默认开启、Stemmer词干提取如 running → run、StopWords移除 the、and、is 等停用词、AsciiFolding重音折叠如 é → e。语言支持词干提取与停用词移除支持阿拉伯语、丹麦语、荷兰语、英语、芬兰语、法语、德语、希腊语、匈牙利语、意大利语、挪威语、葡萄牙语、罗马尼亚语、俄语、西班牙语、瑞典语、泰米尔语、土耳其语。基础全文检索查询索引构建完成后在to_table方法中通过full_text_query参数传入关键词即可检索import lance # Open dataset ds lance.dataset(/tmp/fts.lance) # Specify keyword phrases when calling the to_table method query_result ds.to_table( full_text_queryumbrella train ) print(query_result)该查询返回包含 umbrella 或 train任一即可的文档检索大小写不敏感且直接走倒排索引加速。输出结果中除了原始列还包含 BM25 相关性分数_scoreid: [[1, 3]] text: [[I left my umbrella on the evening train to Boston, This train is scheduled to leave for Edinburgh at 9:30 in the morning]] _score: [[..., ...]]全文检索与元数据过滤组合实际业务中常需要「文本相关性 结构化条件」的复合查询。只需在full_text_query之外再传入filter表达式即可Lance 会先在元数据层面裁剪数据再对剩余文档执行文本检索import lance import pyarrow as pa table pa.table( { id: [1, 2, 3], text: [ I left my umbrella on the morning train to Boston, This ramen recipe simmers the broth for three hours with dried mushrooms., This train is scheduled to leave for Edinburgh at 9:30 AM, ], category: [travel, food, travel], } ) # Temp write dataset lance.write_dataset(table, ./fts_test_with_metadata.lance, modeoverwrite) ds lance.dataset(./fts_test_with_metadata.lance) # Create FTS index ds.create_scalar_index( columntext, index_typeINVERTED, ) # Run FTS query with metadata filter query_result ds.to_table( full_text_querythree, filtercategory food, ) # Returns # id: [[2]] # text: [[This ramen recipe simmers the broth for three hours with dried mushrooms.]] # category: [[food]]这种「先过滤、后检索」或「先检索、后过滤」的组合策略可以大幅缩小搜索空间尤其适合需要快速淘汰大量无关文档的大型数据集详见「查询优化」小节。高级查询布尔、短语、N-gram 与模糊搜索当默认的「任一关键词命中」语义无法满足需求时可以借助lance.query模块中的结构化查询对象构建复杂查询。这些 Python 对象定义在python/python/lance/query.py底层经PyFullTextQuery桥接到 Rust 核心。布尔运算符AND、OR、NOTAND全部命中使用MatchQuery并指定operatorFullTextOperator.AND要求所有词同时出现from lance.query import FullTextOperator, MatchQuery # Require the terms umbrella AND train AND boston to be present and_query MatchQuery(umbrella train boston, text, operatorFullTextOperator.AND) query_result ds.to_table(full_text_queryand_query) # Returns # text: [[I left my umbrella on the evening train to Boston]]OR任一命中from lance.query import FullTextOperator, MatchQuery # Require the terms morning OR evening to be present or_query MatchQuery(morning evening, text, operatorFullTextOperator.OR) query_result ds.to_table(full_text_queryor_query) # Returns the Boston document that mentions evening, and the Edinburgh document that mentions morning # text: [[This train is scheduled to leave for Edinburgh at 9:30 in the morning, I left my umbrella on the evening train to Boston]]组合 AND/OR查询对象重载了与|运算符可以自然组合出嵌套语义from lance.query import FullTextOperator, MatchQuery # Combine AND and OR semantics # Require train AND (morning OR evening) q1 MatchQuery(morning evening, text, operatorFullTextOperator.OR) q2 MatchQuery(train, text) query_result ds.to_table(full_text_query(q1 q2)) # Returns both the Boston and Edinburgh documents that mention train # text: [[I left my umbrella on the evening train to Boston, This train is scheduled to leave for Edinburgh at 9:30 in the morning]]需要说明的是运算符语义在 Python 层由FullTextQuery.__and__/__or__实现等价于两个Occur.MUST子句的BooleanQuery|等价于两个Occur.SHOULD子句见python/python/lance/query.py#L64-L94。因此每个被AND组合的子句都是评分MUST子句——所有子句必须命中且每个命中子句的分数都会累加到最终的_score。NOT排除关键词NOT语义需要显式使用BooleanQuery与Occur枚举构造from lance.query import MatchQuery, BooleanQuery, Occur # Require that umbrella be present, but train NOT be present q BooleanQuery( [ (Occur.MUST, MatchQuery(umbrella, text)), (Occur.MUST_NOT, MatchQuery(train, text)), ] ) query_result ds.to_table(full_text_queryq) # Returns empty result, as no document matches this condition # text: []Occur提供三种语义SHOULD可选命中命中则加分、MUST必须命中且贡献分数、MUST_NOT仅用于排除文档不参与计分。短语搜索Phrase Search短语查询需要精确的词序与相邻位置信息因此必须在建索引时开启with_positionTrue默认关闭。注意短语中包含 to 这类默认停用词时还需要设置remove_stop_wordsFalse否则停用词被剔除后短语无法完整匹配# Rebuild the index with positions enabled (required for phrase queries) ds.create_scalar_index( text, INVERTED, with_positionTrue, remove_stop_wordsFalse, ) # Search for the exact phrase train to boston table ds.to_table(full_text_querytrain to boston) # If stopwords are removed, this phrase query would return an empty result # text: [[I left my umbrella on the evening train to Boston]]警告停用词默认被移除建索引时默认会移除 to、the 等常见停用词若需要检索包含停用词的精确短语请设置remove_stop_wordsFalse。如果想控制短语内词与词之间的间隔容忍度可以使用PhraseQuery的slop参数python/python/lance/query.py中定义为「短语允许的最大间隔位置数」默认0表示严格相邻。N-gram 索引子串匹配NGRAM标量索引专为子串/模式匹配设计是通配符式查询如term*/*termLance 的full_text_query不解析此类语法的良好替代方案。该索引为字符串中的每个 N-gram默认三连字 trigram建立位图可加速contains(...)过滤器import lance ds lance.dataset(/tmp/fts.lance) # Build an NGRAM index for substring search (speeds up contains(...) filters) # Give the index a distinct name so it wont replace your FTS index ds.create_scalar_index(columntext, index_typeNGRAM, nametext_ngram) # Substring search q1 ds.to_table(filtercontains(text, ramen)) # Returns the document about ramen # text: [[This ramen recipe simmers the broth for three hours with dried mushrooms.]]与 FTS 索引同名时新索引会替换旧索引因此这里为 N-gram 索引指定了独立名称text_ngram以保留两个索引。Rust 侧实现位于rust/lance/src/index/scalar/ngram.rs其段合并逻辑复用lance_index::scalar::ngram::NGramIndex。可以通过explain_plan检查查询计划确认 N-gram 索引是否真的被使用# Inspect the query plan to confirm index usage print(ds.scanner(filtercontains(text, train)).explain_plan())模糊搜索Fuzzy SearchFTS 的MatchQuery支持基于 Levenshtein 编辑距离的模糊匹配可容忍拼写错误与轻微词形变化from lance.query import MatchQuery # Explicit edit distance (1) query_result ds.to_table( full_text_queryMatchQuery( rammen, # Misspelled ramen text, fuzziness1, max_expansions50, # default: 50 ) )将fuzziness设为None可启用自动模糊度规则词长 2时编辑距离为0词长 5时编辑距离为1词长 5时编辑距离为2query_result ds.to_table( full_text_queryMatchQuery( rammen, text, fuzzinessNone, ) )prefix_length用于强制前缀精确匹配前N个字符必须完全一致模糊编辑只允许作用于其余部分。例如prefix_length2时rammen只能匹配以ra开头的词如ramenquery_result ds.to_table( full_text_queryMatchQuery( rammen, text, fuzziness1, prefix_length2, # ra must match exactly ) )max_expansions默认 50限制模糊匹配时考虑扩展的候选词数量是召回范围与查询开销之间的权衡点。索引维护与增量更新追加数据后的行为在创建INVERTED索引后继续insert新数据Lance 仍能正确返回这些新行的检索结果已索引分片走 FTS 索引未索引分片走扁平扫描flat search最后合并结果。这种「混合检索」保证了数据新鲜度但会带来延迟开销。增量索引更新optimize_indices为降低持续写入场景下的 FTS 延迟应定期将未索引分片并入现有索引# Append new data new_rows pa.table( { id: [4], text: [The next train leaves at noon], } ) ds.insert(new_rows) # Incrementally update existing indices (including text_idx) ds.optimize.optimize_indices(index_names[text_idx]) # Optional: monitor index coverage stats ds.stats.index_stats(text_idx) print(stats[num_unindexed_rows], stats[num_indexed_rows])说明若创建索引时使用了自定义name...请将上述text_idx替换为你的索引名未指定名称时text列上 FTS 索引的默认名即为text_idx。如果修改了分词相关配置如with_position、base_tokenizer、停用词、词干提取等增量合并无法回填历史数据必须用create_scalar_index(..., replaceTrue)重建索引让全量数据按新配置重新索引。性能调优建议索引配置层面需要短语查询时才开启with_position会显著增大索引体积纯词项检索关闭它可节省可观存储且不影响性能大多数应用保持lower_caseTrue以获得大小写不敏感的搜索体验若领域要求区分大小写再关闭需要更高召回率如 running 能匹配 run时开启stemTrue需要精确词项匹配时关闭内容密集型应用建议开启remove_stop_wordsTrue以降低噪声、提升相关性若停用词在领域内有实际语义如代码、术语表场景则应保留查询层面使用具体、聚焦的检索词通常比宽泛词性能更好将全文检索与元数据过滤组合使用可显著缩小搜索空间。底层原理索引存储布局与训练过程存储布局FTS 索引由多个文件组成详见docs/src/format/index/scalar/fts.mdtokens.lance—— token 词典将 token 映射到 token ID列_tokenUtf8、_token_idUInt32docs.lance—— 文档元数据含每篇文档的 token 数列_rowidUInt64、_num_tokensUInt32分片文件可带total_tokens元数据键以提供精确语料统计invert.lance—— 每个 token 的压缩 posting 列表delta 编码的行 ID 与频率含_max_score查询优化用、_length、可选的_compressed_position位置列表metadata.lance—— JSON 序列化的索引配置与分区信息partitions分区 ID 列表与params序列化参数一个 FTS 索引可能包含多个分区partition每个分区拥有独立的前缀文件如part_0_tokens.lancemetadata.lance记录全部分区 ID。查询时每个分区都必须被搜索并合并结果因此分区越少查询性能越好分区数量由训练配置特别是LANCE_FTS_TARGET_SIZE控制。训练构建流程构建 FTS 索引是多阶段流水线实现在 Rust 核心中先扫描源列并行分词中间结果溢写spill到磁盘 part 文件最后把 part 文件合并为最终输出分区。第一阶段中每个分词 worker 独立工作达到分区大小上限或文档数上限u32::MAX时把内存缓冲溢写为part_id_tokens.lance/part_id_invert.lance/part_id_docs.lance第二阶段以有界缓冲流式合并 part 文件统一 token 词典、拼接文档集、重写 posting 列表达到目标大小时写出一个新分区最后落盘metadata.lance。构建调优环境变量环境变量默认值说明LANCE_FTS_NUM_SHARDS计算密集型 CPU 核数并行分词 worker 数越大索引吞吐越高但内存占用越大LANCE_FTS_PARTITION_SIZE256 (MiB)worker 内存缓冲溢写为 part 文件前的最大未压缩大小LANCE_FTS_TARGET_SIZE4096 (MiB)合并输出分区的目标未压缩大小更少更大的分区有利于查询性能内存占用主要由NUM_SHARDS × PARTITION_SIZE决定构建期间需要临时磁盘空间存放 part 文件——开启with_position后位置信息可能使临时空间需求达到原列的 10 倍以上未开启时索引通常小于原列、总磁盘需求一般不超过原列的 2 倍。分布式训练FTS 索引支持分布式构建各 worker 通过片段掩码(fragment_id as u64) 32与分区 ID 按位或确保全局唯一 ID设置skip_merge: true跳过合并阶段直接写出 part 文件并各自写出part_id_metadata.lance全部完成后由协调节点统一合并元数据、将分区 ID 重映射为从 0 开始的连续序列并写出最终metadata.lance。这样分词阶段各节点完全独立只有轻量级的元数据合并需要单节点步骤。更多检索能力加速查询类型一览除 Python 快速入门覆盖的用法外Lance 的 FTS 索引还支撑以下查询类型详见索引规范文档查询类型说明示例contains_tokens基于 token 的 UDF 检索BM25 评分自动排序contains_tokens(column, search terms)match可配置 AND/OR 算子的匹配查询{match: {query: text, operator: and/or}}phrase精确短语匹配需with_position: true{phrase: {query: exact phrase}}booleanmust/should/must_not 子句组合的复杂布尔查询{boolean: {must: [...], should: [...]}}multi_match多字段同时检索、统一评分{multi_match: [{field1: query}, ...]}boost对指定词项/查询按因子加权{boost: {query: {...}, factor: 2.0}}这些能力在 Python 侧对应python/python/lance/query.py中的PhraseQuery、BoostQuery、MultiMatchQuery等类可结合本文的布尔/短语/模糊示例组合使用。进一步阅读深入了解不同分词器细节、索引训练过程的更深入技术说明含内存与磁盘占用预估可阅读全文检索索引规范掌握 Lance 数据集的读写与版本管理基础参考用户指南感兴趣的读者可以进一步阅读 Rust 核心实现倒排索引、N-gram 索引以及 Python 侧查询对象定义了解索引训练与查询执行的真实调用链【免费下载链接】lanceOpen Lakehouse Format for Multimodal AI. Convert from Parquet in 2 lines of code for 100x faster random access, vector index, and data versioning. Compatible with Pandas, DuckDB, Polars, Pyarrow, and PyTorch with more integrations coming..项目地址: https://gitcode.com/GitHub_Trending/la/lance创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号