跳转至

Puffin vs Lance · 向量下沉到湖的两条路

Reference · 速查资深

读完能回答的选型问题

"我们要让湖表直接支持向量检索" 这件事 —— 到底选 Iceberg + Puffin 把 ANN 索引当侧车,还是 整表改成 Lance 格式?两条路背后的架构假设不同,成本与灵活度也不同。

TL;DR

  • Puffin 是 Iceberg 协议里的一个侧车文件类型;Lance 是一种独立的列式文件格式
  • Puffin = 保留 Parquet 数据 + 外挂索引 Blob;最小侵入,引擎多
  • Lance = 数据文件 + 索引 + manifest 三位一体;多模原生,随机访问强
  • 选 Puffin:已有 Iceberg 栈 + 向量需求轻量 + 看重跨引擎开放
  • 选 Lance:多模主线 + ML 训练重 + 愿接受独立格式的生态成本
  • 非互斥:一家可并存。Puffin 管"BI 事实表上的小向量侧",Lance 管"多模资产 + 向量大表"

两者的本质差异

维度 Iceberg + Puffin Lance / LanceDB
定位 协议扩展(标准 spec 的一部分) 独立文件格式(新的事实标准候选)
数据文件 Parquet / ORC(沿用) Lance Fragment(原生)
索引存放 Puffin blob(独立文件,被 Manifest 引用) 内嵌 Fragment(与数据同文件簇)
向量原生字段 VECTOR\<FLOAT, N>(Iceberg 类型) 原生,连带多模二进制
随机访问 Parquet 级别(Page 解压) 原生行级
更新 / 删除 Iceberg 的 delete files Fragment 原子替换
读端要求 引擎认识 Puffin blob 类型 需要 Lance reader
最大规模 随 Iceberg(表格式层面) 取决于 LanceDB 部署方式
治理 / Catalog Iceberg Catalog(Unity / Polaris / Nessie)原生 在 Unity Catalog 支持中;Lance 表注册仍在演进

架构层面的对比

Iceberg + Puffin

Catalog
  └── metadata.json
       └── Manifest List
            └── Manifest
                 ├── Data file (Parquet)
                 ├── Delete file (Parquet/position deletes)
                 └── Puffin blob (HNSW / IVF-PQ / stats)

关键性质: - 数据文件和索引文件分离,被同一个 Manifest 引用 - Iceberg 全部能力(Time Travel、Schema Evolution、Partition Evolution)无损继承 - 引擎读取时分两条路径:数据扫描 vs 索引查询,由优化器选择 - Puffin blob 自描述类型(字符串 kind,如 apache-datasketches-theta-v1 / vector-index-hnsw-v1

Lance

对象存储
  └── dataset/
       ├── Fragment 1
       │    ├── Data file (Lance format)
       │    └── Index file (ANN, inline with fragment)
       ├── Fragment 2
       │    └── ...
       └── _versions/
            └── manifest.json (version history)

关键性质: - 数据 + 索引 + 版本元数据三位一体 - 每个 Fragment 自足,独立 Reader 可直接消费 - 原生支持随机访问(对训练数据 shuffle 重要) - 多模二进制字段(图 / 音 / 视)作为一等公民

生态对比

哪些引擎 / 工具能读

对象 Puffin(Iceberg 表的侧车) Lance
Spark ✅ 通过 Iceberg Spark runtime ✅ lance-spark
Trino ✅ Puffin stats 已用;向量索引 blob 阅读在演进 ⚠️ 需要 lance reader,实验性
Flink ✅ Iceberg Sink/Source ⚠️ 较新
DuckDB ✅ 通过 Iceberg extension ✅ lance 扩展
Python / pyiceberg / pyarrow lance 包原生
LanceDB ✅ 原生
Ray / PyTorch 训练 ✅ 通过 Spark 或 pyiceberg 最佳(随机访问原生)
Milvus / Qdrant 迁出 不直接 可作为落地格式

Catalog 支持

  • Puffin / Iceberg:Unity / Polaris / Nessie / Gravitino / HMS 全部原生(因为本来就是 Iceberg)
  • Lance:Unity Catalog 支持向量表的路径;Nessie 尚未明确;Polaris 暂不支持。生态仍在追赶。

治理(权限 / 血缘)

  • Puffin:治理 = Iceberg 治理,现成
  • Lance:表级权限相对新,跨 Catalog 一致性要自己设计

性能场景

向量检索本身

场景 Puffin Lance
单个查询 Top-K(内存索引) HNSW blob 加载到内存后等价 等价
大规模(百亿级)磁盘友好 Puffin DiskANN blob 理论支持 Lance + DiskANN 更成熟
带结构化过滤的 hybrid Iceberg 的谓词下推 + Puffin LanceDB filter-aware 更强
多向量列(CLIP + BGE) 一列一个 blob,协议统一 原生多列,内嵌

ML 训练读取

  • 随机 shuffle 读 100M 行训练集:Lance 明显胜(随机访问原生);Parquet 需要解压 Row Group,成本高
  • 全量批扫描训练集:两者接近

写入路径

  • 流式 upsert(CDC):Iceberg+Paimon 组合成熟;Lance 能用但不是核心场景
  • 批量 append(新向量):两者都高效

团队落地建议(和 ADR-0003 一致)

场景 选择
BI 事实表要加个"推荐相似"向量列 Puffin(最小侵入)
多模资产表(图 / 文 / 音 + 向量) Lance
大规模 ML 训练集 Lance
已有 Iceberg 栈,短期验证向量能力 Puffin
长期主线:多模检索 + RAG 支撑 Lance(配合 LanceDB)
小向量量(< 千万)+ 结构化主导 Puffin(避免引新格式)

共存模式(最可能的实际结果)

大多数团队会走组合拳

主线多模 asset 表          → Lance / LanceDB
BI 事实表上的"小向量尾巴"  → Iceberg + Puffin
大规模 in-production 向量检索 → Milvus(独立服务)
全部通过 Unity / Polaris 统一 Catalog 注册

不要纠结"必须二选一"。Puffin 是 Iceberg 的一个特性;Lance 是一种格式。它们的竞争不对称——更准确说 Lance 竞争的是 Parquet,Puffin 是 Iceberg 协议的扩展。

陷阱与风险

  • Puffin 向量索引标准仍在演进:不同引擎支持进度不同,选型时问清楚你用的引擎版本
  • Lance 表迁移到其他格式成本高:锁定性比 Parquet 强
  • Lance + Iceberg 混合:一张 Iceberg 表里能不能放 Lance 数据文件?理论上 spec 允许,实现支持仍看引擎
  • Catalog 对 Lance 表的权限模型:比 Iceberg 晚成熟,权限边界可能有灰色

相关

延伸阅读

  • Iceberg Puffin spec: https://iceberg.apache.org/puffin-spec/
  • Lance 论文 / LanceDB blog 系列
  • A Vector Search Engine for the Data Lake Era(LanceDB 博客)
  • Iceberg Vector Search discussion(社区讨论)