我正在尝试使用Spark SQL编写parquet
文件。
默认情况下,Spark SQL支持gzip
,但它也支持其他压缩格式,如snappy
和lzo
。
这些压缩格式有什么区别?
我正在尝试使用Spark SQL编写parquet
文件。
默认情况下,Spark SQL支持gzip
,但它也支持其他压缩格式,如snappy
和lzo
。
这些压缩格式有什么区别?
压缩比: GZIP 压缩比较 Snappy 或 LZO 更高,但使用的 CPU 资源也更多。
一般用途: 对于不经常访问的冷数据,GZip 是一个不错的选择。 而对于经常访问的热数据,Snappy 或 LZO 更加合适。
Snappy 的性能通常优于 LZO。值得运行测试以查看是否存在显著差异。
可分割性: 如果需要将压缩数据分割,BZip2、LZO 和 Snappy 格式都是可分割的,但 GZip 不支持。
GZIP 相对于 Snappy 可以将数据压缩 30%,但读取 GZIP 数据时消耗的 CPU 是 Snappy 的两倍。
LZO 专注于在低 CPU 使用率下提供快速解压缩和更高的压缩比,但代价是更多的 CPU 消耗。
对于长期/静态存储,GZip 压缩仍然更好。
如果你可以承受更高的磁盘使用量以获得性能提升(更低的CPU使用率+可分割性),则应使用Snappy。
当Spark将默认压缩方式从GZIP切换为Snappy时,其原因是:
根据我们的测试,gzip解压速度非常慢(<100MB/s), 导致查询过程处于解压绑定状态。 Snappy可以在单核心上以~500MB/s的速度解压缩。
Snappy:
GZIP:
1)http://boristyukin.com/is-snappy-compressed-parquet-file-splittable/
根据以下数据,我认为在流媒体等需要重视写入时间延迟的场景之外,gzip
是胜出的。
需要记住的是,速度本质上就是计算成本。然而,云计算只需一次付费,而云存储则需要循环性的支付成本。权衡取舍取决于数据保留期。
我们使用大型和小型parquet
文件在Python中测试速度和大小。
结果(大文件,117 MB):
+----------+----------+--------------------------+
| snappy | gzip | snappy/gzip |
+-------+----------+----------+--------------------------+
| write | 1.62 ms | 7.65 ms | 4.7x faster |
+-------+----------+----------+--------------------------+
| size | 35484122 | 17269656 | 2x larger |
+-------+----------+----------+--------------------------+
| read | 973 ms | 1140 ms | 1.2x faster |
+-------+----------+----------+--------------------------+
结果(小文件,4 KB,鸢尾花数据集):
+---------+---------+--------------------------+
| snappy | gzip | snappy/gzip |
+-------+---------+---------+--------------------------+
| write | 1.56 ms | 2.09 ms | 1.3x faster |
+-------+---------+---------+--------------------------+
| size | 6990 | 6647 | 5.2% smaller |
+-------+---------+---------+--------------------------+
| read | 3.22 ms | 3.44 ms | 6.8% slower |
+-------+---------+---------+--------------------------+
small_file.ipynb
import os, sys
import pyarrow
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(
data= np.c_[iris['data'], iris['target']],
columns= iris['feature_names'] + ['target']
)
# ========= WRITE =========
%timeit df.to_parquet(path='iris.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.56 ms
%timeit df.to_parquet(path='iris.parquet.gzip', compression='snappy', engine='pyarrow', index=True)
# 2.09 ms
# ========= SIZE =========
os.stat('iris.parquet.snappy').st_size
# 6990
os.stat('iris.parquet.gzip').st_size
# 6647
# ========= READ =========
%timeit pd.read_parquet(path='iris.parquet.snappy', engine='pyarrow')
# 3.22 ms
%timeit pd.read_parquet(path='iris.parquet.gzip', engine='pyarrow')
# 3.44 ms
large_file.ipynb
import os, sys
import pyarrow
import pandas as pd
df = pd.read_csv('file.csv')
# ========= WRITE =========
%timeit df.to_parquet(path='file.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.62 s
%timeit df.to_parquet(path='file.parquet.gzip', compression='gzip', engine='pyarrow', index=True)
# 7.65 s
# ========= SIZE =========
os.stat('file.parquet.snappy').st_size
# 35484122
os.stat('file.parquet.gzip').st_size
# 17269656
# ========= READ =========
%timeit pd.read_parquet(path='file.parquet.snappy', engine='pyarrow')
# 973 ms
%timeit pd.read_parquet(path='file.parquet.gzip', engine='pyarrow')
# 1.14 s
我同意第一个答案(@Mark Adler)并提供一些研究信息[1],但我不同意第二个答案(@Garren S)[2]。也许Garren误解了问题,因为: [2] Parquet支持所有支持的编解码器分割:在HDFS中使用Spark时,是否可以将gzip压缩的Parquet文件分割? ,Tom White的《Hadoop权威指南》第四版,第5章:Hadoop I/O,第106页。 [1] 我的研究: 源数据-205 GB。文本(分隔字段),未压缩。 输出数据:
<!DOCTYPE html>
<html>
<head>
<style>
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<table style="width:100%">
<tr>
<th></th>
<th>time of computing, hours</th>
<th>volume, GB</th>
</tr>
<tr>
<td>ORC with default codec</td>
<td>3-3,5</td>
<td>12.3</td>
</tr>
<tr>
<td>Parquet with GZIP</td>
<td>3,5-3,7</td>
<td>12.9</td>
</tr>
<tr>
<td>Parquet with SNAPPY</td>
<td>2,5-3,0</td>
<td>60.4</td>
</tr>
</table>
</body>
</html>
使用Hive在由2个m4.16xlarge组成的EMR上执行了转换。 转换-选择所有字段并按多个字段排序。 当然,这项研究并不标准,但至少在一定程度上展示了真实的比较。使用其他数据集和计算结果可能会有所不同。