首页 > 解决方案 > 镶木地板内部和火花

问题描述

我有一个由每日批处理创建的数据帧,该批处理在特定日期运行,然后保存在 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)

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

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

交易/2019/08/25

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

交易/2019/08/26

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

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

问题的下一部分是:

当我查看存储 parquet 文件的文件夹时,我看到很多小的“part-****.snappy.parquet 文件。我通过阅读这里的一些论坛问题了解到我必须使用“重新分区”如果我必须减少文件数量的选项。但问题是 - 是否有必要?我读到太多的小文件当然会影响性能,所以一种选择可能是将其保存为 128 MB 的块(如果我我不确定数据将如何在下游使用(目前意味着哪些列),这样 HDFS 中的 NameNode 不会负担过重,我们也没有太大的文件。这是否也适用于这些“活泼的镶木地板分区文件” “ 还?

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

标签: apache-sparkhdfsparquet

解决方案


如果数据存储为,Spark 会知道从哪里获取数据

root/    
   date=ddmmyy/
   date=dd1mm1yy1/
...

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

在你的例子中

你需要存储类似的东西

  root/
      Trades=2019/08/25
      Trades=2019/08/26

Spark 利用 hive 分区发现机制来检测表中的分区。Hive 分区需要以特定方式放置数据。

来到你问题的下一部分。无论文件的类型如何,保留小文件HDFS都是非常糟糕的。是的,对于 snappy 分区文件来说确实如此。您应该使用repartitionorcoalesce函数来保持文件大小接近 128 MB。

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


推荐阅读