镶木地板内件和火花

Parquet Internals & Spark

我有一个数据框,该数据框由运行特定日期的每日批处理创建,然后保存在 HDFS(Azure Data Lake Gen 2)中。

它是用这样的东西保存的

TradesWritePath="abfss://refined@"+datalakename+".dfs.core.windows.net/curated/clientscoredata/clientscoredatainput/Trades/" + TradeDatedt + "/Trades_" + tradedateInt + ".parquet"
tradesdf.write.mode("overwrite").parquet(TradesWritePath)

如您所见,我没有对数据帧进行分区,因为它只包含一个日期。

因此,作为示例,第一天的第一个文件将存储在文件夹中

Trades/2019/08/25

然后第二天,它将在文件夹中

Trades/2019/08/26

问题是,当所有数据都已放入后,日期的过滤谓词是否仍会被下推,HDFS 是否会知道在哪里找到数据而不是进行全面扫描?

或者即使我节省了一天时间,我仍然必须使用 Partition by option 来编写,这样 Spark 就可以在阅读时理解并将其推送到 HDFS 并且 HDFS 也知道在哪里可以找到它(而不是全扫描) ?

问题的下一部分是:

当我查看存储 parquet 文件的文件夹时,如果我必须减少文件数量,我会看到很多小的 "part-****.snappy.parquet files. I understand by reading some of the forum questions here that I have to use "repartition" 选项。 但问题是——有必要吗?我读到过多的小文件当然会影响性能,因此一种选择是将其保存为 128 MB 的块(如果我不确定数据将如何在下游使用,即目前哪些列),这样 HDFS 中的 NameNode 就不会负担过重,我们也不会有太大的文件。这也适用于这些 "snappy parquet partition files" 吗?

概念太多,我仍在努力寻找将这些数据帧存储为镶木地板的最佳解决方案,所以任何见解都将不胜感激。

如果数据存储为

,Spark 会知道从哪里获取数据
root/    
   date=ddmmyy/
   date=dd1mm1yy1/
...

= 符号很重要。谓词下推不能有任意目录结构。它必须采用上述格式。

在你的例子中

您需要存储类似

的内容
  root/
      Trades=2019/08/25
      Trades=2019/08/26

Spark 利用 Hive 分区发现机制来检测 table 中的分区。 Hive分区需要数据以特定的方式铺设。

进入你问题的下一部分。无论文件类型如何,将小文件保存在 HDFS 中都是非常糟糕的。是的,活泼的分区文件也是如此。您应该使用 repartitioncoalesce 函数使文件大小接近 128 MB。

namenode的职责是跟踪HDFS中的所有文件。 HDFS 中的块大小为 128 MB。因此,请尽量将 .parquet 文件大小保持在接近 128 MB 但不要更大。如果你保留更多,HDFS 将使用 2 个块来表示数据。

您不应创建自己的目录。

在编写 parquet 时使用 partition 按日期分区。它将自动处理目录创建,并且在读取时不会扫描完整的table。

对于你问题的第二部分,是的,想法是将每个分区保持在 128MB 左右,但老实说,这不会花费你太多,你可以将默认分区保持在 200。