【问题标题】:Why does Spark not push down a filter to before a groupBy with collect_list?为什么 Spark 不使用 collect_list 将过滤器推到 groupBy 之前?
【发布时间】:2020-07-05 11:29:02
【问题描述】:

考虑这个例子:

import pyspark
import pyspark.sql.functions as f


with pyspark.SparkContext(conf=pyspark.SparkConf().setMaster('local[*]')) as sc:
    spark = pyspark.sql.SQLContext(sc)

    df = spark.createDataFrame([
        [2020, 1, 1, 1.0],
        [2020, 1, 2, 2.0],
        [2020, 1, 3, 3.0],
    ], schema=['year', 'id', 't', 'value'])

    df = df.groupBy(['year', 'id']).agg(f.collect_list('value'))
    df = df.where(f.col('year') == 2020)
    df.explain()

产生以下计划

== Physical Plan ==
*(2) Filter (isnotnull(year#0L) AND (year#0L = 2020))
+- ObjectHashAggregate(keys=[year#0L, id#1L], functions=[collect_list(value#3, 0, 0)])
   +- Exchange hashpartitioning(year#0L, id#1L, 200), true, [id=#23]
      +- ObjectHashAggregate(keys=[year#0L, id#1L], functions=[partial_collect_list(value#3, 0, 0)])
         +- *(1) Project [year#0L, id#1L, value#3]
            +- *(1) Scan ExistingRDD[year#0L,id#1L,t#2L,value#3]

我希望 Spark 将过滤器 year = 2020 推到 hashpartitioning 之前。如果聚合函数是sum,Spark 会这样做,但对于collect_list 则不会。

关于为什么不是这种情况的任何想法,以及是否有办法解决这个问题?

这样做的原因是没有过滤器下推,3年的语句(例如year IN (2020, 2019, 2018)在它们之间执行洗牌。另外,我需要在代码中的groupBy之后表达过滤器。

更重要的是,我试图理解为什么 Spark 不会为某些聚合下推过滤器,但它会为其他聚合下推。

【问题讨论】:

    标签: apache-spark


    【解决方案1】:

    让我们看看您正在使用的聚合函数。

    collect_list

    来自下面的文档 -

    /**
       * Aggregate function: returns a list of objects with duplicates.
       *
       * @note The function is non-deterministic because the order of collected results depends
       * on the order of the rows which may be non-deterministic after a shuffle.
       *
       * @group agg_funcs
       * @since 1.6.0
       */
      def collect_list(columnName: String): Column = collect_list(Column(columnName))
    

    collect_list 是一个非确定性操作,其结果取决于行的顺序。

    现在看看Optimizer.scala#PushPredicateThroughNonJoin

    // SPARK-13473: We can't push the predicate down when the underlying projection output non-
        // deterministic field(s).  Non-deterministic expressions are essentially stateful. This
        // implies that, for a given input row, the output are determined by the expression's initial
        // state and all the input rows processed before. In another word, the order of input rows
        // matters for non-deterministic expressions, while pushing down predicates changes the order.
        // This also applies to Aggregate.
    

    由于上述操作是不确定的,即结果取决于底层数据帧的行顺序,spark 无法推送谓词,因为它改变了行的顺序。

    【讨论】:

    • 很好的答案。你知道是否有任何方法可以确定地collect_list?例如。我可以在某处应用 orderBy 以使其具有确定性吗?
    • 很难理解,我不会这样想。通过上面的评论订购 - 试试看并告诉我们...@JorgeLeitao
    • 更难理解,如果你不使用 order by,sort 那么我想谁在乎呢?
    • 来自@JorgeLeitao - 您知道是否有任何方法可以确定性地收集列表?例如。我可以在某处应用 orderBy 以使其具有确定性吗? -> 我认为,我们不能使任何 spark Collect 操作具有确定性,因为它们在 repo 中被硬编码为 false .检查 - github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/…
    • 我认为在现实中没有什么意义的错过者,但很高兴知道
    猜你喜欢
    • 1970-01-01
    • 2018-07-23
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多