Lance:面向多模态 AI 的湖仓格式,用两行代码替换 Parquet
多模式 AI 的开放 Lakehouse 格式。只需 2 行代码即可从 Parquet 进行转换,以实现速度提高 100 倍的随机访问、向量索引和数据版本控制。与 Pandas、DuckDB、Polars、Pyarrow 和 PyTorch 兼容,即将推出更多集成。
秒懂
- 它是什么?
- Lance 是一个开源湖仓格式,专为多模态 AI 设计,支持向量搜索、全文检索和随机访问。本文基于其 README 和仓库信息,分析它的核心机制、使用方式、局限性与适用场景。
- 适合谁用?
- Lance 适合需要高性能随机访问、向量搜索和版本控制的多模态 AI 团队,尤其是那些已经使用 Parquet 但受限于其扫描式 IO 的项目。不建议仅将其用作通用分析存储,因为其核心优势在列存扫描上并不突出,且格式仍处于快速迭代期。
- 能商用吗?
- 可以。Apache-2.0 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库最近一次提交在 3 天前。
- 用什么语言写的?
- 主要是 Rust(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月14日)和我们的分析,不构成法律意见。
开源项目深度解析
它解决什么问题:Parquet 的随机访问痛点
Parquet 是列式存储的事实标准,但它的设计目标是扫描密集型分析,按行读取单条记录时效率很低。Lance 的出现就是为了解决这个问题。README 明确宣称其随机访问比 Parquet 或 Iceberg 快 100 倍,同时不牺牲扫描性能。这个数字来自官方,我们未做独立验证,但它指向的核心问题是真实的:多模态 AI 工作负载,比如训练时需要随机采样图片或文本,或者构建特征存储时需要频繁按 ID 读取,Parquet 的块式布局会导致大量不必要的 IO。Lance 的目标用户是构建搜索引擎、特征存储和大型 ML 训练管道的工程师,他们需要在一个数据集上同时做向量相似度搜索、全文检索和 SQL 分析。
核心机制:文件格式、表格式与目录规范的组合
Lance 不是单一的文件格式,而是三件套:文件格式、表格式和目录规范。文件格式负责存储数据,表格式管理数据集的结构和版本,目录规范则定义了如何在对象存储上组织多个数据集。这种分层设计让它可以构建完整的湖仓,而不只是替代 Parquet。数据写入时,Lance 使用列式布局,但针对随机访问优化了页和块的组织方式。它还支持原生多模态数据,比如图片、视频和音频,通过高效的 blob 编码和惰性加载,避免在查询时加载整个大对象。版本控制是零拷贝的,基于 ACID 事务,支持时间旅行、标签和分支,不需要额外的基础设施。这些机制在 README 中有描述,但具体的数据页布局和索引结构并未在文档中展开,需要查阅完整的格式规范才能深入。
两行代码转换:从 Parquet 到 Lance 的实操
转换过程确实简单。README 给出了明确的示例:先用 PyArrow 写出 Parquet 文件,然后调用 lance.write_dataset 即可。代码如下:
import lance import pyarrow.dataset as pa parquet = pa.dataset.dataset("/tmp/test.parquet", format='parquet') lance.write_dataset(parquet, "/tmp/test.lance")
读取时,lance.dataset 返回一个 pyarrow.dataset.Dataset,所以可以直接用 Pandas 或 DuckDB 查询。DuckDB 的用法是 duckdb.query("SELECT * FROM dataset LIMIT 10").to_df(),但 README 中有一条警告:如果段错误,请确保 duckdb 版本在 0.7 以上。这个细节说明集成层可能存在兼容性问题,实际使用时需要检查版本。安装则通过 pip install pylance,预览版需要指定额外的索引 URL。
向量索引:IVF_PQ 的构建与搜索示例
向量搜索是 Lance 的核心卖点之一。README 用 SIFT 1M 数据集演示了完整流程。首先将 .fvecs 文件读入 numpy 数组,然后转换为 Lance 表,写入时指定 max_rows_per_group 和 max_rows_per_file。接着调用 create_index 方法,设置 index_type="IVF_PQ",num_partitions=256,num_sub_vectors=16。这里 IVF(倒排文件)和 PQ(乘积量化)是经典的近似最近邻索引方法,Lance 将其内置到格式中。搜索时,通过 dataset.to_table(nearest={"column": "vector", "k": 10, "q": q}) 传入查询向量,返回最近邻。这个 API 设计得很直接,但注意它依赖 DuckDB 来采样查询向量,如果 DuckDB 版本不对,示例代码会直接段错误。索引参数需要用户自己调优,num_partitions 和 num_sub_vectors 的选择会影响召回率和构建时间,文档没有给出指导,需要实验。
数据演化与版本控制:免重写的列添加
Lance 宣称可以高效地添加列,并用回填值填充,而无需重写整个表。这对 ML 特征工程很关键,因为特征经常需要增量计算。传统的 Parquet 表添加列通常需要重写所有数据,成本高昂。Lance 的版本控制是自动的,基于 ACID 事务,支持时间旅行、标签和分支。这些特性在 README 中被列为零拷贝版本控制,意味着不需要额外的版本控制服务。但这里有一个隐含的权衡:每次写入都会产生新版本,如果频繁写入小批量数据,版本元数据可能会膨胀。README 没有提及清理旧版本的机制,实际使用中可能需要手动合并或删除旧版本,否则存储成本会上升。
生态集成:Arrow、Pandas、DuckDB、Spark 等,但各有差异
Lance 的集成列表很长:Apache Arrow、Pandas、Polars、DuckDB、Spark、Ray、Trino、Flink,以及开放目录如 Apache Polaris、Unity Catalog、Apache Gravitino。README 明确说“更多集成正在路上”。但集成深度不一。Python 绑定通过 PyO3 实现,Java 绑定通过 JNI,核心是 Rust。这意味着每个语言绑定的成熟度可能不同。DuckDB 的集成在快速入门中就有段错误警告,说明并非所有版本都稳定。对于 Spark 或 Flink 用户,需要检查是否支持写入和读取,还是只支持读取。README 没有给出每个集成的具体功能列表,这是一个信息缺口。如果你依赖某个特定引擎,必须先验证其兼容性,而不是假设所有列出的集成都是等价的。
格式稳定性与版本管理:data_storage_version 是关键
Lance 发布频繁,但 README 强调文件格式本身有稳定性保证。每个数据集都存储一个 data_storage_version,稳定版本是长期兼容契约。一旦数据集用稳定版本写入,未来的 Lance 版本会继续支持读取。但 SDK 和 API 的兼容性遵循语义化版本,与文件格式兼容性分开。这意味着升级 SDK 可能引入 API 变化,但不会破坏已存在的数据。有一个警告:旧版 Lance 可能无法理解新版文件格式,如果混合运行不同版本,需要固定 data_storage_version。此外,next 别名不稳定,只能用于实验,不能用于生产。对于生产环境,你应该显式指定稳定版本,而不是依赖默认值。这个机制是合理的,但需要用户在部署时注意版本对齐。
维护成本与许可证:Apache-2.0 下的活跃开发
Lance 采用 Apache-2.0 许可证,这对商业使用友好,没有 copyleft 义务。仓库最后推送时间是 2026 年 8 月,最近有 v12.0.0-beta 系列,说明开发非常活跃。但活跃也意味着 API 可能频繁变化,README 提到迁移指南,说明存在破坏性变更。维护成本取决于你的使用深度:如果只用 Python 绑定做基本读写,成本较低;如果要自定义索引或依赖特定版本的行为,需要关注每个版本的迁移说明。预览版更新更频繁,README 保证至少保留 6 个月,但生产环境应使用稳定版。整体上,Lance 的维护成本比 Parquet 高,因为它涉及索引和版本管理,但这是换取随机访问性能的代价。
编辑结论
Lance 适合需要高性能随机访问、向量搜索和版本控制的多模态 AI 团队,尤其是那些已经使用 Parquet 但受限于其扫描式 IO 的项目。不建议仅将其用作通用分析存储,因为其核心优势在列存扫描上并不突出,且格式仍处于快速迭代期。在采用前,应验证你的数据写入版本对应的 data_storage_version 是否为稳定版本,并检查所依赖的 SDK(Python、Java 或 Rust)与你的查询引擎(DuckDB、Polars)的兼容性。如果只是需要简单的列存分析,Parquet 加上 DuckDB 可能更省事。Lance 的复杂度来自其索引和版本管理,若你用不到这些特性,它只会增加运维负担。最终判断:Lance 是一个针对 AI 工作负载重新设计的存储格式,它的价值在于随机访问和混合搜索,而不是替代所有 Parquet 场景。
社区笔记