当前位置: 首页 > news >正文

从本地目录理解 Lance Dataset:Manifest、Fragment 与 Blob

如果只从 LanceDB 的 API 看,表就是一张 table:可以建表、追加数据、建索引、做
vector search 或 full-text search。但落到磁盘后,它不是一个单独的数据文件,而是
一个 Lance dataset。

本文试图回答一个问题:

LanceDB 创建一张本地表之后,Lance 到底如何组织数据、版本、索引和大对象?

核心结论先放在前面:

  • LanceDB table 落地后是一个 Lance dataset,不是单文件数据库。
  • Manifest 描述某个版本的完整 dataset 状态。
  • Transaction 描述一次提交做了什么,主要服务写入、冲突检测和恢复。
  • Fragment 是 manifest 中的一段 rows,不是一个可见目录。
  • DataFile 是 fragment 指向的物理文件;一个 fragment 可以包含多个 data files。
  • 同一个 fragment 内的多个 data files 按 row offset 对齐。
  • Row address 是物理定位:fragment id + row offset
  • Row id 是逻辑记录身份,和 row offset、fragment id 不是同一个概念。
  • Blob v2 是 Lance 新的多模态大对象存储机制,用 descriptor 管理 inline、packed、dedicated 和 external blob。

一句话模型

可以先把 Lance dataset 记成这样:

LanceDB table-> Lance dataset-> manifest versions-> transactions-> fragments-> data files-> index files-> blob sidecar files

再压缩成更短的一句话:

Manifest 记录表的状态,Fragment 记录一段 rows,DataFile 存这些 rows 的字段,Index 指向候选行,Blob 管理大对象 bytes。

这个模型不是源码细节,而是理解 Lance 的入口。

从目录开始

跑完一个很小的 LanceDB demo 后,本地目录可能长这样:

data/day2_data_model.lancedb/
└── docs.lance/├── data/│   └── 100000011100000001100110a7a3f04005bedd716da9cccea8.lance├── _versions/│   ├── 18446744073709551614.manifest│   ├── 18446744073709551613.manifest│   └── 18446744073709551612.manifest├── _transactions/│   ├── 0-....txn│   ├── 1-....txn│   └── 2-....txn└── _indices/├── <vector-index-id>/│   ├── auxiliary.idx│   └── index.idx└── <fts-index-id>/├── metadata.lance├── part_0_docs.lance├── part_0_invert.lance└── part_0_tokens.lance

这里最容易误解的是:目录里没有 fragments/。Fragment 不是一个目录,而是写在
manifest 里的逻辑元数据。

_versions/<version>.manifest-> fragments[]-> id-> files[]-> physical_rows-> deletion_file

