我的数据原则上是一个表格,除了其他“数据”外,还包含一列ID
和一列GROUP_ID
。
在第一步中,我将CSV读入Spark,进行一些处理以准备第二步的数据,并将数据写为镶木地板。
第二步做了很多groupBy('GROUP_ID')
和Window.partitionBy('GROUP_ID').orderBy('ID')
。
现在的目标是 - 为了避免在第二步中进行洗牌 - 在第一步中有效地加载数据,因为这是一次性的。
问题第1部分: AFAIK,Spark从镶木地板加载时保留了分区(这实际上是任何“优化写入考虑”的基础) - 对吗?
我提出了三种可能性:
df.orderBy('ID').write.partitionBy('TRIP_ID').parquet('/path/to/parquet')
df.orderBy('ID').repartition(n, 'TRIP_ID').write.parquet('/path/to/parquet')
df.repartition(n, 'TRIP_ID').sortWithinPartitions('ID').write.parquet('/path/to/parquet')
我会将n
设置为单个拼花文件大约为100MB。
问题第2部分:三个选项在目标方面是否产生“相同”/类似结果(在第2步中避免改组)是否正确?如果没有,有什么区别?哪一个'更好'?
问题第3部分:对于第1步,这三个选项中哪一项表现更好?
感谢您分享您的知识!
编辑2017-07-24
在做了一些测试(写入和读取镶木地板)后,似乎Spark在第二步中默认无法恢复partitionBy
和orderBy
信息。分区数(从df.rdd.getNumPartitions()
获得似乎取决于核心数量和/或spark.default.parallelism
(如果设置),但不取决于镶木地板分区的数量。所以回答问题1 将错误,问题2和问题3将无关紧要。
事实证明,真实问题是:有没有办法告诉Spark,数据已经按 X 列分区,并按列排序ÿ
答案 0 :(得分:0)
据我所知,没有办法无法从镶木地板中读取数据并告诉Spark它已被某些表达式分割并排序。
简而言之,对于一个Spark分区,HDFS等上的一个文件太大。而且,即使您将整个文件读取到一个具有Parquet属性(例如parquet.split.files=false
,parquet.task.side.metadata=true
等)的分区,与仅进行一次随机播放相比,也将花费最多。
答案 1 :(得分:0)
尝试使用BucketBy。此外,分区发现也可以提供帮助。
答案 2 :(得分:0)
您可能会对Spark中的存储桶支持感兴趣。
在此处查看详细信息 https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-bucketing.html
large.write
.bucketBy(4, "id")
.sortBy("id")
.mode(SaveMode.Overwrite)
.saveAsTable(bucketedTableName)
Notice Spark 2.4添加了对bucket pruning
(例如partition pruning
)的支持
您正在查看的更多直接功能是Hive的存储桶分类表 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-BucketedSortedTables 这在Spark中尚不可用(请参阅下面的PS部分)
还请注意,Spark不会自动加载排序信息,但是由于数据已经被排序,因此对它的排序操作实际上要快得多,因为不需要做很多工作。传递一个数据只是为了确认它已经被排序。
PS。 Spark和Hive的存储桶略有不同。 这是伞票,可在Spark中为在Hive中创建的存储桶表提供兼容性- https://issues.apache.org/jira/browse/SPARK-19256