Apache spark ApacheSpark重新分区/Bucketing最佳实践,以避免数据倾斜

Apache spark ApacheSpark重新分区/Bucketing最佳实践,以避免数据倾斜,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我的重点是对数据帧进行bucketing和重新分区,作为将数据分组在一起以加快后期处理的方法 使用bucketing,目的是将数据拆分为固定数量的“bucket”,并覆盖一些列。目标是将已分区的数据拆分为一组相等的存储桶 我相信您已经了解到,总体目标是使用此方法来防止数据倾斜 以下是我为实现bucketing而采用的一步一步的程序 请注意,我使用的是Spark SQL,而不是PySpark,但原理是一样的。例如,我使用名为NTILE的函数来存储数据。此函数取自典型的T-SQL 不管怎样,我们走吧

我的重点是对数据帧进行bucketing和重新分区,作为将数据分组在一起以加快后期处理的方法

使用bucketing,目的是将数据拆分为固定数量的“bucket”,并覆盖一些列。目标是将已分区的数据拆分为一组相等的存储桶

我相信您已经了解到,总体目标是使用此方法来防止数据倾斜

以下是我为实现bucketing而采用的一步一步的程序

请注意,我使用的是Spark SQL,而不是PySpark,但原理是一样的。例如,我使用名为NTILE的函数来存储数据。此函数取自典型的T-SQL

不管怎样,我们走吧:

我有以下两个数据帧

df_table1 = spark.read.csv("/tamingskew/table1/", header=True)
df_table2 = spark.read.csv("/tamingskew/table2/", header=True)
ApacheSpark对数据帧进行一次更新,并为每个数据帧创建一个分区,如下代码所示:

df_table1.rdd.getNumPartitions()
一,

然后,我创建两个表来执行查询,以生成bucketted数据:

df_table1.createOrReplaceTempView("t1")
df_table2.createOrReplaceTempView("t2")
现在,我们将对第一个表't1'进行bucketing和重新分区

df_pt1 = spark.sql("""SELECT
  t1.*
 ,NTILE(8) OVER (ORDER BY t1.registration) AS newpart1
FROM t1
ORDER BY newpart1 DESC
""").repartition(8, col("newpart1"))
从上面可以看到,我已经将数据压缩到8个bucket中,并基于压缩数据“newpart1”将数据重新划分到8个分区中

然后,我执行以下代码以查看分区数据的外观

print("Number of partitions: {}".format(df_pt1.rdd.getNumPartitions())) 
print('Partitioning distribution: '+ str(df_pt1.rdd.glom().map(len).collect()))
如下所示:

Number of partitions: 8
Partitioning distribution: [0, 1250, 1250, 3750, 0, 0, 2500, 1250]
上面的输出并不理想,因为正如您所看到的,有3个分区根本没有任何数据

然后,我从上面的带扣数据框创建一个表,用于我的最终查询:

df_pt1.createOrReplaceTempView('t11')
然后,我对表2做了完全相同的操作(不再详述所有细节)

最终查询如下:

querywithgroups = spark.sql("""SELECT
  t11.registration
 ,AVG(t22.sale_price) AS average_price
FROM t11
INNER JOIN t22
  ON t11.make = t22.make
    AND t11.model = t22.model
WHERE ABS(t22.engine_size - t11.engine_size) <= 0.1
GROUP BY t11.registration
        ,t11.newpart1
        ,t22.newpart2
""")
我的问题是:有没有更好的方法使用bucketing对数据进行分区以加速查询? 上述情况是否可以改进


非常感谢您的任何想法。

据我所知,您的主要流程是在
make
model
上加入
JOIN
,因此Spark将(据我所知有限)首先使用这些列洗牌您的数据。这击败了以前的任何党派斗争——这纯粹是浪费。我错过什么了吗?@GPI,谢谢你的帮助。我真的不知道答案。我希望SE的人能提供一些有趣的建议
querywithgroups = spark.sql("""SELECT
  t11.registration
 ,AVG(t22.sale_price) AS average_price
FROM t11
INNER JOIN t22
  ON t11.make = t22.make
    AND t11.model = t22.model
WHERE ABS(t22.engine_size - t11.engine_size) <= 0.1
GROUP BY t11.registration
        ,t11.newpart1
        ,t22.newpart2
""")
Number of partitions: 8
Partitioning distribution: [0, 10000, 10000, 30000, 0, 0, 20000, 10000]