- 自描述性 - 列式存储格式 - 与编程语言无关
与Apache Avro、Sequence Files、RC File等相比,我想了解这些格式的概述。我已经阅读了《如何使用Hadoop文件格式进行Impala工作》(链接1),它对这些格式提供了一些见解,但我想了解每种格式中数据的访问和存储是如何进行的。Parquet相比其他格式有什么优势?
我认为可以描述的主要区别是基于记录和基于列的数据格式。 基于记录的格式是我们都熟悉的 - 文本文件,如CSV,TSV等分隔符格式。 AVRO比它们稍微更好,因为它可以随时间改变模式,例如从记录中添加或删除列。其他各种格式的技巧(特别是包括压缩)涉及格式是否可以拆分 - 也就是说,您能否从数据集的任何地方读取一块记录并仍然知道它的模式?但以下更详细介绍了像 Parquet 这样的列格式。
Parquet 和其他列格式可以高效处理一个常见的 Hadoop 情况。通常会有比良好设计的关系数据库中预期得到的列数多得多的表(数据集) - 有一百个或两百个列并不罕见。因为我们经常使用 Hadoop 作为去规范化来自关系格式的数据的位置 - 是的,你会得到许多重复值和许多表全部展开成单个表格。但由于所有的连接都已解决,因此查询变得容易得多。还有其他优点,例如保留状态-时间数据。因此,在表中有大量列是很常见的。
假设有 132 列,其中一些是非常长的文本字段,每个不同的列依次使用大约 10K 的记录。
虽然从 SQL 角度来看查询这些表是很容易的,但通常您只想基于其中少数几个百列获取某个记录范围。例如,您可能希望获取销售额> $500 的客户在二月和三月之间的所有记录。
要按行格式执行查询,需要扫描数据集的每个记录。读取第一行,将记录解析为字段(列),获取日期和销售列,如果满足条件,则将其包含在结果中。重复这个过程。如果你有10年(120个月)的历史记录,为了找到其中的2个月,你需要读取每一个记录。当然,这是使用年份和月份分区的好机会,但即使如此,为了找出客户销售额> $500的那两个月,你仍然需要读取和解析每个记录/行的10K字节。列式存储的另一个好处是数据分散。要获取单个记录,您可以有132个工作线程从132个不同的位置读取(和写入)数据。赞成并行化!
现在到了关键的一步:当压缩算法能够找到重复模式时,它会工作得更好。您可以将压缩成<2A6B16C>,但不会变小(嗯,实际上,在这种情况下它会变小,但相信我 :-))。再次减少阅读。还有写作。
因此,我们读取的数据量要少得多,以回答常见查询,可能更容易并行读取和写入,并且压缩倾向于工作得更好。
当输入方很大,输出为过滤后的子集时,列式存储非常好。 从大到小很好。当输入和输出大致相同时,效益不太明显。
但在我们的例子中,Impala使用了我们旧的Hive查询,这些查询运行时间为5、10、20或30分钟,并在几秒钟或一分钟内完成了大部分查询。
Avro 是 Hadoop 的基于行的存储格式。
Parquet 是 Hadoop 的基于列的存储格式。
如果您的用例通常在每个查询中扫描或检索一行中的所有字段,则 Avro 通常是最佳选择。
如果您的数据集有许多列,并且您的用例通常涉及处理这些列的子集而不是整个记录,则 Parquet 为此类工作进行了优化。
汤姆的回答非常详细和全面,但您可能也会对Allstate Insurance在这里总结的关于Parquet与Avro之间的简单研究感兴趣:
“总体而言,Parquet在每个测试中表现出与或更好的结果[比Avro]。Parquet在大型数据集上的查询性能差异在某种程度上归因于压缩结果; 在查询宽度数据集时,Spark必须读取Parquet比Avro少3.5倍的数据。Avro在处理整个数据集时表现不佳,正如我们所预料的那样。”
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文件。 文件的磁盘分区,避免大文件和压缩小文件非常重要。 数据的最佳磁盘布局取决于您的查询模式。
虽然,将sqoop导入作为常规文件所需的时间仅为3分钟,而对于Parquet文件,它需要6分钟作为4个部分文件。我很惊讶地看到在存储parquet文件时出现了这种时间差异。这方面的时间需要更多的研究。