考虑的方法(Spark 2.2.1
):
DataFrame.repartition
(采用partitionExprs: Column*
参数的两个实现)DataFrameWriter.partitionBy
来自partitionBy
的{{3}}:
如果指定,则输出将在文件系统上布局,类似于
Hive
的分区方案。例如,当我们按年份和月份对Dataset
进行分区时,目录布局将如下所示:
- 年= 2016 /月= 01 /
- 年= 2016 /月= 02 /
据此,我推断列参数的顺序将决定目录布局;因此它相关。
来自repartition
的{{3}}:
返回由给定分区表达式分区的新
Dataset
,使用spark.sql.shuffle.partitions
作为分区数。生成的Dataset
是散列分区。
根据我目前的理解,repartition
在处理DataFrame
时决定并行度。有了这个定义,repartition(numPartitions: Int)
的行为很简单,但对于repartition
带有partitionExprs: Column*
个参数的其他两个实现,也不能说同样的。
所有事情都说,我怀疑的是:
partitionBy
方法一样,repartition
方法中列输入的顺序是否相关?SQL
进行查询?GROUP BY
方法repartition(columnExprs: Column*)
的第三个实现中同时包含numPartitions: Int
和partitionExprs: Column*
参数的相关性是什么?答案 0 :(得分:6)
这两种方法之间唯一的相似之处在于它们的名称。有不同的东西,有不同的机制,所以你根本不应该比较它们。
话虽如此,repartition
使用以下方式对数据进行洗牌:
partitionExprs
时,它会使用spark.sql.shuffle.partitions
在表达式中使用的列上使用散列分区程序。partitionExprs
和numPartitions
,它与前一个相同,但会覆盖spark.sql.shuffle.partitions
。numPartitions
,只需使用RoundRobinPartitioning
重新排列数据。在重新分区方法中相关的列输入顺序也是如此?
是的。 hash((x, y))
通常与hash((y, x))
不同。
df = (spark.range(5, numPartitions=4).toDF("x")
.selectExpr("cast(x as string)")
.crossJoin(spark.range(5, numPartitions=4).toDF("y")))
df.repartition(4, "y", "x").rdd.glom().map(len).collect()
[8, 6, 9, 2]
df.repartition(4, "x", "y").rdd.glom().map(len).collect()
[6, 4, 3, 12]
如果我们在同一列上运行带有GROUP BY的SQL查询,那么为并行执行提取的每个块是否包含与每个组中相同的数据?
取决于具体问题。
GROUP BY
将导致密钥在分区上的逻辑分布相同。GROUP BY
“只看到”实际的群组。答案 1 :(得分:-1)
在回答这个问题之前,让我向您介绍一下Spark中的一些概念。
块:这些块物理映射到HDFS文件夹,并且能够存储子块和镶木地板/ *文件。
镶木地板:数据存储压缩文件,通常在HDFS群集中用于存储数据。
现在来回答。
Repartition(number_of_partitions,* columns):这将创建镶木地板文件,对数据进行混洗,并根据提供的列的不同组合值进行排序。因此,列的顺序在这里没有任何区别。您可以在后台提供任何顺序来获取这些列的所有可能值,对它们进行排序,然后将数据整理到文件中,这些文件的总和为 number_of_partitions 。
PartionBy(* columns):这与重新分区略有不同。这将在HDFS中使用参数中提供的不同列值创建块或文件夹。假设:
颜色A = [1,2,3,4,5]
在写入表HDFS时,它将创建文件夹名称 colA-1
colA-2
colA-3 。 。 。 如果您提供两列,则
colA-1 / colB-1 colB-2 colB-3 。
colA-2 /
colA-3 / 。 。
,在其中将存储实木复合地板文件,这些文件的数据将按父列值排序。该文件夹中的文件数将由(bucketBy)属性固定,该属性将进一步建议每个文件夹中的最大文件数。仅在pyspark 2.3和scala 1.6及更高版本中可用。