Spark是否支持对S3中的镶木地板文件进行真正的列扫描?

时间:2016-09-26 12:37:40

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

Parquet数据存储格式的一大好处是it's columnar。如果我有一个包含数百列的'宽'数据集,但我的查询只涉及其中的一些,那么它可能只读取存储这几列的数据,并跳过其余列。

据推测,此功能的工作原理是在镶木地板文件的头部读取一些元数据,指示每列的文件系统上的位置。然后,读者可以在磁盘上搜索只读必要的列。

有谁知道spark的默认镶木地板阅读器是否正确地在S3上实现了这种选择性搜索?我认为it's supported by S3,但理论支持与正确利用该支持的实现之间存在很大差异。

4 个答案:

答案 0 :(得分:9)

这需要细分

  1. Parquet代码是否从spark获得谓词(是)
  2. 然后,使用Hadoop FileSystem seek() + read()readFully(position, buffer, length)来电,拼花是否会尝试选择性地仅读取这些列?是
  3. S3连接器是否将这些文件操作转换为高效的HTTP GET请求?在亚马逊EMR:是的。在Apache Hadoop中,您需要在类路径上使用hadoop 2.8并设置正确的spark.hadoop.fs.s3a.experimental.fadvise=random以触发随机访问。
  4. Hadoop 2.7及更早版本严重处理攻击性的seek(),因为它们始终启动GET偏移结束文件,对下一次搜索感到惊讶,必须中止该连接,重新打开新的TCP / HTTPS 1.1连接(慢,CPU重),重复执行。随机IO操作会对.csv.gz等大量加载造成伤害,但对于获得ORC / Parquet性能至关重要。

    你没有在Hadoop 2.7的hadoop-aws JAR上获得加速。如果你需要它,你需要更新hadoop * .jar和依赖项,或者从头开始针对Hadoop 2.8构建Spark

    请注意,Hadoop 2.8+还有一个很好的小功能:如果您在日志语句中调用S3A文件系统客户端上的toString(),它会打印出所有文件系统IO统计信息,包括在搜索中丢弃了多少数据,中止TCP连接& c。帮助您了解正在发生的事情。

    2018-04-13警告::不要尝试将Hadoop 2.8 + hadoop-aws JAR与hadoop-2.7 JAR集的其余部分一起放在类路径上,并期望看到任何加速。您将看到的只是堆栈跟踪。您需要更新所有hadoop JAR及其传递依赖项。

答案 1 :(得分:8)

免责声明:我没有明确的答案,也不想作为权威来源,但是花了一些时间在Spark 2.2+的镶木地板支持上,我希望我的回答能有所帮助我们都要接近正确的答案。

  

S3上的Parquet是否避免从S3中提取未使用列的数据,只检索所需的文件块,还是拉出整个文件?

我使用今天构建的Spark 2.3.0-SNAPSHOT master

parquet数据源格式由ParquetFileFormat处理,FileFormat

如果我更正,则阅读部分由buildReaderWithPartitionValues方法处理(覆盖FileFormat&#39}。

buildReaderWithPartitionValues仅在为所谓的输入RDD请求FileSourceScanExec物理运算符时使用,这些RDD实际上是在执行WholeStageCodegenExec时生成内部行的单个RDD。

话虽如此,我认为审查buildReaderWithPartitionValues所做的事情可能会让我们更接近最终答案。

当您查看the line时,您可以放心,我们已走上正轨。

  

//启用过滤器下推时尝试按下过滤器。

该代码路径取决于spark.sql.parquet.filterPushdown的{​​{1}} Spark属性。

  

spark.sql.parquet.filterPushdown 设置为true时启用Parquet过滤器下推优化。

这导致我们找到了镶嵌过滤器的is turned on by default iff 过滤器的定义。

if (pushed.isDefined) {
  ParquetInputFormat.setFilterPredicate(hadoopAttemptContext.getConfiguration, pushed.get)
}

稍后当代码回落到parquet-mr(而不是使用所谓的矢量化镶木地板解码读取器)时使用过滤器时,代码会变得更有趣。这是我不太了解的部分(除了我在代码中看到的内容)。

请注意,矢量化镶木地板解码阅读器由默认启用的spark.sql.parquet.enableVectorizedReader Spark属性控制。

提示:要了解if表达式的哪个部分,请为DEBUG记录器启用org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat日志记录级别。

要查看所有下推过滤器,您可以启用INFO记录器的org.apache.spark.sql.execution.FileSourceScanExec日志记录级别。你应该ParquetInputFormat.setFilterPredicate

INFO Pushed Filters: [pushedDownFilters]

我确实希望,如果它不是一个明确的答案,它已经帮助了一点,而且有人在我离开的地方捡到它,很快就会把它变成一个。 希望最后死去:)

答案 2 :(得分:1)

不,谓词下推不完全支持。当然,这取决于:

  • 特定用例
  • Spark版本
  • S3连接器类型和版本

为了检查您的特定用例,您可以在Spark中启用DEBUG日志级别,然后运行您的查询。然后,你可以看到是否有"寻找"在S3(HTTP)请求期间以及实际发送的请求数。像这样:

17/06/13 05:46:50 DEBUG wire: http-outgoing-1 >> "GET /test/part-00000-b8a8a1b7-0581-401f-b520-27fa9600f35e.snappy.parquet HTTP/1.1[\r][\n]" .... 17/06/13 05:46:50 DEBUG wire: http-outgoing-1 << "Content-Range: bytes 0-7472093/7472094[\r][\n]" .... 17/06/13 05:46:50 DEBUG wire: http-outgoing-1 << "Content-Length: 7472094[\r][\n]"

最近打开的问题报告的示例,由于Spark 2.1无法根据Parquet文件中存储的元数据计算数据集中所有行的COUNT(*)https://issues.apache.org/jira/browse/SPARK-21074

答案 3 :(得分:0)

spark的镶木地板阅读器就像任何其他的InputFormat一样,

  1. 没有任何inputFormat对S3有任何特殊之处。输入格式可以从LocalFileSystem,Hdfs和S3读取,没有为此完成特殊优化。

  2. Parquet InpuTFormat取决于您要求的列,将有选择地为您读取列。

  3. 如果你想确定(尽管下推谓词适用于最新的spark版本),请手动选择列并编写转换和操作,而不是依赖于SQL