Spark:对数据进行排序和分区的最有效方法是将其写为镶木地板

时间:2017-07-20 20:43:44

标签: apache-spark pyspark apache-spark-sql pyspark-sql

我的数据原则上是一个表格,除了其他“数据”外,还包含一列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在第二步中默认无法恢复partitionByorderBy信息。分区数(从df.rdd.getNumPartitions()获得似乎取决于核心数量和/或spark.default.parallelism(如果设置),但不取决于镶木地板分区的数量。所以回答问题1 错误,问题2和问题3将无关紧要。

事实证明,真实问题是:有没有办法告诉Spark,数据已经按 X 列分区,并按列排序ÿ

3 个答案:

答案 0 :(得分:0)

据我所知,没有办法无法从镶木地板中读取数据并告诉Spark它已被某些表达式分割并排序。

简而言之,对于一个Spark分区,HDFS等上的一个文件太大。而且,即使您将整个文件读取到一个具有Parquet属性(例如parquet.split.files=falseparquet.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