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

Posted

技术标签:

【中文标题】与其他格式相比,镶木地板格式的优缺点是啥?【英文标题】:What are the pros and cons of parquet format compared to other formats?与其他格式相比,镶木地板格式的优缺点是什么? 【发布时间】:2016-08-17 18:15:50 【问题描述】:

Apache Parquet 的特点是:

自我描述 列格式 与语言无关

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

【问题讨论】:

可以在此演示文稿中找到一个很好的摘要:link @ani-menon 链接失效了。 @SajjadHossain 已更新。 【参考方案1】:

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

Parquet 和其他列格式可以非常有效地处理常见的 Hadoop 情况。在精心设计的关系数据库中,表(数据集)的列数通常比您预期的多得多——一百或两百列并不罕见。之所以如此,是因为我们经常使用 Hadoop 作为从关系格式中去规范化数据的地方——是的,你会得到很多重复的值,并且很多表都被扁平化为一个表。但是由于所有连接都已计算出来,因此查询变得容易得多。还有其他优点,例如保留时间状态数据。所以无论如何,在一个表中有一大堆列是很常见的。

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

虽然从 SQL 的角度查询这些表很容易,但您通常希望仅根据这数百列中的几列来获取一些记录范围。例如,您可能需要销售额 > 500 美元的客户在 2 月和 3 月的所有记录。

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

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

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

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

(注意:出于这个原因,在进行直接转换时,列格式是一个糟糕的选择,例如,如果您将所有两个表连接到一个大(ger)结果集中,然后将其保存为新表,无论如何,源都会被完全扫描,因此读取性能并没有太多好处,而且由于列格式需要记住更多关于内容的位置,它们比类似的行格式使用更多的内存。

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

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

因此,我们读取的数据要少得多来回答常见查询,并行读取和写入可能会更快,而且压缩往往会更好地工作。

当您的输入端很大并且您的输出是经过过滤的子集时,列式非常好:从大到小非常好。当输入和输出大致相同时,效果就不那么好了。

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

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

【讨论】:

优秀。谢谢你。是许多 apache 项目文档中缺少的一个非常有用的摘要。你提到:“小字段......都是按记录排序的”。假设我有一个简单的 userid:long 和 age:int 表,并且想要找到某个年龄之间的所有用户。这里我有两列。我是否需要指定排序索引的时间,还是所有列都可以有效索引? 如果我在时间序列中使用镶木地板怎么办?几列(100+),每列一个不同频率(100hz到0.25hz)的传感器数据。这是一个明智的决定吗?【参考方案2】:

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

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

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

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

Source

【讨论】:

【参考方案3】:

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

“总体而言,Parquet 在每次测试中都显示出相似或更好的结果 [比 Avro]。Parquet 在较大数据集上的查询性能差异部分是由于压缩结果;在查询宽数据集时,Spark 必须Parquet 读取的数据比 Avro 少 3.5 倍。正如怀疑的那样,Avro 在处理整个数据集时表现不佳。"

【讨论】:

【参考方案4】:

选择正确的文件格式对于构建高性能数据应用程序很重要。本文中概述的概念适用于 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 文件,但没有t 支持 Avro。 Parquet 文件更易于使用,因为它们受到许多不同项目的支持。

架构

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

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

列元数据

Parquet 商店 metadata statistics for each column 和 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 文件是不可变的,as described here。 CSV 文件是可变的。

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

数据湖

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

【讨论】:

以上是关于与其他格式相比,镶木地板格式的优缺点是啥?的主要内容,如果未能解决你的问题,请参考以下文章

镶木地板格式的模式演变

我是不是需要将文件放入熊猫数据框中以放入镶木地板格式?

将镶木地板文件加载到红移时如何格式化时间戳字段?

从多个火花工人以镶木地板格式保存

如何将镶木地板格式的特定列加载到 Redshift 光谱中?

将火花数据帧写入镶木地板格式时出现内存不足错误