关于 lance-format
lance-format 是面向 Lance 格式及其 Rust、Python、Java 实现的参考技能,供使用或维护 Lance 的开发者查阅。它按主题提供规范、性能指南和版本变更资料,并明确区分 Lance 与 LanceDB。
主要功能
- 01覆盖文件、表与索引规范
- 02提供 Rust、Python、Java 实现参考
- 03按主题组织深度文档
- 04跟踪 v7 至 v13 的版本变化
- 05提供性能与远程存储指南
适用场景
- 01查阅 Lance 数据集和文件格式细节
- 02核对索引类型与构建方式
- 03升级依赖时评估版本变更
- 04排查性能调优与远程存储问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tenequm/ skills --skill lance-format安装后在 Claude Code 中输入/lance-format确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdLICENSE.txtreferences/changelog-v7-v13.mdreferences/docs/format/index.mdreferences/docs/format/file/encoding.mdindex.mdversioning.mdreferences/docs/format/index/index.mdindices-compaction.drawio.svgindices-fragment handling.drawio.svgscalar_index.drawio.svgstarter-example.drawio.svgreferences/docs/format/index/scalar/bitmap.mdbloom_filter.mdbtree.mdfmindex.mdfts.mdlabel_list.mdngram.mdrtree.mdzonemap.mdreferences/docs/format/index/system/frag_reuse.mdmem_wal.mdreferences/docs/format/index/vector/index.mdreferences/docs/format/table/branch_tag.mddata_overlay_file.mdindex.mdlayout.mdmem_wal.mdrow_id_lineage.md详细介绍
Lance v13 参考
Lance 是一种面向多模态 AI 的开放列式格式——“一种随机访问速度比 Parquet 快 100 倍的列式数据格式”。它并非单一格式,而是一组相互协作的规范:文件格式、表格式、索引格式、目录规范以及命名空间客户端规范。lance-format/lance 中的 Rust 工作区实现了所有这些规范,并提供 Python(pylance)和 Java 绑定。
此技能跟踪 v13.0.0-beta.4(lance-format/lance git 标签),即当前的开发前沿版本;v12.0.0 是稳定版本,发布于 2026-09-17。请固定到标签,而不是 main——Lance 每隔几天就会发布 beta 标签,next 格式的编码可能会发生变化。下方列出了版本概况。
参考资料分为三层,根据任务需要加载:
-
深入参考——适用于任何具体的架构、参数、proto 或约束。按主题拆分:
references/中的文件涵盖内容 章节 format-file.mdLance 简介、26 个 crate、文件格式、数据类型 1-4 format-table.md数据集布局、清单、片段、架构演进、版本/标签/分支、行 ID、事务 + OCC、MemWAL 5-10 indexes.md向量 / 标量 / FTS / 地理索引、分布式构建 11-12 ops.md对象存储、能力矩阵、源代码映射 13、15、16 changelog-v7-v13.mdv7 -> v13 的完整变更 14 以“section N”形式编写的交叉引用通过
references/lance-reference.md解析。 -
references/performance.md- 所有性能指导。A 部分指向官方文本,并补充上游尚未记录的源代码分析变更;B 部分介绍经过实地验证的远程存储实践。对于任何有关性能、调优、维护成本或“为什么这么慢”的问题,都请加载此文件。 -
references/docs/- 官方文档的逐字镜像(所跟踪标签中的docs/src):包含所有指南、快速入门和格式规范,未经编辑。需要完整官方文本时请加载。下方列出了目录结构。
references/maintenance.md 介绍了如何将此技能更新到新的上游标签。
Lance 与 LanceDB
这是两个不同的东西,混为一谈会导致错误答案。
- Lance - 格式和引擎。
lance-format/lance仓库;lance/lance-*Rust crate;pylance。它提供数据集、文件/表格式、索引、提交和扫描。DuckDB、Polars、Ray、Spark、PyTorch、DataFusion 或你自己的 Rust/Python 代码都可以直接使用。此技能介绍的是 Lance。 - LanceDB - 基于 Lance 构建的独立数据库产品(
lancedb/lancedb)。它增加了查询构建器 API、嵌入注册表、以 API 形式提供的重排序器、多语言 SDK 一致性,以及托管 Cloud/Enterprise 层级。此处不涉及。
更广泛的生态系统(独立仓库,各自有版本线,均不在本文范围内):Flink 流式写入(lance-flink)、通过 pglance 进行 PostgreSQL 读取、Cypher 图引擎(lance-graph)、数据集浏览器(lance-data-viewer)、Agent 上下文管理(lance-context),以及 Hive、Polaris、Gravitino、Unity Catalog 和 AWS Glue 的命名空间目录。
规范文档网站是 lance.org。按语言生成的 SDK 文档位于 Python 的
lance-format.github.io/lance-python-doc,以及 Java 的
javadoc.io - 对应的 lance-format.github.io/lance-java-doc 路径会返回 404。
在 Cargo.toml 中链接 lance crate,意味着你直接使用 Lance - 请使用此技能。
对于 LanceDB 内部实现,其下方的存储层仍然是 Lance,因此此技能仍是了解该格式的权威资料。
封装层可能会隐藏格式功能。 LanceDB 的 create_table 无法启用稳定行 ID;
只有 pylance 的 write_dataset(enable_stable_row_ids=True) 可以。如果某项格式级功能会影响你的设计,请先检查封装层是否提供了该功能,不要直接假设底层格式可以解决问题 - 如果封装层没有提供,就直接使用 pylance。
crate 工作区
rust/ 下有 26 个 crate 目录。lance 是公共入口 - 包含 Dataset、扫描器、
索引、提交;其他所有内容(lance-table、lance-file、lance-encoding、lance-index、
lance-io、lance-core、lance-datafusion、lance-linalg、lance-namespace* 等)都是它下方的层。
Edition 2024,MSRV 1.91.0,arrow 58,datafusion 54;Python 绑定需要 3.10+。包含角色、版本和所有工作区依赖项的完整
表格见 references/format-file.md 第 2 节。
如果你依赖 lance 以下的任何内容,v11 会导致你的代码失效 - PR #8020-#8026 删除了
lance-encoding::version,且未重新导出(LanceFileVersion 和 ConcreteFileVersion 现在都位于 lance-file::version),移除了 lance_io::encodings 和 previous 命名空间,
并为每个当前格式版本提供了各自的 versions/v2_{0,1,2,3} 模块。见第 2.1 节。
事务代码也已迁移(#8053/#8054/#8056):rust/lance/src/dataset/transaction.rs 已
删除,由 rust/lance-table/src/transaction/ 模块树取代(builder、
conflicts、operation、proto、manifest_build、validate、index_maintenance、
row_version、update_map)。lance::dataset::transaction 垫片仍会重新导出
Operation、Transaction、TransactionBuilder、RewriteGroup、UpdateMap 等内容,因此常用接口不会中断 - 但如果某个符号未被垫片导出,或引用了旧路径,就需要调整目标。
文件格式版本
文件格式包含一个单独的主版本号和次版本号。创建数据集时会设置 data_storage_version——但从 v12.0.0 开始,数据集创建后不再固定该值。它是写入时未指定目标版本的默认值,并非数据集所含内容的概述:“创建和覆盖操作会设定此默认值;追加、更新、合并插入和压缩操作不会改变它。”
现有的 V2 数据集可以在每次操作中使用 "2.0"、"2.1"、"2.2" 或 "2.3",而无需重写其他文件(#8582-#8585),因此一个数据集可以包含多个确切 V2 版本的数据文件。**V1 和 V2 仍不能混用。**见第 3 节。
| 版本 | 状态 | 说明 |
|---|---|---|
0.1 (legacy) | 只读 | 原始格式;不再支持写入 |
2.0 | 稳定 | 移除了行组;支持列表、FSL 和原始类型中的 null 值 |
2.1 | 先前的默认版本 | 自适应结构编码;改进整数和字符串压缩;结构体字段支持 null 值;改进嵌套随机访问。从 Lance 5.0.0 到 v12.0.0-beta.15 一直是默认版本 |
2.2 | 当前默认版本(stable) | Map 类型、Blob v2、VariablePackedStruct、更大的迷你块。Map 和 Blob v2 必须使用此版本 |
2.3 | 不稳定(next) | 当前 next 别名指向的版本(枚举中的 V2_3)。提供稀疏结构页;现在,2.3 写入器会根据 rep/def 预算启发式自动选择该格式 |
现在,stable 指向 2.2,而非 2.1(#8657,beta.15),且 2.2 是枚举的 #[default],因此创建数据集时如果未显式指定 data_storage_version,写入的就是 2.2。此更改通过 DataStorageFormat::default() -> stable_file_version() 影响新数据集的创建;Python 的 write_dataset 默认值也通过 stable 继承此设置。文档尚未更新此更改——format/file/versioning.md 仍只将 stable 称为“默认版本的别名”,因此应以代码为准。next 指向 2.3。若要确保不同构建版本间的行为一致,请明确指定版本号。
2.3 是代码中唯一标记为不稳定的版本;2.2 从未被标记为不稳定,现在还是默认版本。发行版选择器(LanceFileVersion)与持久化标识(ConcreteFileVersion)是不同的类型。详情以及稀疏格式的自动选择规则,见 references/format-file.md 的第 3.1 和 3.6 节。
版本概览
主版本号由机器人而非人工递增:只要自发布根提交以来的任何 PR 带有 GitHub breaking-change 标签,ci/publish_beta.sh 就会从 MAJOR+1 重新设定根版本——标记是标签,而不是 conventional commit 中的 !。因此,主版本号递增表示“有某个带标签的重大变更已合入”,而不是重新设计;没有标签的 ! 不会触发版本号递增。如今,这种情况已连续发生在四个版本线上,这就是为什么从未发布过 v9.1.0、v10.1.0、v11.1.0 或 v12.1.0。12.1 版本线是最明显的例子:main 合入了一个 chore: bump main to 12.1.0-beta.0 提交,四个提交之后,机器人就重新将根版本设为 13,因此 release-root/12.1.0-beta.N 和 release-root/13.0.0-beta.N 使用的是同一个基础提交
(c3c9632a2),并且不存在 v12.1.0-beta.* 标签。
最近有三个版本线确实发布了正式版:v10.0.0(2026-08-08)、v11.0.0(2026-08-30)和
v12.0.0(2026-09-17)。每个版本都基于一个不是 main 祖先提交的稳定分支——这对 Lance 正式版来说很正常,并不意味着该版本不是官方发布。
| 主版本 | 重大变更主题 |
|---|---|
v13(当前,v13.0.0-beta.4) | WriteParams 新增了 file_writer_options(#9192——这是触发主版本号重新设定的那个带标签 PR);延迟初始化页面元数据改变了 StructuralFieldScheduler 签名和元数据缓存键结构(#7465);json_extract/json_get 不再路由到 JSON 索引(#9101)。下文详述 |
v12(v12.0.0,2026-09-17) | WrappingObjectStore 的实现者必须添加 wrap_paginated(没有默认实现);MemWAL 的 ShardManifestStore 已重命名并缩小范围;lance-namespace 返回响应对象;外部存储新增了基于前序条件的发布;命名空间 merge-insert 键改为列表;移除了调用方提供的 Writer / open_part 流程(#9072)。更大但未加标签的变更:stable -> 2.2,以及 IVF_RQ 的 5-bit 默认值。新增格式能力:混合数据文件版本。下文详述 |
v11(v11.0.0,2026-08-30) | Fragment ID 改为数据集生命周期内的高水位标记;对 lance-file / lance-encoding 进行了大规模内部重组;自 v7 以来的首个新 manifest 功能标志——但该标志随后在正式版发布前重新分配。新增功能:覆盖索引、merge_insert write_mode、行地址预筛选。下文详述 |
| v10 | Blob API 保留空值选择;缓存键改为不透明的 BLAKE3 摘要(所有预热缓存或持久化缓存都会发生冷未命中,没有旧版回退);异步 create_remapper;MemWAL 将 generation 重命名为 SSTable、将 merge 重命名为 compaction(线格式兼容,符号有破坏性变更) |
| v9.1(从未发布;更名并入 v10) | FTS/倒排索引创建新增了 block_size 参数。新增功能:数据覆盖文件(无需重写基础文件即可进行单元格级更新,不稳定且由环境变量控制)、稀疏结构页、lance-index-core |
| v9 | 移除对 Python 3.9 的支持;当对索引列进行类型转换时,alter_columns 会快速失败;FM-Index proto 重命名导致现有 FM 索引无法读取;FTS/倒排索引默认使用磁盘格式 v2 |
| v8 | 所有索引构建统一采用基于段的生命周期。新增功能:lance-derive、FM-Index、多位 IVF_RQ、公开的 approx_mode、TOS + GooseFS 对象存储 |
| v7 | MemWAL、分支、geo/RTree 索引、lance-select crate、ICU FTS |
v12.0.0 是稳定版本固定目标,也是 GitHub Releases 标记为 Latest 的版本。crates.io 仅提供正式版(最新为 lance 12.0.0,没有 13.x);PyPI 上的 pylance 也停留在 12.0.0。因此,固定到 beta 版本意味着使用 git 依赖——beta wheel 则发布到 fury.io,归属于更名后的组织(https://pypi.fury.io/lance-format),目前其中提供 pylance-13.0.0b1 至 b4。
每个标签对应的完整差异及所有 PR 引用:references/changelog-v7-v13.md。
v11 的差异
从 v10.0.0-beta.7 到最终版 v11.0.0 共 357 次提交,其中 16 个 PR 带有 breaking-change 标签(14 个在 beta.16 之前,另外 #8407 和 #8535 在最终版中)。大多数结构性不变量保持不变:26 个 crate、16 个事务操作、CommitConfig.num_retries 20、arrow 58 / datafusion 54、MSRV 1.91.0、Edition 2024、Python 3.10+——到 v13.0.0-beta.4 时,这些仍然全部成立。
references/changelog-v7-v13.md 包含完整变更——每个 PR 的引用、从 v7 开始的各标签版本变更明细、Python/Java 接口,以及每项正确性修复的触发条件。遇到任何“改了什么 / 会不会影响我”的问题,都应加载此文件。下面只列出影响最大的内容。
v11 中会造成影响的五件事:
- 片段 ID 是数据集生命周期内的高水位标记(#8206)——这是一个 格式 不变量,不只是 API。覆盖写入不再将 ID 重置为 0,携带删除文件的覆盖写入片段会被拒绝,任何会产生重复 ID 的提交也会被拒绝——因此,Lance 0.16 及更早版本写入的数据集可能仍可读取,但不能再提交。覆盖写入后,
dataset.get_fragment(0)必须从清单读取 ID。见第 5 节——该节还介绍了一个解析风险:对于 0.10 之前未排序的清单,按片段筛选的索引可能覆盖错误的片段。 - 文件版本类型以及读写器的组合方式已变更(#8020-#8026)——
lance-encoding::version已删除且没有重新导出;LanceFileVersion不再实现PartialOrd/Ord(#8027、#8028),因此v >= LanceFileVersion::Next将无法编译。FileWriter现在是一个 enum,所有构造函数均已移除。这些变更大多会在编译时直接报错。见第 3.6 节。 - 事务代码已移至
lance-table(#8053/#8054/#8056)——请参阅上文的 crate 工作区说明;lance::dataset::transactionshim 涵盖了常见接口。 Operation::Project/Merge新增了preserves_nullability(#8347)——收紧可空性时不得设置此字段,且此类投影现在会与任何并发值写入发生冲突。此变更修复了一个实际漏洞:alter_columns可能导致并发写入写入 null 值,而这些值在收紧后的 schema 下无法读取。见第 9.2 节。- 外部清单协议已变更(#8499)——对象存储是权威来源,外部存储的 put-if-not-exists 操作是一种 预留,必须忽略已存储的 ETag;如果保留该 ETag,读取器会因
Manifest e_tag mismatch拒绝有效清单。见第 9 节。
清单特性标志已变更——且 bit 128 在最终版发布前重新分配。 v11 新增了自 v7 以来的第一个新 bit,并将 FLAG_UNKNOWN 从 128 移至 256。但新增的 bit FLAG_MEM_WAL_INDEX_CATCHUP 后来又被弃用(#8680),回收的 bit 在 v11.0.0 发布前分配给了 FLAG_COVERED_INDEX_METADATA = 128(#8535)。在最终版和 v12 中,既没有 index-catchup 标志,也没有 require_index_catchup proto 字段;index_catchup 中缺少某个分片现在一律表示 未知。读取器和写入器都必须支持 bit 128,否则就应拒绝该表。见第 7 节。
请勿使用 v11.0.0-beta.4 到 beta.17 之间的任何版本。 这些版本将 bit 128 视为受支持的 MemWAL 标志,因此会打开覆盖索引数据集,而不是拒绝它——会选中错误的相邻项,且不会报错。无论后来哪个标志被分配到该 bit,都会继承这一风险。
覆盖索引是 v11 新增的格式特性(#8535),并在 v13 重新定义(#8856)。
IndexMetadata.covering_fields(proto 字段 11)列出索引携带值的列,因此只投影这些列的查询无需访问基表即可得到结果。它不再是 fields 的尾部后缀:它“必须是 fields 的子集,且顺序与索引输出顺序一致。仅当列在此处列出时,该列才会被携带”,包括索引也以其为键的列;而 fields[0] 仍然是键列。索引失效范围仍然很广:任何 fields 包含已更新列的索引都会失效,“无论该列是索引键还是仅被携带”。
旧说法“目前还没有索引构建器会写入被携带的值”已不再成立。V3 IVF 辅助文件可以在物理上携带列,而“读取器通过排除法而非位置来发现被携带的列:辅助文件架构中任何不属于量化器内部列的列,都是被携带的列”,并通过新的 covering_field_ids 元数据键与源字段绑定。覆盖现在是按段而非按索引计算的:“一个逻辑索引可以在部分段中保存值,而在其他段中不保存”。VectorQueryProto.covering_projection(字段 15)预留了查询侧标签,其中不存在、存在但为空、存在且非空,分别表示三种不同含义。第 11 节。
在 v12.0.0 正式版中,位 8 已被占用。 FLAG_MIXED_DATA_FILE_VERSIONS = 1 << 8(256)不再是固定等于 FLAG_UNKNOWN 的保留值:断言放宽为 FLAG_MIXED_DATA_FILE_VERSIONS < FLAG_UNKNOWN,FLAG_UNKNOWN 从 1 << 8(256)移至 1 << 9(512),并且该版本现在既能读取也能写入混合版本数据集。它仍由 STICKY_PAIRED_FLAGS 携带,而只设置一半的标志现在会导致硬错误:“清单只设置了混合数据文件版本读取器和写入器功能位中的一个,因此其语义未定义”。第 7 节。
位 1024 是文档与代码不一致之处——以代码为准。
FLAG_FRAGMENT_REUSE_INDEX = 1 << 10 在 rust/lance-table/src/feature_flags.rs:69 中声明;在 v13.0.0-beta.4 中,这是它在整个代码树中的唯一出现位置。它位于 FLAG_UNKNOWN(512)之上,而支持的标志集合按 FLAG_UNKNOWN - 1 计算,因此设置该标志的清单会被拒绝。与此同时,规范页面将其列为读取器 Yes / 写入器 Yes,并将未知边界设为 2048。文档描述的是预期的最终状态;代码目前只预留了这个常量。如今,任何针对带标签 FRI 构建的内容,依据的都是文档,而非实际行为。
新增了两个 LANCE_* 环境变量(来自 AMX 工作,#8540):LANCE_DISABLE_AMX(运行时终止开关)和 LANCE_AMX_FP16_CC(构建时编译器覆盖项)。注意 grep 陷阱:LANCE_AMX_CFG_* 和 LANCE_AMX_TILE_COUNT 是 amx_fp16.c 中的 C 宏,而非环境变量;LANCE_FACTOR 则是 BALANCE_FACTOR 的子串——直接 grep LANCE_* 会把这四项都报告为真实环境变量。
不看完整差异也值得了解: FTS 新增了文档边界维度(DocumentGranularity,#7788),其 list_element 模式是第三种触发方式,并要求 FTS 磁盘格式 v3;超过 20 MiB 的事务会完全溢出清单(#7881);MemWAL 追赶行为改为派生而非声明(#8481);事务 proto 字段 9 弃用,改用字段 10(#7432);压缩新增行数/字节数预算以及片段排除功能(#8235,#8532);merge_insert 新增 write_mode(#8423);Python 提交冲突现在是 lance.commit.CommitConflictError,它是 OSError 的子类,因此现有处理程序仍可正常工作(#8563)。完整列表及引用见 references/changelog-v7-v13.md。
地址域索引不再错误地声称包含已压缩的片段(v11,beta.16 或更早版本)。过去,重写会将每个索引的 fragment_bitmap 更新为新的片段 ID,包括 ZoneMap;但 ZoneMap 存储的地址指向重写时被丢弃的片段。现在,Rewrite 路径会根据 results_are_row_addrs() 分支处理:地址域索引会执行 drop_rewritten_fragments 并回退到全扫描,虽然速度较慢,但结果正确,不再使用过时的地址。仅对新的压缩操作有效:在 v10 或更早版本中已损坏的索引必须重新创建,且常规维护无法自动修复,因为更新后的 fragment_bitmap 也会导致增量折叠不执行任何操作。第 11 节。
正确性修复分为升级即可生效和需要额外处理两类。 大多数修复只涉及读取路径,升级后即可生效。以下修复则不能仅靠升级生效——必须重写或修复数据:#8382、#8669、#8509、#7703、#8539、#8459、#8378、#8482、#8834(重建 HNSW——持久化图可能包含指向其不包含的 ID 的边;已丢失的召回率无法恢复)、#8101(在每次重复执行 merge_insert 时,可空主键会导致行被静默重复插入;必须手动删除现有重复行)、#8511、#8427、#8513、#8839、#8904。各项修复的适用条件见 references/changelog-v7-v13.md。
v12 的变化
从 release-root/12.0.0-beta.N 到最终版 v12.0.0 共 225 次提交,其中有 7 个带 breaking-change 标签的 PR——beta.15 中可见的 5 个,以及发布最终版前的 #9072 和 #9101。没有新增索引类型或 crate;上述每项结构性不变量仍然成立。标签只是下限,不是上限——该版本系列中最大的两项行为变更带有 conventional commit 的 !,却没有标签,因此机器人从未将它们计入:stable -> 2.2 的迁移(#8657,见上文)以及 IVF_RQ 的 5 位默认值(见下文)。
WrappingObjectStore实现者必须添加wrap_paginated(#8606)——“这里刻意不提供默认实现:如果处理错误,要么会悄无声息地损失速度,要么会悄无声息地丢失包装器,这两种情况都不会自行显现。”返回Some,以保留穿过包装器的列表下推;返回None,放弃下推并回退到inner。链中的任意一个包装器放弃下推,整个链都会放弃。任何包装对象存储的代码在更新之前都无法通过编译。- 新增分页列表接口:
ObjectStore::read_dir_page(#8606)——获取某个前缀的直接子项中的一页,以及一个不透明的续传令牌。注意:“一页对应一次请求,因此一页包含的子项可以少于请求的limit,但后面仍可能有更多子项。”应遍历至令牌为None,绝不能因为某一页返回的子项较少就停止。 - MemWAL
ShardManifestStore更名并收窄可见性 (#8640)——read_latest->latest,read_latest_uncached->refresh_latest,且write现在是 crate 私有的(通过commit_update、claim_epoch或initialize_shard调用)。现有的commit_update闭包无需修改。第 10 节。 lance-namespace从 0.8.5 升至 0.11.1 (#8903)——四个LanceNamespace方法现在返回响应对象,而非直接返回值:count_table_rows->CountTableRowsResponse,query_table->QueryTableResponse,namespace_exists/table_exists-> 各自的响应类型。调用方需要解包;任何实现该 trait 的代码也需要更新相应签名。- 外部清单存储新增了以前置条件约束的发布功能 (#8800)——只有当前置项仍具有写入者观测到的标识时,
put_if_predecessor才会保留一个版本;commit_after则会以PrerequisiteFailed拒绝,“绝不会发生冲突”。真正导致编译失败的是新增的ManifestLocation.identity字段,而不是 trait 方法(这些方法都提供了默认实现)。没有内置存储实现该功能。第 9 节。 - 命名空间合并插入键改为列表 (#8915)——
on从Option<String>改为Option<Vec<String>>,并采用依赖键数量的 NULL 语义:单列键将 NULL 视为等于 NULL;复合键采用 SQL 相等语义,“按此规则,NULL 键不匹配任何内容——甚至不匹配字节完全相同的 NULL”。
lance-namespace 的版本锁定不再只有一个数字。 #8915 将 Rust 客户端升级至 0.12.0,#8979 也将 Java 升级至 0.12.0;只有 Python 仍锁定在 >=0.11.1,<0.12,因为其生成的模型仍将 on 作为普通字符串发送。应按语言分别注明版本锁定,绝不能用一个数字涵盖三种语言——还要注意,这种版本划分此前已经变更过一次,因此应重新核实,而不是沿用旧的对应关系。
IVF_RQ 现在默认每维使用 5 位,而非 1 位 (#8936)——默认情况下,索引大小大约增加 4.4 倍(上游以 100M x 768d 为例:约 10.8 GiB -> 约 47.3 GiB)。Fast 搜索模式“即使索引存储了额外的位,也只使用 1 位符号码”,因此会增加存储开销,却不使用这些额外数据;可显式设置 num_bits=1 以退出此默认设置,但会失去多位距离估算,并导致部分召回率损失。大小估算公式见 references/indexes.md。
列切片拼接(#8660)已在 beta.9 中回退 (#8926)——“在开发 #8923 中由调用方管理的替代方案期间,不应发布此功能。”rust/lance-file/src/concat.rs 在 beta.15 中再次出现,但其中包含的是 #8923 的调用方管理数据文件部分,而非已回退的拼接实现。
新增两项 proto 定义。 MemWAL SsTable 新增了 in_memory_bytes、physical_rows 和 primary_key_bytes(字段 3-5,#8981);这些字段均为可选,且不得将缺失解释为零。FilteredReadOptions 新增了 materialization_readahead_bytes 和 batch_size_bytes(13、14)——根据 protos/AGENTS.md 中新增的规则,这不属于格式变更:执行计划架构“属于线缆协议契约,而非持久化的 Lance 格式”。transaction.proto / ann.proto / index.proto 均未改动。
全新且不破坏兼容性: 原生提供程序批量复制和深度克隆并发上限(第 13 节);注册 Python ObjectStoreProvider(#8522);打包 blob 写入器中的 BinaryView(#8700);由调用方管理的数据文件分片(#8923);清理特定版本(#8617);LanceDataset.slice()(#8059)以及另外 6 个 LanceFragment.scanner 选项(#8429);恢复 Python 索引重新训练(#8788);命名空间管理的克隆已弃用并改为垫片(#8964)。命名空间解析最新版本时不再列出整个 _versions/ 前缀(#8679)——在一张约有 34 万个版本的表上,这大约需要 344 个列表页,产生“约 25 秒纯 I/O 等待”,且每次打开都要承担这笔开销。
需要重建或重写才能修复,而非仅升级: #8779(重建 NGRAM 索引)、#8510(重写由均匀重排的分片压缩而成的数据)、#8984(重新删除复活的索引)、#8837(修复每行低于约 2.7KB 的 MemWAL 分片——此类分片无法重新打开)。每个 PR 的完整适用条件,以及升级即可修复的长得多的列表,见 references/changelog-v7-v13.md。
混合数据文件版本已落地——不再是“6 项中的 1 项”。#8581-#8584 已在 v12.0.0 中发布(验证、按操作指定 V2 写入目标、在数据集操作间传播、压缩目标设置),#8585 则在 v13 系列中通过绑定接口开放了此功能。proto 也随之变更:DataStorageFormat.version 现在是“写入数据文件时使用的默认格式版本”;设置此能力后,“每个 DataFile 的版本是解码时的权威依据”。
正在进行,尚未落地——请勿视为已发布: 通用 block v5 压缩合并的 PR 仍只有 10 项中的 1 项(#8324;#8325-#8333 均仍处于开放状态)。队列中下一个重大的依赖项变更是 #8997,“升级到 arrow 59、DataFusion 55 和 pyo3 0.29”——在 v13.0.0-beta.4 时仍处于开放状态,因此仍使用 arrow 58 / datafusion 54。它还阻塞着两项尚未解决的 PyO3 安全公告(RUSTSEC-2026-0176/0177);rustls 已另行修补至 0.23.45,以解决 RUSTSEC-2026-0285(#9212)。
v13 的变更
从 release-root/13.0.0-beta.N 到 v13.0.0-beta.4,共有 66 次提交,其中 2 个 PR 标记为 breaking-change。没有新增 crate,也没有新增索引类型;26 个 crate、16 个事务操作、CommitConfig.num_retries 20、arrow 58 / datafusion 54、MSRV 1.91.0、Edition 2024 和 Python 3.10+ 均保持不变。
在此时间段内,! 与标签的规则反转了。 3 次 conventional-commit ! 提交(#7465、#9192、#9101)都带有 breaking-change 标签。仍应将该标签视为最低标准,而非上限——但此时间段是反例,并非标签与 ! 不一致的更多证据。
WriteParams新增了file_writer_options(#9192)——这是为本次主版本升级重新定根的唯一标注 PR。FileWriterOptions { data_cache_bytes, max_page_bytes, keep_original_array }现可通过 Rust、Python 和 Java 中的数据集写入 API 使用。若max_page_bytes为 0,会在构造编码器前直接拒绝,而不是等到后续才出现异常行为。任何通过结构体字面量构造WriteParams的代码都会编译失败。- 页元数据改为延迟初始化,元数据缓存键的形态也发生了变化(#7465)。
StructuralFieldScheduler::initialize现在接收requested_ranges,页调度器的initialize拆分为init_ranges()和init_from_buffers(buffers, io)——任何外部实现者都会编译失败。公开的DecodeBatchScheduler::try_new保持原有签名;支持范围的入口是 crate 私有的try_new_with_ranges。不会触发编译错误、但影响很大的变化是:缓存键从按列的FieldDataCacheKey改为按页的PageDataCacheKey { column_index, page_index, view_tag },因此升级后,所有热缓存或持久化元数据缓存都会发生冷未命中。这带来的收益确实可观——“冷点查找/范围读取的元数据 I/O 不再受列总页数影响”。 json_extract和json_get不再走 JSON 索引(#9101)。只有四个有类型的访问器(json_get_int/_float/_bool/_string)会使用索引;其他操作都会退回全表扫描。这修复了三个实际的错误结果问题——带引号的键不匹配,导致“搜索带引号的键却没有匹配结果”;Utf8字面量驱动Int64btree 导致 panic;以及范围不可靠,因为“加引号不保序(ab<ab!,但"ab">"ab!")”。代价不会显式提示:以前会命中索引的json_extract工作负载现在会改为扫描,不会报错,也不会在执行计划中发出警告。请将这些谓词改写为使用有类型的访问器。
Fragment Reuse Index 新增了带版本的磁盘契约(#9136)。InlineContent 的字段 1 从 versions 重命名为 legacy_versions,并在字段 2 新增带标签的 transitions 列表,由 index_version >= 1 控制;映射现在是 OrderedCompaction 或 StablePartition 的单选项。稳定分区“会将源行分配到目标片段,同时保留每个目标片段中源行的相对顺序”,因此 FRI 可在重新聚类后复用现有索引——这是 v0 模型中未涉及的第二种用例。其物理形式是不可变的行映射 Lance 文件,包含 uint16 标签和带 LSPC 魔数的计数矩阵。两条硬性规则:稳定行 ID 与带标签的 FRI 互斥(“写入方不得在此类索引上发布 index_version >= 1”);清理时“必须保留仍用于转换旧地址的中间转换记录”。上游还弱化了旧说法——“FRI 不会消除重叠重写之间的冲突”。第 11 节。
新增且不破坏兼容性:Dataset::frag_reuse_index() 现已公开(#9112),并在性能指南中提供文档;FileFragment::write_overlay 返回真正的 OverlayWriter(#8761,仍受环境变量控制);支持带有 hf_enable_resolve_cache 的 hf:// 对象存储(#9236);Python 新增 lance.bitmap.Bitmap、deep_clone()(#9181)、base_paths()(#9191)和 update_columns(with_offsets=True)(#8891);Java 新增 DataStorageVersion、FileWriteOptions 和 ScanOptions.indexSegments;命名空间表列表查询终于通过 read_dir_page 实现了分页限制(#9165)。inline_optimization_enabled 从 true 改为 false(#9180),上游给出的理由是在 100 万条目时写入 p50 降低了 49%。
性能问题
对于任何与性能相关的问题——扫描或搜索缓慢、远程/对象存储成本、索引维护成本、内存配置、版本膨胀、基准测试——请先加载 references/performance.md。A 部分会指引至官方指南以及从源码中发现但未记录的变更;B 部分则介绍经过实地验证、适用于 S3 兼容存储的实践。核心原则仍是 尽量减少远程调用——减少提交、扫描和往返次数——因为这能带来数量级的提升。官方的 “Tuning remote scans” 部分(v11 中提供,v12 中未变)为跨区域或公共互联网访问提供了起点;在这种情况下,云端默认的 64 个并发请求过于激进:LANCE_IO_THREADS=8、fragment_readahead=1、batch_readahead=2、io_buffer_size=64MB。在远程调用量已降至最低后,这是一项合理的后续优化。
AMX-FP16(#8540,beta.16)是 v11 中唯一会改变结果、而不仅仅是速度的性能变更:在适用的情况下,IVF 分区分配会变为精确而非近似,因此召回率会提升,分配结果也会与旧版本不同。它受形状条件限制(float16 + dot、dimension >= 32、num_centroids >= 32);其他情况仍使用先前的路径。LANCE_DISABLE_AMX=1 可禁用此功能,但也会使分配回退到近似路径——因此,使用该选项构建的索引与未使用该选项构建的索引并不等效。
在优化任何远程访问之前,有两项缓存相关事实需要了解:Lance 没有常驻数据缓存(Session 仅保存索引和元数据缓存,从不保存已解码的值,因此重复的点读取会再次产生对象存储 I/O);通过 DatasetBuilder::with_session 共享一个 Arc<Session>,可让多个数据集共用该会话。首次冷启动搜索的主要耗时来自分页载入索引——解决方法是 prewarm_index。请注意,#7465 会改变元数据缓存键的形式,因此升级到 v13 后首次运行时,即使缓存已预热或持久化,仍需再次支付这部分分页成本。详情和构建时要求见 references/performance.md。
时间旅行不是归档机制。 版本看起来像是免费的历史记录,但默认清理会回收超过 7 天的数据,而清理也是常规优化的一部分——因此,如果设计中将旧版本视为持久记录,那么第一次维护时这些记录就会丢失。如有归档需求,请单独保留明确的归档。
官方文档镜像
references/docs/ 原样镜像了 lance-format/lance 在所跟踪标签下的 docs/src——
共 45 个 Markdown 文件和 4 张图表,均可直接阅读。
| 目录 | 文件数 | 涵盖内容 |
|---|---|---|
guide/ | 14 | CRUD、性能、对象存储、分布式写入与索引、JSON、分词器、数据类型、数据演进、blob、数组、标签/分支、迁移、可观测性 |
quickstart/ | 4 | 第一个数据集、向量搜索、全文搜索、版本控制 |
format/ | 1 | 规范栈概览 |
format/file/ | 3 | 容器规范、结构编码与压缩、格式版本 |
format/table/ | 9 | 布局、架构、事务(冲突解决矩阵)、版本控制、行 ID 溯源、分支/标签、MemWAL、数据覆盖文件 |
format/index/ | 1 + 4 svg | 索引生命周期、片段覆盖范围、压缩交互 |
format/index/scalar/ | 9 | fts、fmindex、ngram、btree、bitmap、bloom_filter、label_list(array_has_any/all)、zonemap、rtree |
format/index/vector/ | 1 | IVF / PQ / SQ / RQ / HNSW 概念与存储布局 |
format/index/system/ | 2 | 片段复用索引、MemWAL 系统索引 |
integrations/ | 1 | 基于 Lance 的 DataFusion SQL,包括 JSON 函数 |
未镜像的内容:docs/src/images/(PNG/GIF 资源),因此镜像页面中的图片链接无法解析——正文内容完整自足,且四张 .drawio.svg 图表已镜像。
此外,以下内容按设计未纳入:community/、examples/、integrations/{index,pytorch,tensorflow}.md;以及着陆页占位文件和贡献者文件(format/AGENTS.md、format/CLAUDE.md)。
有一整层文档完全不在此仓库中,因此无法镜像,也无法通过克隆仓库列出。docs/make-full-website.sh 会在构建时从六个各自有版本线的同级仓库组装 format/catalog、format/namespace 以及 integrations/{duckdb,huggingface,spark,ray,trino,context} 章节——已检入的 integrations/index.md 将 spark/、duckdb 和 trino 链接为本地内容,但这些路径在目录树中并不存在。Lance Context 和 HuggingFace 集成文档是仅存在于构建后网站中的完整导航章节。对于其中任何内容,请阅读 lance.org,而不是此镜像。Protobuf 消息正文也会在构建时由 mkdocs_protobuf 从 protos/ 展开,因此镜像中的规范页面会显示 %%% proto.message.X %%% 占位符,而网站上显示的是渲染后的架构。