与其他格式相比,Apache Parquet格式有哪些优缺点?

205
Apache Parquet的一些特点包括:
- 自描述性 - 列式存储格式 - 与编程语言无关
与Apache Avro、Sequence Files、RC File等相比,我想了解这些格式的概述。我已经阅读了《如何使用Hadoop文件格式进行Impala工作》(链接1),它对这些格式提供了一些见解,但我想了解每种格式中数据的访问和存储是如何进行的。Parquet相比其他格式有什么优势?

4
这份演示文稿中提供了一个很好的总结:[链接](http://www.slideshare.net/StampedeCon/choosing-an-hdfs-data-storage-format-avro-vs-parquet-and-more-stampedecon-2015),涵盖了选择HDFS数据存储格式 Avro vs Parquet 等方面的内容。 - Dominik
@ani-menon 链接已失效。 - Sajjad Hossain
@SajjadHossain 已更新。 - Ani Menon
5个回答

383

我认为可以描述的主要区别是基于记录和基于列的数据格式。 基于记录的格式是我们都熟悉的 - 文本文件,如CSV,TSV等分隔符格式。 AVRO比它们稍微更好,因为它可以随时间改变模式,例如从记录中添加或删除列。其他各种格式的技巧(特别是包括压缩)涉及格式是否可以拆分 - 也就是说,您能否从数据集的任何地方读取一块记录并仍然知道它的模式?但以下更详细介绍了像 Parquet 这样的列格式。

Parquet 和其他列格式可以高效处理一个常见的 Hadoop 情况。通常会有比良好设计的关系数据库中预期得到的列数多得多的表(数据集) - 有一百个或两百个列并不罕见。因为我们经常使用 Hadoop 作为去规范化来自关系格式的数据的位置 - 是的,你会得到许多重复值和许多表全部展开成单个表格。但由于所有的连接都已解决,因此查询变得容易得多。还有其他优点,例如保留状态-时间数据。因此,在表中有大量列是很常见的。

假设有 132 列,其中一些是非常长的文本字段,每个不同的列依次使用大约 10K 的记录。

虽然从 SQL 角度来看查询这些表是很容易的,但通常您只想基于其中少数几个百列获取某个记录范围。例如,您可能希望获取销售额> $500 的客户在二月和三月之间的所有记录。

要按行格式执行查询,需要扫描数据集的每个记录。读取第一行,将记录解析为字段(列),获取日期和销售列,如果满足条件,则将其包含在结果中。重复这个过程。如果你有10年(120个月)的历史记录,为了找到其中的2个月,你需要读取每一个记录。当然,这是使用年份和月份分区的好机会,但即使如此,为了找出客户销售额> $500的那两个月,你仍然需要读取和解析每个记录/行的10K字节。
在列格式中,记录的每个列(字段)都与其它相同种类的列一起存储在磁盘的许多不同块中。年份列一起,月份列一起,客户员工手册(或其他长文本)列一起,以及使那些记录变得如此巨大的所有其他列都在磁盘上自己独立的位置上,当然还有销售列。日期和月份是数字,销售也是数字-它们只是几个字节。如果我们只需要读取每个记录的几个字节来确定哪些记录符合我们的查询条件,那不是很好吗?列式存储解救了我们!
即使没有分区,扫描满足我们查询所需的小字段非常快-它们按记录顺序排序,大小都相同,因此磁盘仅需查找包含的记录并检查它们所需的数据量就少得多。没有必要阅读员工手册和其他长文本领域-只需忽略它们。因此,通过将列分组在一起而不是分组在行中,你几乎总是可以扫描更少的数据。赢了!
但等等,情况变得更好了。如果你的查询只需要知道那些值以及另外几个值(比如说132个列中的10个),并且不关心那个员工手册列,一旦它选择了正确的记录返回,现在它只需要回到它需要呈现结果的这10列,忽略我们数据集中的其他122列中的内容。再次跳过了很多读取。(注意:因此,在进行直接转换时,列格式是一个糟糕的选择,例如,如果您将两个表连接成一个大结果集并将其保存为新表,则源将完全被扫描,因此在读取性能方面没有太多好处,并且由于列格式需要记住更多关于所在位置的信息,它们使用比类似行格式更多的内存)。

列式存储的另一个好处是数据分散。要获取单个记录,您可以有132个工作线程从132个不同的位置读取(和写入)数据。赞成并行化!

现在到了关键的一步:当压缩算法能够找到重复模式时,它会工作得更好。您可以将压缩成<2A6B16C>,但不会变小(嗯,实际上,在这种情况下它会变小,但相信我 :-))。再次减少阅读。还有写作。

