与其他格式相比,镶木地板格式的优缺点是什么?

What are the pros and cons of parquet format compared to other formats?

Apache Parquet 的特点是:

与 Avro、序列文件、RC 文件等相比,我想了解一下这些格式。我已经阅读过:How Impala Works with Hadoop File Formats,它提供了一些关于格式的见解,但我想知道如何以这些格式中的每一种格式访问数据和存储数据。实木复合地板与其他地板相比有何优势?

我认为我能描述的主要区别与面向记录和面向列的格式有关。面向记录的格式是我们都习惯的——文本文件、分隔格式,如 CSV、TSV。 AVRO 比那些稍微酷一点,因为它可以随时间改变模式,例如从记录中添加或删除列。各种格式(尤其是压缩)的其他技巧涉及一种格式是否可以拆分——也就是说,您能否从数据集中的任何地方读取一个记录块并且仍然知道它的模式?但这里有关于 Parquet 等柱状格式的更多详细信息。

Parquet 和其他列格式可以非常有效地处理常见的 Hadoop 情况。在一个设计良好的关系数据库中,tables(数据集)的列比您预期的要多得多是很常见的——一百或两百列并不罕见。之所以如此,是因为我们经常将 Hadoop 用作对关系格式的数据进行 非规范化 的地方——是的,您会得到很多重复的值,并且许多 table 都被压平成一个单一的一。但是查询变得容易得多,因为所有连接都已解决。还有其他优点,例如保留时间状态数据。所以无论如何,在 table 中包含大量列是很常见的。

假设有 132 列,其中一些是非常长的文本字段,每个不同的列一个接着一个,每条记录可能用掉 10K。

虽然从 SQL 的角度查询这些 table 很容易,但通常您会希望仅基于这数百条记录中的一小部分来获得一些 运行ge 的记录-加列。例如,您可能需要 2 月和 3 月销售额 > 500 美元的客户的所有记录。

要以行格式执行此操作,查询需要扫描数据集的每条记录。读取第一行,将记录解析为字段(列)并获取日期和销售列,如果满足条件则将其包含在结果中。重复。如果您有 10 年(120 个月)的历史记录,那么您正在阅读每条记录只是为了找到其中的 2 个月。当然,这是在年和月上使用分区的好机会,但即便如此,您还是要读取和解析这两个月每个 record/row 的 10K,只是为了确定客户的销售额是否 > 500 美元。

在列式格式中,记录的每一列(字段)都与同类的其他列一起存储,分布在磁盘上的许多不同块上——年份列在一起,月份列在一起,客户列员工手册(或其他长文本),以及所有其他使这些记录如此庞大的文件,它们都在磁盘上各自独立的位置,当然还有销售专栏。哎呀,日期和月份是数字,销售额也是数字——它们只是几个字节。如果我们只需要为每条记录读取几个字节来确定哪些记录与我们的查询匹配,那不是很好吗?列式存储来拯救!

即使没有分区,扫描满足我们查询所需的小字段也是超快的——它们都是按记录排序的,而且大小都相同,所以磁盘查找包含记录的数据检查要少得多.无需通读员工手册和其他长文本字段——只需忽略它们即可。因此,通过将列而不是行分组,您几乎总是可以扫描更少的数据。赢了!

但等等,它会变得更好。如果您的查询只需要知道这些值和更多值(假设 132 列中的 10 列)并且不关心那个员工手册列,那么一旦它选择了 return 的正确记录,它现在就会只需返回到呈现结果所需的 10 列,忽略我们数据集中 132 列中的其他 122 列。同样,我们跳过了很多阅读。

(注意:出于这个原因,在进行直接 t运行 变换时,柱状格式是一个糟糕的选择,例如,如果您将两个 table 全部连接成一个大的 ( ger) 保存为新 table 的结果集,无论如何源都将被完全扫描,因此在读取性能方面没有太多好处,并且因为列式格式需要记住更多关于位置的信息问题是,它们比类似的行格式使用更多的内存)。

柱状的另一个好处:数据是分散的。要获得单个记录,您可以让 132 个工作人员每个读取(和写入)数据 from/to 132 个数据块上的 132 个不同位置。支持并行化!

现在最重要的是:当压缩算法可以找到重复模式时,它会工作得更好。您可以将 AABBBBBBCCCCCCCCCCCCCCCC 压缩为 2A6B16C,但 ABCABCBCBCBCCCCCCCCCCCCCC 不会变得那么小(嗯,实际上,在这种情况下它会,但请相信我 :-))。所以再次,少读书。还有写作。

所以我们读取更少的数据来回答常见的查询,并行读取和写入可能会更快,并且压缩往往会更好。

当您的输入端很大并且您的输出是经过过滤的子集时,Columnar 很棒:从大到小很好。当输入和输出大致相同时,效果不佳。

但在我们的例子中,Impala 在 5、10、20 或 30 分钟内完成了我们旧的 Hive 查询 运行,并且大部分在几秒或一分钟内完成。

