Lance 文件格式规范
这篇规范说明了 Lance 文件在容器层的布局、定位机制与读取策略,并补充了列元数据 protobuf 消息的具体定义。容器边界与核心对象文档聚焦文件容器本身:按列分页存储、footer 定位与偏移组织。类型系统不内建在容器层,而是由编码层补足。列与全局缓冲区都通过整数索引和绝对偏移进行引用。文件尾元数据组织列描述符、…
Reprint Notice(转载提示):本文转载自 https://github.com/lance-format/lance/blob/main/docs/src/format/file/index.md。 原文标题:Lance File Format。 原文语言:English。本文为中文翻译版本,并对部分站内可演进链接做了本地知识库化改写。Lance 文件格式规范文件结构 一个 Lance 文件是表格数据的容器。数据以磁盘页(disk pages)的形式存储。每个磁盘页包含单列的一部分行数据。每列可以有一个或多个磁盘页,不同列的页数也可能不同。文件尾部的元数据描述了页面位置及其编码方式。 格式总览 说明 本页描述的是容器规范。我们还提供了一组默认编码,用于将数据编码到磁盘页。详见编码策略。磁盘页 磁盘页被设计为足够大,以便即使在云存储上也值得一次专门的 I/O 操作,典型大小为数 MB。更大的页大小可以减少读取文件所需的 I/O 次数,但也会提高写文件时的内存需求。实践中,当追求高速读取时,过大的页并不实用,因为大块连续读取通常仍需拆分为更小读取以获得更好性能(尤其在云存储上)。因此,建议默认页大小为 8MB,在各类存储系统上通常都能获得理想性能。 磁盘页通常不应被视为不可拆分的黑盒。仅需部分行时,可以只读取磁盘页中的一部分字节。但具体读取方式取决于列编码,这将在后续章节说明。不使用 Row Group 与类似格式不同,Lance 没有 row group 概念,只有 pages。我们认为 row group 在性能上存在根本性问题。row group 太小时,列会被切分为较小的“零碎页(runt pages)”,在云存储上读取性能较差。row group 太大时,写入器需要大量 RAM,因为写入前必须先在内存里缓冲整个 row group。相反,为了在多个读取器之间切分文件,我们依赖“可进行部分页读取且读取放大较小”这一特性。因此,你可以按任意行边界切分文件。缓冲区对齐 文件格式不要求缓冲区必须连续,因为缓冲区是通过绝对偏移量引用的。实践中,缓冲区通常会按 64 字节边界对齐。外部缓冲区 文件中的每个页面都通过绝对偏移量引用。这意味着页面之间可以插入非页面数据。当某些超大数据类型在常规页内每页只能容纳很少行时,这种方式很有用。此时可将数据以 out-of-line 形式存储,并在页面中存放其位置。 此外,文件格式支持用于辅助数据的全局缓冲区(global buffers)。这些缓冲区可用于存储文件 schema、文件索引、列统计信息或其他元数据。全局缓冲区的引用会写入 footer 的特定位置。列描述符 文件尾部包含描述每个页面的元数据,特别是所使用的编码策略。该元数据由一系列列描述符组成,每个列描述符都是一个独立的 protobuf 消息,对应文件中的一列。由于每列都有独立消息,如果只关心部分列,就不必读取全部文件元数据。不过在很多场景中,列描述符很小,一次读取整个 footer 往往比拆成多次读取更划算。偏移表与 Footer 列描述符之后是列描述符和全局缓冲区的偏移数组。这些数组仅用于指向各项的位置。最后是固定大小的 footer,用于描述偏移数组的位置以及元数据区的起始位置。标识符与类型系统 这个基础容器格式本身不包含类型概念。类型由编码层补充。所有列通过整数“列索引(column index)”引用,所有全局缓冲区通过整数“全局缓冲区索引(global buffer index)”引用。schema 通常存储在全局缓冲区中,但文件格式本身并不感知这一点。读取策略 读取数据前必须先拿到文件元数据。加载 footer 的一种简单方式是从文件末尾读取一个扇区(扇区大小取决于文件系统:本地磁盘通常为 4KiB,云存储通常更大),随后解析 footer,并在已知大小后读取其余元数据。这通常需要 1-2 次 IOPS。如果元数据大小保存在其他位置(例如表 manifest),则有可能始终通过单次 IOP 读取 footer。若文件列非常多且只需其中部分列,逐列读取元数据可能更合适:I/O 次数会增加,但读取字节量会下降。 接下来读取数据时,需要扫描每列的页面来判断需要哪些页。每个页都会存储该页第一行的行偏移(row offset),因此可快速定位目标页面。再结合该页的编码信息,就能确定需要从页中读取哪些精确字节范围。 磁盘页通常足够大,顺序读取整个文件不会带来明显优势。但如果需要该模式,在已知元数据后仍可顺序读取整个文件,前提是你确实要读取所有列。详细概览 格式总览 下面给出文件布局的详细描述:// Note: the number of buffers (BN) is independent of the numbe…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行