因此,我们读取的数据量要少得多,以回答常见查询,可能更容易并行读取和写入,并且压缩倾向于工作得更好。

当输入方很大,输出为过滤后的子集时,列式存储非常好。 从大到小很好。当输入和输出大致相同时,效益不太明显。

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


7
非常好。谢谢您。这是一篇非常有用的摘要,许多Apache项目文档都缺少。您提到:“小字段…按记录顺序排列”。假设我有一个简单的表,其中包含userid:long和age:int,并且想查找某个年龄之间的所有用户。在这里,我有两列。我需要指定索引的顺序,还是所有列都可以高效地建立索引? - user48956
1
如果我在时间序列中使用Parquet会怎样?几个列(100+),每个列都是具有不同频率(100hz到0.25 hz)的传感器数据。这是否是一个明智的决定? - guilhermecgs

80

Avro 是 Hadoop 的基于行的存储格式。

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

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

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

来源


32

汤姆的回答非常详细和全面,但您可能也会对Allstate Insurance在这里总结的关于Parquet与Avro之间的简单研究感兴趣

“总体而言,Parquet在每个测试中表现出与或更好的结果[比Avro]。Parquet在大型数据集上的查询性能差异在某种程度上归因于压缩结果; 在查询宽度数据集时,Spark必须读取Parquet比Avro少3.5倍的数据。Avro在处理整个数据集时表现不佳,正如我们所预料的那样。”


26
选择正确的文件格式对于构建高性能数据应用程序非常重要。本文中概述的概念适用于Pandas、Dask、Spark和Presto / AWS Athena。
列剪枝
列剪枝是一种针对基于列的文件格式(Parquet、ORC)的重大性能改进,而在基于行的文件格式(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构建执行计划,并在可能的情况下自动利用列剪枝。当然,只有在底层文件格式是面向列时,才能进行列剪枝。

流行度

Spark和Pandas内置了CSV、JSON、ORC、Parquet和文本文件的读写器。它们没有内置Avro的读取器。

Avro在Hadoop生态系统内很受欢迎。Parquet已经在Hadoop生态系统外获得了重要进展。例如,Delta Lake项目正在基于Parquet文件构建。

Arrow是一个重要的项目,使得使用各种不同语言(C、C++、Go、Java、JavaScript、MATLAB、Python、R、Ruby、Rust)与Parquet文件一起工作变得容易,但不支持Avro。由于Parquet文件受到许多不同项目的支持,因此更容易使用。

模式

Parquet将文件模式存储在文件元数据中。CSV文件不存储文件元数据,因此读取器需要提供模式或推断模式。提供模式很繁琐,推断模式容易出错/代价高昂。

Avro也将数据模式存储在文件本身中。在文件中具有模式是一个巨大的优势,这也是为什么现代数据项目不应该依赖于JSON或CSV的原因之一。

列元数据

Parquet存储每列的元数据统计信息并且允许用户添加自己的列元数据

最小/最大列值元数据允许进行Parquet谓词下推过滤,这受到Dask和Spark集群计算框架的支持。

以下是如何使用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文件。 文件的磁盘分区,避免大文件和压缩小文件非常重要。 数据的最佳磁盘布局取决于您的查询模式。


0
我正在研究不同的文件格式,如Avro、ORC、Parquet、JSON和部分文件,以在大数据中保存数据。我发现Parquet文件在许多方面都更好。
以下是我的研究结果: 将数据存储为Parquet文件的优点:
  1. 数据安全性,因为数据不可读
  2. 低存储消耗
  3. 通过列存储提高了数据读取效率,最小化延迟。
  4. 支持高级嵌套数据结构。针对处理大量数据的查询进行了优化
  5. Parquet文件可以进一步压缩。
使用实时测试数据得出以下结果: 13,193,045条记录的表通过Sqoop导入时,输出常规文件大小为8.6 GB。但将相同的13,193,045条记录作为Parquet文件导入后,输出文件只有1.6 GB,存储节省约500%。
此外,我们可以通过引用此Parquet文件创建Hive外部表,并直接从Parquet文件中处理数据。

虽然,将sqoop导入作为常规文件所需的时间仅为3分钟,而对于Parquet文件,它需要6分钟作为4个部分文件。我很惊讶地看到在存储parquet文件时出现了这种时间差异。这方面的时间需要更多的研究。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接