Spark-读取许多小的镶木地板文件之前,需要获取每个文件的状态

时间:2018-11-02 17:18:24

标签: scala apache-spark amazon-s3 apache-spark-sql parquet

我有成千上万个较小的镶木地板文件,我希望定期通过Spark阅读。我的应用程序运行,但是在使用执行程序节点读取文件之前,驱动程序节点似乎正在获取每个文件的状态。我读了一点,这是推断架构和分区所必需的。我尝试这样提供它们:

sparkSession.baseRelationToDataFrame(
  DataSource
    .apply(
      sparkSession,
      paths = paths, // List of thousands of parquet files in S3
      partitionColumns = Seq("my_join_column"),
      userSpecifiedSchema = Some(schema),
      className = "parquet",
      options = Seq().toMap
    )
    .resolveRelation(checkFilesExist = false)
)

但是,即使提供架构列和分区列,也需要一些时间。在仔细研究了resolveRelation代码之后,看起来仍然需要查询每个文件的状态才能构建InMemoryFileIndex

有什么办法可以解决这个问题?

我正在使用spark-sql 2.3.1

1 个答案:

答案 0 :(得分:6)

在当前的Spark体系结构中,没有很好的方法来避免此问题。

前一阵子,我与一些Spark提交者合作进行了LazyBaseRelation设计,该设计可能会延迟发现文件信息,直到必须知道数据源的分区数量(而不仅仅是模式)为止。在必须执行某项操作之前,从技术上讲是没有必要的,但是我们从未完成工作。即使这样,当需要执行一个动作时,您还是会受到打击。

有四种实用的方法可以加快初始文件的发现速度:

  1. 使用大型群集,因为文件发现的某些方面是分布式的。在某些环境中,一旦发现完成,您就可以缩小集群的规模。
  2. 之前进行初始发现,以便希望在需要时可以使用它们。在数百万个具有三个分区级别的大型Parquet文件中,有PB级的数据。我们使用计划的作业来刷新内存文件索引。
  3. 如果您使用的是Databricks,请使用Delta的OPTIMIZE将Parquet小文件合并为更少,更大的文件。请注意,达美航空需要额外付费。
  4. 由您自己实施OPTIMIZE的等效项,重写数据的子集。是否可以轻松完成此操作取决于访问模式:您必须考虑幂等性和一致性。

完成初始发现后,缓存内存文件列表是您最好的朋友。有两种方法可以做到:

  • 通过将数据注册为外部表来使用元存储。是否可以轻松完成此操作取决于数据更新模式。如果数据是自然分区的,则可以使用DDL添加分区,并且可以轻松实现上述策略(4)。

  • 构建自己的表管理器。这是我们所做的,因为元存储实现对模式演变有不可接受的限制。您必须决定范围:驱动程序/ JVM-和SparkSession是两个显而易见的选择。

祝你好运!