PySpark - 在镶木地板读取后优化分区数量

时间:2018-06-05 09:20:35

标签: apache-spark pyspark partitioning parquet

在由yearmonth划分的拼花数据湖中,spark.default.parallelism设置为ie 4,假设我要创建一个由月份组成的数据框架〜 2017年12月,2018年1月3日,两个来源AB

df = spark.read.parquet(
    "A.parquet/_YEAR={2017}/_MONTH={11,12}",
    "A.parquet/_YEAR={2018}/_MONTH={1,2,3}",
    "B.parquet/_YEAR={2017}/_MONTH={11,12}",
    "B.parquet/_YEAR={2018}/_MONTH={1,2,3}",
)

如果我得到分区数,Spark使用spark.default.parallelism作为默认值:

df.rdd.getNumPartitions()
Out[4]: 4

考虑到在创建df后我需要在每个时段执行joingroupBy操作,并且这些数据或多或少均匀分布在每个时段(大约1000万)每期行数):

问题

  • 重新分区会改善后续操作的效果吗?
  • 如果是这样,如果我有10个不同的期间(A和B每年5个),我应该按期间数重新分配并明确引用要重新分区的列(df.repartition(10,'_MONTH','_YEAR'))吗?

1 个答案:

答案 0 :(得分:2)

  

重新分区会改善我后续操作的效果吗?

通常它不会。抢先重新分区数据的唯一原因是,当基于相同条件将相同Dataset用于多个联接时,避免进一步改组

  

如果是这样,如果我有10个不同的期间(A和B每年5个),我应该按期间数重新分配并明确引用要重新分配的列(df.repartition(10,'_ MONTH',' _YEAR'))?

让我们一步一步走:

  •   

    我应该按期间数重新分配

    从业者不保证级别和分区之间的1:1关系,因此唯一要记住的是,您不能拥有比唯一键更多的非空分区,因此使用更大的值是没有意义的。< / p>

  •   

    并明确引用要重新分区的列

    如果您repartition以及随后joingroupBy使用相同的两个部分列是唯一明智的解决方案。

<强>摘要

加入之前的

repartitoning在两种情况下有意义:

  • 如果有多个后续joins

    df_ = df.repartition(10, "foo", "bar")
    df_.join(df1, ["foo", "bar"])
    ...
    df_.join(df2, ["foo", "bar"])
    
  • 当所需数量的输出分区与spark.sql.shuffle.partitions不同(并且没有广播加入)时,使用单一联接

    spark.conf.get("spark.sql.shuffle.partitions")
    # 200
    spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
    
    df1_ = df1.repartition(11, "foo", "bar")
    df2_ = df2.repartition(11, "foo", "bar")
    
    df1_.join(df2_, ["foo", "bar"]).rdd.getNumPartitions()
    # 11
    
    df1.join(df2, ["foo", "bar"]).rdd.getNumPartitions()
    # 200
    

    可能优于:

    spark.conf.set("spark.sql.shuffle.partitions", 11)
    df1.join(df2, ["foo", "bar"]).rdd.getNumPartitions()
    spark.conf.set("spark.sql.shuffle.partitions", 200)