Parquet数据存储格式的一大好处是it's columnar。如果我有一个包含数百列的'宽'数据集,但我的查询只涉及其中的一些,那么它可能只读取存储这几列的数据,并跳过其余列。
据推测,此功能的工作原理是在镶木地板文件的头部读取一些元数据,指示每列的文件系统上的位置。然后,读者可以在磁盘上搜索只读必要的列。
有谁知道spark的默认镶木地板阅读器是否正确地在S3上实现了这种选择性搜索?我认为it's supported by S3,但理论支持与正确利用该支持的实现之间存在很大差异。
答案 0 :(得分:9)
这需要细分
FileSystem
seek()
+ read()
或readFully(position, buffer, length)
来电,拼花是否会尝试选择性地仅读取这些列?是spark.hadoop.fs.s3a.experimental.fadvise=random
以触发随机访问。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中启用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一样,
没有任何inputFormat对S3有任何特殊之处。输入格式可以从LocalFileSystem,Hdfs和S3读取,没有为此完成特殊优化。
Parquet InpuTFormat取决于您要求的列,将有选择地为您读取列。
如果你想确定(尽管下推谓词适用于最新的spark版本),请手动选择列并编写转换和操作,而不是依赖于SQL