我正在阅读镶木地板数据,我看到它列出了驱动程序端的所有目录
Listing s3://xxxx/defloc/warehouse/products_parquet_151/month=2016-01 on driver
Listing s3://xxxx/defloc/warehouse/products_parquet_151/month=2014-12 on driver
我在where子句中指定了month = 2014-12。 我尝试过使用spark sql和数据框架API,看起来两者都没有修剪分区。
使用Dataframe API
df.filter("month='2014-12'").show()
使用Spark SQL
sqlContext.sql("select name, price from products_parquet_151 where month = '2014-12'")
我在版本1.5.1,1.6.1和2.0.0
上尝试了上述内容答案 0 :(得分:2)
Spark需要首先在驱动程序中加载分区metdata,以了解分区是否存在。 Spark将查询目录以查找现有分区,以了解它是否可以在扫描数据期间修剪分区。
我在Spark 2.0上测试了这个,你可以在日志消息中看到。
16/10/14 17:23:37 TRACE ListingFileCatalog: Listing s3a://mybucket/reddit_year on driver
16/10/14 17:23:37 TRACE ListingFileCatalog: Listing s3a://mybucket/reddit_year/year=2007 on driver
这并不意味着我们正在扫描每个分区中的文件,但Spark会存储分区的位置以供将来查询。
您可以在分区过滤器中看到实际传递的日志以修剪数据:
16/10/14 17:23:48 TRACE ListingFileCatalog: Partition spec: PartitionSpec(StructType(StructField(year,IntegerType,true)),ArrayBuffer(PartitionDirectory([2012],s3a://mybucket/reddit_year/year=2012), PartitionDirectory([2010],s3a://mybucket/reddit_year/year=2010), ...PartitionDirectory([2015],s3a://mybucket/reddit_year/year=2015), PartitionDirectory([2011],s3a://mybucket/reddit_year/year=2011)))
16/10/14 17:23:48 INFO ListingFileCatalog: Selected 1 partitions out of 9, pruned 88.88888888888889% partitions.
如果您在查询中运行explain(True)
,则可以在逻辑计划中看到此内容:
spark.sql("select created_utc, score, name from reddit where year = '2014'").explain(True)
这将向您显示该计划,您可以看到它在计划的底部进行过滤:
+- *BatchedScan parquet [created_utc#58,name#65,score#69L,year#74] Format: ParquetFormat, InputPaths: s3a://mybucket/reddit_year, PartitionFilters: [isnotnull(year#74), (cast(year#74 as double) = 2014.0)], PushedFilters: [], ReadSchema: struct<created_utc:string,name:string,score:bigint>
答案 1 :(得分:1)
Spark有机会通过Hive改进其分区修剪;见SPARK-17179。
如果您只是直接进入对象存储,那么问题是针对对象存储的递归目录操作是真正的性能杀手。我和我的同事已在HADOOP-11694的S3A客户端完成了工作 - 现在需要对Spark的更改进行跟进,以采用我们能够修复的特定API调用。尽管如此,我们需要确保我们正在使用具有实字布局的真实数据集,因此不要针对具体示例/基准进行优化。
目前,人们应该选择具有浅层目录树的分区布局。