该存储库包含用于读取和写入 Parquet 元数据的 Apache Parquet 和 Apache Thrift 定义的规范。
Apache Parquet 是一种开源、面向列的数据文件格式,专为高效数据存储和检索而设计。它提供高性能压缩和编码方案来批量处理复杂数据,并受到许多编程语言和分析工具的支持。
我们创建 Parquet 是为了让 Hadoop 生态系统中的任何项目都能利用压缩、高效的列式数据表示的优势。
Parquet 是从头开始构建的,考虑到了复杂的嵌套数据结构,并使用 Dremel 论文中描述的记录粉碎和组装算法。我们相信这种方法优于嵌套名称空间的简单扁平化。
Parquet 旨在支持非常高效的压缩和编码方案。多个项目已经证明了对数据应用正确的压缩和编码方案对性能的影响。 Parquet 允许在每列级别上指定压缩方案,并且面向未来,允许在发明和实现时添加更多编码。
Parquet 专为任何人使用而设计。 Hadoop生态系统有丰富的数据处理框架,我们不喜欢偏袒。我们相信,一个高效、实施良好的列式存储底层应该对所有框架都有用,而无需付出大量且难以建立依赖关系的成本。
parquet-format
项目包含正确读取 Parquet 文件所需的格式规范和 Thrift 元数据定义。
parquet-java
项目包含多个子模块,这些子模块实现了读取和写入嵌套的、面向列的数据流的核心组件,将该核心映射到parquet格式,并提供Hadoop输入/输出格式、Pig加载器等用于与 Parquet 交互的基于 java 的实用程序。
parquet-compatibility
项目包含兼容性测试,可用于验证不同语言的实现是否可以读取和写入彼此的文件。
可以使用mvn package
构建 Java 资源。当前的稳定版本应该始终可以从 Maven Central 获得。
C++ Thrift 资源可以通过 make 生成。
Thrift 还可以将代码生成为任何其他 Thrift 支持的语言。
块(HDFS块):这意味着HDFS中的块,并且对于描述这种文件格式的含义没有改变。该文件格式旨在在 HDFS 上良好运行。
文件:HDFS 文件,必须包含文件的元数据。它不需要实际包含数据。
行组:将数据逻辑水平划分为行。行组没有保证的物理结构。行组由数据集中每列的列块组成。
列块:特定列的数据块。它们位于特定的行组中,并保证在文件中是连续的。
页:列块被分为页。页面在概念上是一个不可分割的单元(就压缩和编码而言)。列块中可以有多种交错的页面类型。
从层次结构上看,文件由一个或多个行组组成。行组的每列恰好包含一个列块。列块包含一页或多页。
应同时阅读该文件和 Thrift 定义以了解其格式。
4-byte magic number "PAR1"
<Column 1 Chunk 1>
<Column 2 Chunk 1>
...
<Column N Chunk 1>
<Column 1 Chunk 2>
<Column 2 Chunk 2>
...
<Column N Chunk 2>
...
<Column 1 Chunk M>
<Column 2 Chunk M>
...
<Column N Chunk M>
File Metadata
4-byte length in bytes of file metadata (little endian)
4-byte magic number "PAR1"
在上面的示例中,该表中有 N 列,分为 M 行组。文件元数据包含所有列块起始位置的位置。有关元数据中包含的内容的更多详细信息可以在 Thrift 定义中找到。
文件元数据在数据之后写入,以允许单遍写入。
读者应首先读取文件元数据以找到他们感兴趣的所有列块。然后应按顺序读取列块。
元数据有两种类型:文件元数据和页眉元数据。所有 thrift 结构都使用 TCompactProtocol 进行序列化。
文件格式支持的类型尽可能少,重点关注类型对磁盘存储的影响。例如,存储格式未明确支持 16 位整数,因为它们被具有高效编码的 32 位整数覆盖。这降低了实现该格式的读取器和写入器的复杂性。类型有:
逻辑类型用于通过指定应如何解释基本类型来扩展 parquet 可用于存储的类型。这将原始类型集保持在最低限度,并重用 parquet 的高效编码。例如,字符串以带有 STRING 注释的基本类型 BYTE_ARRAY 存储。这些注释定义了如何进一步解码和解释数据。注释作为LogicalType
字段存储在文件元数据中,并记录在 LogicalTypes.md 中。
Parquet 在多个级别(例如列块、列索引和数据页)存储最小/最大统计信息。类型值的比较遵循以下规则:
每个逻辑类型都有指定的比较顺序。如果列用未知的逻辑类型注释,则统计信息可能无法用于修剪数据。逻辑类型的排序顺序记录在 LogicalTypes.md 页面中。
对于原始类型,适用以下规则:
布尔值 - 假、真
INT32、INT64 - 有符号比较。
FLOAT、DOUBLE - 对 NaN 和有符号零进行特殊处理的有符号比较。详细信息记录在ColumnOrder
联合的 Thrift 定义中。此处对其进行了总结,但 Thrift 定义被认为是权威的:
+0.0
写入最大统计字段。-0.0
写入最小值统计字段。为了在读取文件时向后兼容:
BYTE_ARRAY 和 FIXED_LEN_BYTE_ARRAY - 字典顺序无符号字节比较。
为了对嵌套列进行编码,Parquet 使用具有定义和重复级别的 Dremel 编码。定义级别指定在列的路径中定义了多少个可选字段。重复级别指定路径中的哪个重复字段具有重复值。最大定义和重复级别可以根据模式计算(即有多少嵌套)。这定义了存储级别所需的最大位数(级别是为列中的所有值定义的)。
支持 BIT_PACKED 和 RLE 两种级别编码。现在仅使用 RLE,因为它取代了 BIT_PACKED。
空值在定义级别中进行编码(游程编码)。 NULL 值不会编码在数据中。例如,在非嵌套模式中,具有 1000 个 NULL 的列将使用游程长度编码(0、1000 次)进行定义级别的编码,而不进行其他编码。
对于数据页,这 3 条信息在页眉之后被背靠背编码。数据页中不允许填充。为了我们有:
标头中指定的uncompressed_page_size
值适用于所有 3 个部分的组合。
数据页的编码值始终是必需的。根据模式定义,定义和重复级别是可选的。如果列不是嵌套的(即列的路径长度为 1),我们不会对重复级别进行编码(它将始终具有值 1)。对于所需的数据,将跳过定义级别(如果进行编码,它将始终具有最大定义级别的值)。
例如,在列非嵌套且需要的情况下,页面中的数据只是编码值。
Encodings.md 中描述了支持的编码
Compression.md 中描述了支持的压缩编解码器
列块由背靠背写入的页组成。这些页面共享一个公共标题,读者可以跳过他们不感兴趣的页面。页面的数据遵循标题,并且可以被压缩和/或编码。压缩和编码在页面元数据中指定。
列块可能部分或完全是字典编码的。这意味着字典索引保存在数据页中,而不是实际值。实际值存储在字典页中。请参阅 Encodings.md 中的详细信息。字典页必须放置在列块的第一个位置。一个列块中最多可以放置一个字典页。
此外,文件可以包含可选的列索引,以允许读者更有效地跳过页面。有关详细信息以及将这些添加到格式背后的原因,请参阅 PageIndex.md。
各种页面都可以单独进行校验和。这允许在 HDFS 文件级别禁用校验和,以更好地支持单行查找。校验和是使用标准 CRC32 算法(例如 GZip 中使用的)对页面的序列化二进制表示形式(不包括页面标头本身)进行计算的。
如果文件元数据损坏,文件就会丢失。如果列元数据损坏,则该列块会丢失(但其他行组中该列的列块没有问题)。如果页头损坏,则该块中的剩余页将丢失。如果页面内的数据损坏,该页面就会丢失。对于较小的行组,文件将更能抵抗损坏。
潜在的扩展:对于较小的行组,最大的问题是将文件元数据放在末尾。如果写入文件元数据时发生错误,则写入的所有数据将不可读。这可以通过每隔 N 行组写入文件元数据来解决。每个文件元数据都是累积的,并包括迄今为止写入的所有行组。将此与使用同步标记的 rc 或 avro 文件所使用的策略相结合,读取器可以恢复部分写入的文件。
该格式明确设计用于将元数据与数据分开。这允许将列拆分为多个文件,以及让单个元数据文件引用多个 parquet 文件。
格式中有很多地方可以兼容扩展:
Parquet Thrift IDL 保留每个 Thrift 结构的字段 ID 32767
用于扩展。该字段的 (Thrift) 类型始终是binary
。
apache/parquet-testing 包含一组用于测试目的的 Parquet 文件。
对问题发表评论和/或联系 parquet-dev 邮件列表,提出您的问题和想法。对此核心格式定义的更改在邮件列表上提出并进行了深入讨论。您可能还有兴趣为 Parquet-Java 子项目做出贡献,其中包含所有 Java 端实现和 API。请参阅 Parquet-Java 项目的“如何贡献”部分
我们要求自己和 Parquet 开发者社区遵守 Twitter OSS 所描述的行为准则:https://github.com/twitter/code-of-conduct/blob/master/code-of-conduct.md。
版权所有 2013 Twitter、Cloudera 和其他贡献者。
根据 Apache 许可证 2.0 版获得许可:http://www.apache.org/licenses/LICENSE-2.0