如何在hdfs中设置文件的行组大小?

时间:2018-11-15 17:43:03

标签: hadoop hdfs parquet parquet-mr

我正在对hdfs中的块大小(dfs.block.size)和行组大小(parquet.block.size)进行一些实验。

我在hdfs中有大量数据,我想复制具有各种块大小和行组大小的数据以进行测试。我可以使用以下不同的块大小复制数据:

hdfs dfs -D dfs.block.size=67108864 -D parquet.block.size=67108864 -cp /new_sample_parquet /new_sample_parquet_64M

但是只有dfs.block.size被更改。我正在验证hdfs dfs -stat的块大小,以及parquet-tools meta的行组大小。实际上,如果我将parquet.block.size替换为blah.blah.blah,则效果相同。我什至进入spark-shell并使用

手动设置parquet.block.size属性
sc.hadoopConfiguration.setInt("parquet.block.size", 67108864).

我正在使用hadoop 3.1.0。我从here获得了parquet.block.size的属性名称。

这是我的尝试输出的前10行

row group 1:                    RC:4140100 TS:150147503 OFFSET:4
row group 2:                    RC:3520100 TS:158294646 OFFSET:59176084
row group 3:                    RC:880100 TS:80122359 OFFSET:119985867
row group 4:                    RC:583579 TS:197303521 OFFSET:149394540
row group 5:                    RC:585594 TS:194850776 OFFSET:213638039
row group 6:                    RC:2620100 TS:130170698 OFFSET:277223867
row group 7:                    RC:2750100 TS:136761819 OFFSET:332088066
row group 8:                    RC:1790100 TS:86766854 OFFSET:389772650
row group 9:                    RC:2620100 TS:125876377 OFFSET:428147454
row group 10:                   RC:1700100 TS:83791047 OFFSET:483600973

您可以看到,TS(总大小)比64MB(67108864字节)大得多。

我目前的理论:

我正在使用spark-shell:

sc.hadoopConfiguration.setInt("parquet.block.size", 67108864)
val a = spark.read.parquet("my_sample_data")
a.rdd.getNumPartitions // 1034
val s = a.coalesce(27)
s.write.format("parquet").mode("Overwrite").options(Map("dfs.block.size" -> "67108864")).save("/my_new_sample_data")

所以也许是因为我的输入数据已经有1034个分区。我真的不确定。我的数据每行大约有118列。

1 个答案:

答案 0 :(得分:1)

parquet.block.size属性仅影响Parquet编写器。另一方面,hdfs dfs -cp命令将复制文件而不管其内容如何。因此,parquet.block.size将忽略hdfs dfs -cp属性。

想象一下您有一个应用程序,该应用程序以JPG或PNG格式拍摄屏幕快照,具体取决于配置文件。您可以使用cp命令来复制这些屏幕截图。自然,即使您在配置文件中更改了所需的图像格式,cp命令也将始终以原始文件的图像格式创建输出文件,而与配置文件无关。配置文件仅由屏幕截图应用程序使用,cp不使用。 parquet.block.size属性也是如此。

可以更改块大小的方法是重写文件。您提到自己有spark-shell。使用它来通过发出

来重写Parquet文件
sc.hadoopConfiguration.setInt("parquet.block.size", 67108864)
var df = spark.read.parquet("/path/to/input.parquet")
df.write.parquet("/path/to/output")

更新:由于您在下面的评论中提到它不适用于您,因此我做了一个实验,并在下面发布了会话记录:

$ spark-shell
scala> sc.hadoopConfiguration.setInt("parquet.block.size", 200000)
scala> var df = spark.read.parquet("/tmp/infile.parquet")
df: org.apache.spark.sql.DataFrame = [field0000: binary, field0001: binary ... 78 more fields]
scala> df.write.parquet("/tmp/200K")
scala> df.write.format("parquet").mode("Overwrite").options(Map("parquet.block.size" -> "300000")).save("/tmp/300K")
scala> :quit
$ hadoop fs -copyToLocal /tmp/{200K,300K} /tmp
$ parquet-tools meta /tmp/infile.parquet | grep "row group" | head -n 3
row group 1:  RC:4291 TS:5004800 OFFSET:4
row group 2:  RC:3854 TS:4499360 OFFSET:5004804
row group 3:  RC:4293 TS:5004640 OFFSET:10000000
$ parquet-tools meta /tmp/200K/part-00000-* | grep "row group" | head -n 3
row group 1:   RC:169 TS:202080 OFFSET:4
row group 2:   RC:168 TS:201760 OFFSET:190164
row group 3:   RC:169 TS:203680 OFFSET:380324
$ parquet-tools meta /tmp/300K/part-00000-* | grep "row group" | head -n 3
row group 1:   RC:254 TS:302720 OFFSET:4
row group 2:   RC:255 TS:303280 OFFSET:284004
row group 3:   RC:263 TS:303200 OFFSET:568884

通过查看TS值,您可以看到输入文件的行组大小为4.5-5M,输出文件的行组大小分别为200K和300K。这表明使用sc.hadoopConfiguration设置的值成为“默认值”,而您在下面的注释中提到的涉及df.options的其他方法将覆盖此默认值。

更新2 :现在您已经发布了输出,现在可以看到发生了什么。在您的情况下,正在进行压缩,从而增加了适合行组的数据量。行组大小适用于压缩数据,但TS显示未压缩数据的大小。但是,您可以通过减去行的起始偏移量来推断行组的大小。例如,第一行组的压缩大小为59176084-4 = 59176080字节或更小(因为也可以进行填充)。我将您的结果复制到计算机上的/tmp/rowgroups.dat中,并通过发出以下命令来计算行组大小:

$ cat /tmp/rowgroups.dat | sed 's/.*OFFSET://' | numinterval
59176080
60809783
29408673
64243499
63585828
54864199
57684584
38374804
55453519

numinterval命令在Ubuntu的num-utils软件包中。)如您所见,所有行组都小于您指定的行组大小。 (之所以没有精确指定尺寸,是因为PARQUET-1337。)

相关问题