目录中的 data/*.lance 是 fragment 指向的物理 data files。

Version 记录的是状态,不只是行数

在 demo 里,创建表、创建向量索引、创建 FTS 索引会得到三个版本:

create table:rows = 8version = 1create vector index:rows = 8version = 2create FTS index:rows = 8version = 3

row count 没变,version 仍然变化。原因是 version 记录的是 dataset 状态变化,而不只是业务数据行数变化。

创建索引不会新增业务行,但会新增:

  • index files。
  • index metadata。
  • transaction。
  • manifest version。

所以 Lance 的 version 更像“表状态版本”,不是“数据行版本”。

Manifest 与 Transaction

Manifest 和 transaction 很像湖格式里的 snapshot 与 commit log,但它们在 Lance
里有自己的边界。

Manifest:version N 的完整 dataset 状态Transaction:这次提交做了什么操作

Manifest 里关心的是当前版本如何读取:

  • schema。
  • fragments。
  • indices。
  • table config。
  • data storage format。
  • row id / version 相关元数据。

Transaction 里关心的是提交行为:

  • append。
  • delete。
  • create index。
  • rewrite。
  • merge。
  • update。
  • update config。

读取表时,核心入口是 manifest。Transaction 更多服务于写入提交、冲突检测、重试、
恢复和审计。它不应该被简单理解成传统数据库的 undo log。

Fragment 不是 Parquet RowGroup,但可以类比

Fragment 可以类比为 dataset-level row group / file group。

它和 Parquet RowGroup 的相似点是:都可以理解为一段 rows 的组织单元。

但它们不是同一个层级:

Parquet
└── file.parquet├── RowGroup 0├── RowGroup 1└── RowGroup 2Lance
└── docs.lance/├── _versions/│   └── manifest -> fragments[]└── data/├── xxx.lance└── yyy.lance

Parquet RowGroup 是单个 Parquet 文件内部的物理分块。Lance Fragment 是 manifest
里的 dataset-level 逻辑分组。

更实用的记法是:

Fragment = horizontal grouping of rows
DataFile = physical file that stores fields for those rows

普通写入时,一个 fragment 可能只有一个 data file:

Fragment 0: rows 0..7
└── DataFile A: id, title, text, category, vector

但 Lance 允许一个 fragment 指向多个 data files:

Fragment 12: same rows
├── DataFile A: id, title, text
├── DataFile B: vector
└── DataFile C: updated_column

这些 files 不是不同的行集合,而是同一批 rows 的不同字段集合。

Row Offset、Row Address 与 Row ID

这一组概念非常容易混。

row offset:fragment 内部的物理位置row address:fragment id + row offset用来物理定位一行row id:逻辑记录身份

比如:

Fragment 7row offset   row address   row id
0            (7, 0)        10001
1            (7, 1)        10002
42           (7, 42)       10999

row offset = 42 不是全表第 42 行,而是 Fragment 7 内部第 42 个位置。

fragment id = 7 也不是 first row id。它只是这个 fragment 在 dataset 内的唯一
编号,通常按创建顺序单调分配,但不要假设永远连续无空洞。

如果从 Paimon 的 firstRowID + offset 机制类比,Lance 也有“分组标识 + 组内
offset”的味道。但 Lance 的 fragment id 不是 first row id,它只回答“在哪个
fragment”,row offset 才回答“在这个 fragment 的哪个位置”。

为什么多个 Data Files 要行对齐

一个 fragment 中的多个 data files 必须按 row offset 对齐。

Fragment 12row offset     DataFile A: id,text        DataFile B: vector
0              id=101, text="..."         vector=[...]
1              id=102, text="..."         vector=[...]
42             id=199, text="..."         vector=[...]

这意味着 row offset = 42DataFile ADataFile B 中指向同一条逻辑记录
的不同字段。

这也是索引回表能够成立的原因:

index hit-> row address-> fragment id + row offset-> read only needed columns / files

如果同一行的不同字段被拆到不同 fragment,这个物理定位模型就会被破坏。

Fragment 怎么拆

Fragment 主要按写入过程中的行数或文件大小滚动产生。用户通常不会手动指定每个
fragment 的行范围。

input RecordBatch stream-> roll by max_rows_per_file / max_bytes_per_file-> write data file-> create fragment metadata

小批量频繁 append 会制造很多小 fragments,因为每次 append 都可能提交新的 data
file 和 fragment。后续可以通过 optimize / compaction 合并。

所以 Lance 不是靠“把大列和小列拆到不同 fragment”来避免大列拖慢普通列。Fragment
是横向的 rows 分组。大列隔离更多依赖列式投影、fragment 内多 data files、partial
update,以及 blob sidecar。

Blob v1 与 Blob v2

Blob 是 Lance 面向多模态大对象的能力,例如图片、视频、音频、PDF、模型文件等。

Blob v1 是旧机制。用户字段是:

LargeBinary
metadata: lance-encoding:blob = true

它的 descriptor 基本是:

Struct<position, size>

v1 已经可以 lazy read,但表达能力有限,主要定位当前 Lance data file 里的 byte
range。

Blob v2 是新的推荐机制。用户侧字段带 Arrow extension:

ARROW:extension:name = "lance.blob.v2"

输入形状大致是:

Struct<data: LargeBinary?, uri: Utf8?>

写入后会变成更丰富的 descriptor:

Struct<kind, position, size, blob_id, blob_uri>

kind 表示 blob 的物理存储方式:

Inline:小 blob 放在主 Lance data file 中Packed:中等 blob 打包进共享 .blob sidecarDedicated:大 blob 单独一个 .blob sidecarExternal:不搬运 bytes,只保存外部 URI / path 引用

Blob v2 的核心价值是:用一个统一 descriptor 表达多种 blob 布局。

v1:position + sizemostly current data filev2:kind + position + size + blob_id + blob_urimain file / packed sidecar / dedicated sidecar / external object

这解决了几个实际问题:

  • 大 blob 不必都挤进主 .lance data file。
  • 小 blob 可以 inline,避免制造过多小文件。
  • 中等 blob 可以 packed 到共享 .blob 文件。
  • 超大 blob 可以 dedicated 成独立 .blob 文件。
  • 已在外部存储中的对象可以只保存引用。
  • 外部对象可以通过 position + size 表示 byte range。
  • 读取时可以返回 file-like handle,按需流式读取。

文件格式上,v1 和 v2 的边界也很清楚:

data_storage_version <= 2.1:legacy blob metadata, blob v1data_storage_version >= 2.2:blob v2

因此 v1 主要是 legacy compatibility,v2 是新推荐设计。

与 Paimon Blob 的相似点

Lance Blob 和 Paimon Blob 解决的是同一类问题:大对象列不应该拖慢普通结构化列。

相似点是:

  • 普通列留在正常数据文件中。
  • 大对象 bytes 可以放到独立 blob 文件或外部位置。
  • 正常数据文件里保存 descriptor / reference。
  • 读普通列时不需要加载大对象 bytes。

但要注意,Blob 和 Fragment 不是同一层机制:

Fragment / DataFile:解决 rows 如何分组、字段如何组织、如何随机访问。Blob:解决大对象 bytes 如何从普通列式读取路径中分离出去。

它们方向相似,都是减少无关 I/O,但解决的是不同层次的问题。

Takeaways

  • 先理解 manifest,再理解 fragment,最后理解 data file,Lance 的本地目录就不乱了。
  • Version 是 dataset 状态版本,不是 row count 版本。
  • Fragment 是 dataset-level 的 rows 分组,和 Parquet RowGroup 类似但不等价。
  • row address = fragment id + row offset 是 Lance 随机访问的关键 mental model。
  • Row offset 是 fragment 内位置;row id 是逻辑身份。
  • Fragment 内多个 data files 必须 row-aligned。
  • Blob v2 是 Lance 面向多模态大对象的新版 descriptor 机制。
  • Blob v1 负责兼容旧数据集,Blob v2 承担新设计。
  • Lance Blob 和 Paimon Blob 问题相似,但不要把 blob sidecar 和 fragment 分组混成一个概念。
http://www.jsqmd.com/news/835860/

相关文章:

  • 贵州驾照培训如何做线上推广?2026本地获客指南与服务商盘点 - 精选优质企业推荐官
  • 2026年5月南充区域广告设计制作(喷绘写真,平板UV喷印,亚克力字)安装价格 - 四川华蔓广告有限公司
  • 2026年5月南充区域广告设计制作(灯光舞台,演艺主持,泡沫板)安装价格 - 四川华蔓广告有限公司
  • 初学 Java 接口学习心得
  • HarmonyOS 5.0 PC应用开发实战:构建跨设备协同的桌面生产力工具
  • 贵阳驾照培训如何做线上推广?2026驾培行业获客指南与服务商盘点 - 精选优质企业推荐官
  • 贵阳门窗安装销售服务如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 贵阳成人职业技能培训如何做线上推广?2026全网获客与GEO优化指南 - 精选优质企业推荐官
  • 贵州成人职业技能培训如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 中国发展网:2026全国GEO优化服务商权威榜单丨综合实力与口碑TOP5 - 罗兰艺境GEO
  • Claude Code 终端高效使用指南
  • 贵阳二手车收售评估如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 2026年4月工业风扇公司口碑推荐,大型工业风扇/工业大吊扇/工业风扇/工业排风扇/工业散热风扇,工业风扇厂商怎么选择 - 品牌推荐师
  • 2026年4月目前好吃的小吃品牌推荐,小笼包/包子/小吃/手工小笼包/酱肉小笼包/美食小吃/非遗红油小笼包,小吃品牌推荐 - 品牌推荐师
  • 贵州园林绿植养护工程如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 贵阳室内装修设计施工如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 2026年5月南充区域广告设计制作(警示标识,围挡,展架)安装价格 - 四川华蔓广告有限公司
  • 长春:报考中质协六西格玛黑带和绿带指定报考机构推荐 - 众智商学院课程中心
  • P3258 [JLOI2014] 松鼠的新家 题解
  • 2026年5月南充区域广告设计制作(易拉宝,X展架,行架租赁)安装价格 - 四川华蔓广告有限公司
  • 温州:报考中质协六西格玛黑带和绿带指定报考机构推荐 - 众智商学院课程中心
  • 贵阳瓷砖卫浴建材销售如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • OO第一阶段作业总结:从过程式思维到面向对象设计的蜕变
  • C++学习(26_05_17)
  • 贵阳园林绿植养护工程如何做线上推广?2026本地获客指南与服务商盘点 - 精选优质企业推荐官
  • 2026年甄选:公交站台源头厂家 - 品牌推广大师
  • 贵阳企业团建活动策划如何做线上推广?2026年本地获客指南与服务商推荐 - 精选优质企业推荐官
  • 贵阳冷库仓储物流配送如何做线上推广?2026全网获客指南与服务商盘点 - 精选优质企业推荐官
  • 如何在 Cloudflare Workers 中调用第三方 API 遇到 CORS 怎么解决
  • 面向对象设计与构造----第一单元总结