
Lance 湖仓格式规范全景解析文件、表、索引、Catalog 与命名空间的分层设计【免费下载链接】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 并不是单一的文件格式而是一组可互操作的规范堆栈——文件格式、表格式、索引格式、Catalog 规范与命名空间客户端接口各司其职、彼此解耦。本文以格式规范入口文档为主线逐层拆解每个规范的设计目标、关键结构与读写流程并结合当前仓库中的 proto 定义、Rust/Python/Java 实现与兼容性测试数据给出可验证的代码证据。读完你将掌握 Lance 湖仓格式的完整分层模型理解无行组文件 片段化表 一等公民索引 可插拔 Catalog这套设计如何支撑随机访问、schema 演化与 ACID 提交并能据此快速定位仓库中对应的规范文档与实现源码。Lance 是什么一组互操作规范的堆栈Lance 湖仓格式lakehouse format的核心定义方式是将自身表述为一组可以相互操作、独立演进的规范而不是单一的磁盘文件格式或固定的元数据布局。面向存储的各层分别负责文件、表、索引和 Catalog在这些存储层之上还有一层统一的命名空间接口namespace interface为查询引擎提供跨 Catalog 实现访问 Lance 表的一致方式。之所以刻意保持各层解耦是为了让文件格式、表元数据、索引和 Catalog 能够独立演进避免牵一发而动全身的锁定效应。这一设计的直接结果是一个很关键的分工原则只有表读取器table readers、表写入器table writers以及索引读取器/写入器才需要理解 Lance 磁盘文件的真实布局上层应用与引擎无需关心底层字节级细节。从当前仓库的结构看这一规范堆栈有完整的落点protos/目录集中存放各层规范对应的 protobuf 消息定义rust/lance/、python/lance/、java/lance-jni/则分别承载 Rust、Python 与 Java 生态的读写实现docs/src/format/下按 file / table / index 子目录组织了各层规范的详细文档。架构总览湖仓堆栈的五层结构现代湖仓由互补的多层结构组成。Lance 保持这些层有意解耦使各层可以独立演进而不互相强制锁定。从上到下各层的职责可以概括为层职责关键能力文件格式以面向随机访问优化的大页page存储列数据不采用行组row group列内页数相互独立表格式管理片段fragment、清单manifest、删除文件、schema 演化与 ACID 提交版本化快照、MVCC、时间旅行索引格式定义冗余的检索结构标量索引、向量索引、全文检索、系统索引Catalog 规范定义表如何被发现、注册并在引擎与服务间协调目录型 Catalog 与 REST Catalog 两种形态命名空间客户端规范为引擎提供统一的 Catalog 访问接口语言无关可切换任意 Catalog 实现其中只有文件层之上需要理解磁盘布局的那几类读写器表读写器、索引读写器依赖底层文件格式细节其余组件通过规范接口协作。设计主题逐层拆解文件格式层为云对象存储与高选择性读取而生的列式容器Lance 文件格式的完整规范位于 docs/src/format/file/index.md其核心设计目标是面向云对象存储、随机访问和 Arrow 原生处理的列式容器刻意把表语义与检索结构留给上层。无行组No Row GroupsLance 不使用 Parquet 风格的行组。每个列可以拥有各自数量的页列数据按存储友好的大块组织扫描器的分区不再与物理文件布局耦合。规范文档给出了明确的取舍理由行组太小会产生runt pages矮页在云存储上读取性能差行组太大则写入器需要把整组数据缓冲在内存中导致写文件时内存占用过高。取而代之的是支持部分页读取partial page reads让文件可以在任意行边界拆分给多个 reader 而几乎不产生读放大。随机访问友好的编码页被设计成可以用少量、可预测次数的 I/O 读取连续行区间。这对选择性过滤、点查询、向量检索后的回表读取以及非顺序采样的 ML 训练负载都至关重要。规范建议磁盘页默认大小8MB——足够大以摊薄一次云存储 I/O又不会因为超大连续读在云端被拆碎而失去优势。功能分解Functional Decomposition文件层不把表级统计信息或查询侧索引捆绑进基础文件结构这些能力被定义为独立的索引格式可随核心文件容器独立演进。文件结构要点详见 file/index.md磁盘页Disk Pages每个磁盘页包含单个列的若干行每列可以有一个或多个页文件末尾的元数据描述各页位置与编码方式。页不透明但支持按行子集部分读取。缓冲对齐Buffer Alignment缓冲通过绝对偏移引用不要求连续实践中统一按64 字节边界对齐以配合 SIMD 操作需要 direct I/O 时还可能按 4096 字节对齐。外部缓冲区External Buffers既然每页都由绝对偏移引用非页数据可以插入页之间——超大值类型可以行外存储out-of-line页内只保存位置。此外格式支持全局缓冲区存放辅助数据文件 schema、文件级索引、列统计等其引用存放在 footer 的特殊位置。列描述符Column Descriptors文件尾部元数据由每列独立的 protobuf 消息组成只看部分列时无需读取全部文件元数据。偏移表与 Footer列描述符之后是列描述符偏移数组和全局缓冲偏移数组最后是固定大小的 footer描述偏移数组位置与元数据区起点。footer 以LANC魔数收尾所有字段为小端无符号整数。标识符与类型系统容器格式本身没有类型概念列由整数列索引引用、全局缓冲由整数全局缓冲索引引用schema 通常存放在全局缓冲区中但文件格式本身对此一无所知。读取策略先读文件末尾一个扇区本地盘 4KiB云端更大解析 footer再读剩余元数据通常只需1~2 次 IOPS若把元数据大小存在表清单manifest等外部位置则可恒定单次 IOP 读完 footer。随后按页扫描确定所需页每页记录首行偏移再依据页的编码信息精确计算需要读取的字节范围。文件完整布局的 protobuf 风格示意Data Pages → Column Metadatas → Column Metadata Offset Table → Global Buffers Offset Table → Footer以及 ColumnMetadata 消息定义均可在 file/index.md 中查看磁盘页内数据的默认编码方案则见 file/encoding.md。表格式层片段化、版本化与数据演化Lance 表格式规范位于 docs/src/format/table/index.md将数据集组织为片段fragments、数据文件data files、删除文件deletion files与索引的版本化集合每个版本由一个不可变 manifest 描述该快照的物理数据。它面向机器学习和高选择性负载设计列追加、索引维护与局部重写必须廉价同时支持 ACID 事务、schema 演化、时间旅行time travel以及基于 MVCC 的高效增量更新。二维存储Two-Dimensional Storage行被划分进片段每个片段可包含多个数据文件每个数据文件贡献一列或多列。这样写入者通过向已有片段追加新数据文件来实现加列或回填backfill无需重写整张表——对特征工程和 embedding 更新场景尤为关键。规范明确每个数据文件应包含一组互不重叠的字段 IDfield idsschema 中某个字段 ID 未出现在任何数据文件中时该列按全NULL读取字段 ID 可被替换为墓碑值-2表示该列应被忽略典型场景是重写列旧数据文件以-2标记旧数据新数据文件追加进片段。一等公民索引First-Class Indices索引属于表格式生命周期的组成部分。表元数据描述索引的发现与事务协调方式详细检索结构仍是独立索引格式从而让引擎能以统一方式创建、删除、更新和查询索引而不把表格式绑定到任何单一索引算法上。外部清单存储External Manifest StoreLance 可直接提交到对象存储也支持通过外部清单存储协调提交——外部系统负责串行化提交与治理检查表的标准状态仍以 Lance 表格式持久化。Manifest 与 Schemamanifest 描述数据集的一个版本包含完整 schema 定义含嵌套字段、组成该版本的数据片段列表、单调递增的版本号以及可选的索引段引用IndexSection。Schema 与 Apache Arrow 数据类型基本一一对应每个字段含嵌套字段拥有唯一整数 ID建表时按深度优先顺序分配之后新增字段按增量分配。列编码配置通过lance-encoding:前缀的字段元数据指定。Schema 完整规范见 table/schema.md。未强制主键Unenforced Primary KeyLance 支持通过字段元数据定义未强制主键用于 merge-insert 去重等需要逻辑行标识的场景。约束条件包括字段及其所有祖先不可为空、必须是叶子字段、不能位于 list 或 map 类型内部主键一旦设置即固定不可更新或删除。通过 Arrow schema 建表时在字段元数据中添加lance-schema:unenforced-primary-key设为true/1/yes不区分大小写即可标记主键字段可选lance-schema:unenforced-primary-key:position1 起始整数指定复合主键中的位置与排序。片段与删除文件片段是数据的水平分区持有递增分配的uint32唯一 ID每个片段由一个或多个数据文件加可选的删除文件构成。删除文件记录片段内被删除行的 0 基位置支持两种存储格式Arrow IPC 格式.arrow扁平 Int32Array适合稀疏删除与 Roaring Bitmap 格式.bin压缩位图适合稠密删除。删除也可以被物化重写数据文件剔除已删行但这会使行地址失效并需要重建索引代价较高。存储布局规范见 table/layout.md。数据覆盖文件Data Overlay Files实验特性覆盖文件为片段内一小部分单元格提供新值而无需重写基础数据文件——当只有少量行/列变化时写入者只需追加一个小文件携带变更单元格。该特性目前为实验状态需要特性标志 64data overlay files完整规范见 table/data_overlay_file.md。事务与版本化表的读写通过 MVCC 与事务提交协议协调事务类型与冲突解决规则见 table/transaction.md行地址、稳定行 ID 与变更数据流见 table/row_id_lineage.md特性标志与格式版本兼容性见 table/versioning.md。索引格式层基于行 ID 的冗余检索结构索引规范入口位于 docs/src/format/index/index.md。Lance 把索引视为叠加在表行标识符之上的独立、冗余数据结构这让文件格式保持无内置检索结构索引格式也可独立于表布局演进。索引分为三大类标量索引Scalar Indices加速整数、时间戳、字符串等标量谓词查询包括以 zone map 为代表的主跳过结构以及 B-tree、bitmap、全文检索 FTS 等二级结构接收等值、范围、集合成员或 token 匹配谓词返回匹配的行 ID。向量索引Vector Indices专为高维 embedding 的近似最近邻搜索设计包括 IVF 类布局与 HNSW 图等详见 vector/index.md。与标量谓词不同向量索引接收查询向量并返回行 ID 加距离分数。系统索引System Indices支撑表内部维护与行 ID 解析的辅助结构用户不会直接查询例如支撑压缩后高效重映射的 Fragment Reuse Index。四个核心设计选择详见规范文档按需加载打开数据集无需加载任何索引只有查询可能受益时才加载降低内存占用并加快打开速度。渐进加载查询时只加载必要部分如 B-tree 先加载小型页表确定需要哪些索引页再仅加载这些页执行检索摊薄冷索引查询成本。跨片段合并索引远小于数据文件可将索引段合并覆盖多个片段减少查询时需要打开的索引文件数与检索结构数。不可变文件索引文件一旦写入即不可变只能通过新文件修改可放心在内存或磁盘缓存而不必担心一致性问题。段Segments与片段位图索引定义在数据集的具体列上由名称标识由多个以 UUID 标识的索引段构成。每个段是独立自包含的索引覆盖不相交的片段子集由fragment_bitmap字段记录。索引段不必覆盖所有片段——索引允许不完全最新引擎可把查询拆成走索引与直接扫描两个子计划再合并结果若索引创建时片段存在删除标记段可以不包含已删行。事务式创建与更新先读取待索引片段的列数据构建索引结构写入新_indices/{UUID}目录再构造IndexMetadata消息含uuid、name、fields、covering_fields、fragment_bitmap、index_details、version等字段最后通过与数据写入相同的原子事务机制提交包含新索引段的新 manifest。当列被原地更新时引擎必须从任何fields包含该列的索引段的fragment_bitmap中移除受影响片段 ID无论该列是键列还是仅携带列将片段标记为待重索引。兼容性检查与覆盖列使用索引段前引擎须校验index_details中的类型 URL识别索引类型与version字段格式版本无法识别时跳过该段并回退到扫描被覆盖片段。covering_fields声明索引携带的非键列但段的存储 schema 才是权威——回答来自携带列的查询前引擎必须确认该列确实存在于存储中否则回退到基础表 take声明与存储不符是合法状态而非损坏。规范特别注明当前阶段尚无索引构建器真正写入携带值所有声明都超前于存储读取方应把covering_fields纯当作声明处理。删除与失效行的处理由于索引段不可变其中可能引用已删除/已更新的行规范给出四种必须过滤的情形片段部分行已删用删除文件的行偏移过滤片段整体被删检查片段位图中的片段 ID 是否已从数据集消失片段的索引列被原地更新过滤不在当前fragment_bitmap中的行地址且携带列更新同样适用片段存在覆盖文件且其committed_version大于索引段的dataset_version须从索引结果中排除被覆盖的行并回到 flat 路径按当前覆盖值重评估。前三种情形也有配套图示见 index/index.md 中的 SVG 示意图。压缩与重映射片段压缩后行地址变化索引段会失效规范给出三种策略不处理索引立即过时查询性能最差立即重写索引段保持最新但写放大显著创建 Fragment Reuse Index 做旧地址→新地址的内存重映射增加少量 IO 与计算但避免压缩写放大。此外索引可选使用稳定行 ID逻辑标识符压缩移动后不变好处是压缩后无需重映射、更新只在其fields数据变化时使索引失效代价是查询时多一次稳定行 ID→物理行地址的查找该特性目前为实验状态。Catalog 规范层目录型与 REST 型两种形态Lance 同时提供存储原生与面向服务两类 Catalog 选项详见入口文档的描述目录型 CatalogDirectory Catalog支持零基础设施部署直接跑在对象存储上适合从单机到云端的快速起步。REST Catalog标准化面向企业的 API并可充当外部清单存储external manifest store用于需要服务化协调、权限与治理的部署场景。Catalog 规范负责定义表如何被发现、注册以及如何在多引擎、多服务间协调。当前仓库快照中docs/src/format下暂未收录这两份规范页面不过与其对应的能力在代码层已有落点命名空间namespace相关实现位于 rust/lance-namespace/Java 侧见 java/lance-jni/src/namespace.rsPython 侧见 python/lance/lance/namespace.py。命名空间客户端规范层引擎与 Catalog 之间的语言无关接口在存储层之上命名空间客户端规范为引擎提供与任意 Catalog 实现交互的语言无关接口——无论是 Lance 原生 Catalog 还是第三方目录系统。正是这层抽象让应用可以在目录型、REST 型与第三方 Catalog 之间无缝切换而无需改动业务代码。规范页面对应的接口语义可结合 rust/lance-namespace/ 的命名空间客户端实现与 python/lance/lance/namespace.py 的 Python 绑定对照理解。规范入口清单一份阅读地图入口文档将主要规范入口汇总如下全部转换为仓库根目录相对路径规范文档路径核心内容文件格式docs/src/format/file/index.md页布局、编码机制、无行组设计、footer 结构表格式docs/src/format/table/index.md片段、manifest、删除、schema 演化、ACID 提交索引格式docs/src/format/index/index.md标量/向量/系统索引格式与生命周期Catalog 规范目录型与 REST 型见入口文档描述表发现、注册与跨引擎协调命名空间客户端规范统一接口实现见 rust/lance-namespace/引擎与任意 Catalog 交互的抽象层配套的细化规范还包括文件编码策略 docs/src/format/file/encoding.md、文件版本化 docs/src/format/file/versioning.md、表布局 docs/src/format/table/layout.md、事务 docs/src/format/table/transaction.md、行 ID 与谱系 docs/src/format/table/row_id_lineage.md、格式版本兼容性 docs/src/format/table/versioning.md以及标量索引各实现zonemap、btree、bitmap、fts、bloom_filter、ngram、rtree 等。从规范到实现仓库中的源码证据地图规范的价值在于有可验证的实现。以下路径可作为继续深入当前仓库的起点protobuf 契约层各规范对应的消息定义集中在 protos/——表与索引相关消息在 protos/table.proto含Manifest、DataFragment、DataFile、DeletionFile、IndexSection、IndexMetadata等文件布局相关见 protos/file.proto 与 protos/file2.proto向量索引消息在 protos/ann.proto编码方案见 protos/encodings_v2_0.proto 与 protos/encodings_v2_1.proto事务与行 ID 相关见 protos/transaction.proto 与 protos/rowids.proto。Rust 核心实现rust/lance/src/dataset/117 个文件承载表格式核心提交、优化、统计、blob 等rust/lance/src/index/30 个文件承载索引构建与查询rust/lance/src/io/ 负责文件与对象存储读写命名空间客户端独立成 craterust/lance-namespace/。Python 绑定python/lance/lance/dataset.py、python/lance/lance/fragment.py、python/lance/lance/vector.py 与 python/lance/lance/indices/ 展示了上层 API 如何映射到规范结构python/lance/lance/namespace.py对应命名空间接口。Java/JNI 层java/lance-jni/src/ 中blocking_dataset.rs、index.rs、vector_trainer.rs、namespace.rs等提供 JVM 生态的桥接。兼容性验证数据test_data/ 下按版本存放历史数据与生成脚本如v0.5.9/、v0.7.5/、v0.21.0/bad_index_fragment_bitmap/、v3.0.1/fts_v1/、v4.0.1/fts_v2/等配合 python/python/tests/test_backwards_compatibility.py 验证格式版本兼容性。关键设计权衡小结从规范文本中可以提炼出几条贯穿始终的工程取舍行组概念有害论Lance 选择彻底放弃行组转而依赖大页 部分页读取来兼顾写内存占用与云存储读性能8MB 是推荐页大小但具体取值可随读写场景调整。统计与索引外置文件格式保持纯粹无类型概念、无内置统计与索引让这些关注点作为独立索引格式演进避免容器格式被检索需求绑架。删除的惰性删除文件让删除变成元数据操作避免重写数据文件物化删除虽然彻底但会失效行地址与索引需在成本与查询性能间权衡。列追加优先于全表重写二维存储 字段 ID 机制使加列/回填/重写列成为轻量元数据操作这正是数据演化data evolution与高效 embedding 更新的根基。索引的最终一致性索引段不必覆盖全部片段允许落后于数据引擎用索引子计划 扫描子计划合并查询结果换取索引维护的低成本。结语Lance 湖仓格式的价值不在于某一种文件编码的奇技淫巧而在于规范堆栈式的分层治理文件格式管好随机访问的页布局表格式管好片段与版本的演化索引格式独立演进检索结构Catalog 与命名空间接口让引擎可以插拔式接入任意目录系统。把握住这套分层模型无论是阅读 docs/src/format/index.md 及各子规范还是深入 protos/ 与 rust/lance/ 的实现代码都会有一条清晰的路径可循。【免费下载链接】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),仅供参考