第5章:Lance 文件格式详解
概述
Lance 文件格式是整个项目的核心机制。本章讨论 Lance 文件结构、Fragment 组织、Manifest 元数据管理。
Lance 文件体架构
Lance 文件的逻辑结构如下:
erlang
页头 0
数据块(编码)
页头 1
数据块(编码)
更多页面...
全局元数据
元数据偏移(8字节)
文件读取流程
文件读取器需要:
- 从文件末尾读取元数据偏移量
- 根据偏移量读取全局元数据
- 解析所有页面的元数据
- 根据需要读取特定的列数据
文件读取基本流程:
open(path) -> read_metadata_offset() -> read_global_metadata() -> parse_page_metadata() -> ready for queries
FileReader 接口
FileReader 提供的主要方法:
- open(path, options): 打开文件
- read_column(name, row_range): 读取列数据
- read_batch(): 读取一个批次
- statistics(): 获取统计信息
Fragment 组织
什么是 Fragment?
Fragment 是 Lance 数据的逻辑分片单位。一个 Fragment 包含:
- ID:唯一标识
- 数据文件列表:存储实际数据
- 删除文件:记录已删除行
- 行计数:总行数
- 字节大小:占用空间
Fragment 的结构
每个 Fragment 可以包含多个数据文件,每个文件可以存储不同的列。
Fragment 的优势:
- 支持增量更新(添加新 Fragment)
- 支持删除操作(通过删除文件标记)
- 支持版本演化(添加新列时不需重写旧 Fragment)
- 便于并行读取
Fragment 版本演化
当添加新列时:
- 新 Fragment 直接包含新列
- 旧 Fragment 标记为"需要补全"
- 查询时自动补全缺失列的默认值
Manifest 元数据
Manifest 是什么
Manifest 是数据集的完整元数据快照,记录:
- 版本号:当前版本
- 时间戳:创建和更新时间
- Schema:表的列定义
- Fragment 列表:所有数据分片
- 统计信息:行数、大小等
- 索引信息:已建立的索引
Manifest 的内容
一个 Manifest 包含:
yaml
version: 1
created_at: 2024-01-15T10:30:00Z
schema:
fields:
- name: id
type: int64
- name: name
type: utf8
- name: embedding
type: list<float32>
fragments:
- id: 0
files: [...]
row_count: 10000
statistics:
num_rows: 10000
byte_size: 5242880
Manifest 序列化
Manifest 可以序列化为 JSON 或 Protocol Buffer 格式,存储在文件系统中。
Manifest 版本管理
版本控制机制
Lance 支持多个 Manifest 版本共存:
markdown
_lance/
_manifests/
v1.manifest
v2.manifest
v3.manifest
_latest.txt
_latest.txt 指向当前最新版本。
时间旅行查询
用户可以打开任何历史版本进行查询:
open_version(dataset_path, version=2)
这使得 Lance 支持:
- ACID 事务语义
- 数据恢复
- 审计跟踪
- 版本对比
版本之间的差异
不同版本可能有不同的:
- Fragment 集合(添加/删除数据)
- Schema(添加/修改列)
- 索引(创建/删除索引)
- 统计信息(更新行数、大小)
场景
场景 1:添加新列
原始 Schema:id, name, price 新增列:embedding
处理方式:
- 创建新 Manifest 版本
- 在新 Fragment 中添加 embedding 列
- 旧 Fragment 的 embedding 填充为 NULL
- 提交新 Manifest
场景 2:数据删除
要删除某些行:
- 创建删除文件,记录行 ID
- 更新 Fragment 的删除文件列表
- 创建新 Manifest 版本
- 查询时自动跳过被删除的行
场景 3:版本对比
对比两个版本:
- 版本 1:100 万行,5GB
- 版本 2:150 万行,7.5GB
- 差异:新增 50 万行
性能考虑
随机访问
Lance 文件格式支持快速随机访问:
- 通过 metadata offset 快速定位元数据
- 根据页面索引快速定位数据
- 支持列式读取(不需读取全行)
- 支持范围读取(读取特定行范围)
缓存优化
- 元数据缓存:常驻内存
- 页面缓存:LRU 策略
- 索引缓存:按需加载
总结
Lance 文件格式的核心特性:
- 分页组织:支持快速随机访问
- Fragment 管理:灵活的数据分片
- Manifest 管理:完整的元数据管理
- 版本控制:支持时间旅行查询
- Schema 演化:添加列无需重写
下一章讨论编码与压缩技术。