希望这至少有助于回答您的部分问题!

Tom 的回答非常详细和详尽,但您可能也对 this simple study Allstate Insurance 对 Parquet 与 Avro 的对比感兴趣,总结如下:

"Overall, Parquet showed either similar or better results on every test [than Avro]. The query-performance differences on the larger datasets in Parquet’s favor are partly due to the compression results; when querying the wide dataset, Spark had to read 3.5x less data for Parquet than Avro. Avro did not perform well when processing the entire dataset, as suspected."

A​​vro 是一种基于行的 Hadoop 存储格式。

Parquet 是 Hadoop 的一种基于列的存储格式。

如果您的用例通常在每个查询中扫描或检索一行中的所有字段,Avro 通常是最佳选择。

如果您的数据集有很多列,并且您的用例通常涉及处理这些列的子集而不是整个记录,Parquet 已针对此类工作进行了优化。

Source

选择正确的文件格式对于构建高性能数据应用程序很重要。 post 中概述的概念适用于 Pandas、Dask、Spark 和 Presto / AWS Athena。

列 p运行ing

Column p运行ing 是一个很大的性能改进,它对 column-based 文件格式(Parquet、ORC)是可能的,对 row-based 文件格式(CSV、Avro)是不可能的。

假设您有一个包含 100 列的数据集,并且想要将其中两列读入 DataFrame。如果数据存储在 Parquet 文件中,您可以使用 Pandas 执行此操作。

import pandas as pd

pd.read_parquet('some_file.parquet', columns = ['id', 'firstname'])

Parquet 是一种分栏文件格式,因此 Pandas 可以抓取与查询相关的列并可以跳过其他列。这是一个巨大的性能改进。

如果数据存储在CSV文件中,您可以这样读取:

import pandas as pd

pd.read_csv('some_file.csv', usecols = ['id', 'firstname'])

usecols 由于 CSV 文件格式的行性质,无法跳过整列。

Spark 不要求用户明确列出将在查询中使用的列。 Spark 建立一个执行计划,并会尽可能自动利用 p运行ing 列。当然,列 p运行ing 只有在底层文件格式是面向列的情况下才有可能。

人气

Spark 和 Pandas 有 built-in 个用于 CSV、JSON、ORC、Parquet 和文本文件的读取器写入器。他们没有 built-in 个 Avro 读者。

Avro 在 Hadoop 生态系统中很受欢迎。 Parquet 在 Hadoop 生态系统之外获得了巨大的吸引力。例如,Delta Lake 项目是基于 Parquet 文件构建的。

Arrow 是一个重要的项目,可以轻松地使用各种不同语言(C、C++、Go、Java、JavaScript、MATLAB)处理 Parquet 文件, Python, R, Ruby, Rust), 但不支持 Avro。 Parquet 文件更易于使用,因为它们受到许多不同项目的支持。

架构

Parquet 将文件架构存储在文件元数据中。 CSV 文件不存储文件元数据,因此需要向读者提供架构或需要推断架构。提供模式很乏味,推断模式很容易出错/代价高昂。

Avro 还将数据模式存储在文件本身中。在文件中包含模式是一个巨大的优势,也是现代数据项目不应依赖 JSON 或 CSV 的原因之一。

列元数据

Parquet 商店也 metadata statistics for each column and lets users add their own column metadata

最小/最大列值元数据允许 Dask & Spark 集群计算框架支持的 Parquet 谓词下推过滤。

以下是使用 PyArrow 获取列统计信息的方法。

import pyarrow.parquet as pq

parquet_file = pq.ParquetFile('some_file.parquet')
print(parquet_file.metadata.row_group(0).column(1).statistics)
<pyarrow._parquet.Statistics object at 0x11ac17eb0>
  has_min_max: True
  min: 1
  max: 9
  null_count: 0
  distinct_count: 0
  num_values: 3
  physical_type: INT64
  logical_type: None
  converted_type (legacy): NONE

复杂列类型

Parquet 允许复杂的列类型,如数组、字典和嵌套模式。没有一种可靠的方法可以将复杂类型存储为 CSV 等简单文件格式。

压缩

列式文件格式将相关类型存储在行中,因此更易于压缩。这个CSV文件比较难压缩。

first_name,age
ken,30
felicia,36
mia,2

当相关类型存储在同一行时,此数据更容易压缩:

ken,felicia,mia
30,36,2

Parquet 文件最常使用 Snappy 压缩算法进行压缩。 Snappy 压缩文件可拆分且可快速膨胀。大数据系统希望减少磁盘上的文件大小,但也希望快速膨胀苍蝇和 运行 分析查询。

文件的可变性质

Parquet 文件是不可变的,。 CSV 文件是可变的。

向 CSV 文件中添加一行很容易。您无法轻松地向 Parquet 文件添加一行。

数据湖

在大数据环境中,您将处理成百上千个 Parquet 文件。文件的磁盘分区、避免大文件和压缩小文件很重要。数据的最佳磁盘布局取决于您的查询模式。