Uh oh!
There was an error while loading. Please reload this page.
[SPARK-32940][SQL] Collect, first and last should be deterministic aggregate functions - #29810
[SPARK-32940][SQL] Collect, first and last should be deterministic aggregate functions#29810tanelk wants to merge 25 commits into
Conversation
| test("unwrap cast should skip when expression is non-deterministic or foldable") { | ||
| Seq(positiveInt, negativeInt).foreach (v => { | ||
| val e = Cast(First(f, ignoreNulls = true), IntegerType) <=> v | ||
| Seq(positiveLong, negativeLong).foreach (v => { | ||
| val e = Cast(SparkPartitionID(), LongType) <=> v | ||
| assertEquivalent(e, e, evaluate = false) | ||
| val e2 = Cast(Literal(30.toShort), IntegerType) >= v | ||
| val e2 = Cast(Literal(30), LongType) >= v | ||
| assertEquivalent(e2, e2, evaluate = false) |
There was a problem hiding this comment.
There was no other non-deterministic expression, that can return a short, so I had to change this test a bit.
tanelk
commented
Sep 19, 2020
@cloud-fan, you reviewed the related pull request (although years back). |
dongjoon-hyun
commented
Sep 20, 2020
ok to test |
| override def nullable: Boolean = true | ||
| // First is not a deterministic function. | ||
| override lazy val deterministic: Boolean = false |
There was a problem hiding this comment.
I think you may need to update the note above and says like "The function can be non-deterministic because its results depend on the order of input rows which are usually non-deterministic after a shuffle." You might need to update functions.py, functions.R and functions.scala
SparkQA
commented
Sep 20, 2020
Test build #128898 has finished for PR 29810 at commit
|
SparkQA
commented
Sep 20, 2020
Test build #128910 has finished for PR 29810 at commit
|
cloud-fan
commented
Sep 21, 2020
hmm, it's pretty weird if we list |
tanelk
commented
Sep 21, 2020
Sorry if I didn't word it correctly - these are not listed there. I tried to exemplify the difference between deterministic and order irrelevant. |
hvanhovell
commented
Sep 21, 2020
Maybe I am missing something here. AFAIK the problem with First/Last/CollectList methods is that we can't control how results are merged. This depends on how we shuffle fetches results and this is not deterministic. |
tanelk
commented
Sep 21, 2020
You are 100% correct. As a user, this is how I would also understand the term deterministic. I'll copy our internal definition: For aggregation expressions the internal state part can introduce extra confusion - of course all of them have some internal state about the current group they are aggregating (running count, largest value seen so far, etc), but they do not "remember" the previous groups they have aggregated. There is a separate optimizer rule For context, why this is relevant: Basically this case will filter out groups in the aggregation before aggregating the values. Within one group the aggregator will still see all the same rows in the same order, but it would not see the groups, that were filtered out. This would change the output of an aggregator, that remembers previous groups (non-deterministic), but it would not change the output of an aggregator, that only cares about the current group (deterministic, but possibly order relevant). |
# Conflicts: # python/pyspark/sql/functions.py # sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/UnwrapCastInBinaryComparisonSuite.scala
SparkQA
commented
Dec 30, 2020
Test build #133545 has finished for PR 29810 at commit
|
SparkQA
commented
Dec 31, 2020
Test build #133547 has finished for PR 29810 at commit
|
SparkQA
commented
Sep 30, 2021
Kubernetes integration test starting |
SparkQA
commented
Sep 30, 2021
Test build #143761 has finished for PR 29810 at commit
|
SparkQA
commented
Sep 30, 2021
Kubernetes integration test status failure |
SparkQA
commented
Oct 19, 2021
Kubernetes integration test starting |
SparkQA
commented
Oct 19, 2021
Kubernetes integration test status failure |
SparkQA
commented
Oct 19, 2021
Test build #144407 has finished for PR 29810 at commit
|
cloud-fan
commented
Nov 4, 2021
There is inevitable randomness in the input of aggregate functions, because the shuffle reader may produce data with random orders, and we are not able to completely eliminate this randomness. For example, even I don't think |
cloud-fan
commented
Nov 4, 2021
retest this please |
| Seq(positiveInt, negativeInt).foreach(v => { | ||
| val e = Cast(First(f, ignoreNulls = true), IntegerType) <=> v | ||
| Seq(positiveLong, negativeLong).foreach(v => { | ||
| val e = Cast(SparkPartitionID(), LongType) <=> v |
| aggBuilder => | ||
| val agg = aggBuilder('a) | ||
| test(s"Eliminate Distinct in ${agg.prettyName}") { | ||
| test(s"Eliminate Distinct in ${agg.toString}") { |
SparkQA
commented
Nov 4, 2021
Kubernetes integration test starting |
SparkQA
commented
Nov 4, 2021
Kubernetes integration test status failure |
AmplabJenkins
commented
Nov 4, 2021
Refer to this link for build results (access rights to CI server needed): |
SparkQA
commented
Nov 4, 2021
Test build #144906 has finished for PR 29810 at commit
|
AmplabJenkins
commented
Nov 4, 2021
Refer to this link for build results (access rights to CI server needed): |
SparkQA
commented
Nov 5, 2021
Kubernetes integration test starting |
SparkQA
commented
Nov 5, 2021
Kubernetes integration test status failure |
AmplabJenkins
commented
Nov 5, 2021
Refer to this link for build results (access rights to CI server needed): |
cloud-fan
commented
Nov 5, 2021
thanks, merging to master! |
SparkQA
commented
Nov 5, 2021
Test build #144921 has finished for PR 29810 at commit
|
AmplabJenkins
commented
Nov 5, 2021
Refer to this link for build results (access rights to CI server needed): |
What changes were proposed in this pull request?
Collect, first and last have mistakenly been marked as non-deterministic. They are actually deterministic iff their child expression is deterministic.
For example collect was marked as non-deterministic in #14749. The reasoning was that its output depends on the actual order of input rows. Although it is correct that these aggregators depend on the order of input rows, it does not make them non-deterministic.
In
EliminateSortsoptimizer rule, there is a methodisOrderIrrelevantAggs, that lists all aggregators that do not depend on their input row order. Collect, first and last are correctly not listed there.An aggregator would be non-deterministic if its output for a group would depend on previous groups it has aggregated - I can't think of any practical examples of this kind of aggregator in Spark.
An analogous aggregator to these would be sum on float and double datatype - its result does depend on the order of its inputs, but is deterministic. Another similar aggregates are the
max_byandmin_by- deterministic functions, that can return different results when the order of rows changes.Why are the changes needed?
The optimizer rule
PushPredicateThroughNonJoincan work in more cases.Does this PR introduce any user-facing change?
No
How was this patch tested?
UT