Uh oh!
There was an error while loading. Please reload this page.
[SPARK-40588] FileFormatWriter materializes AQE plan before accessing outputOrdering - #38358
[SPARK-40588] FileFormatWriter materializes AQE plan before accessing outputOrdering#38358EnricoMi wants to merge 2 commits into
Conversation
EnricoMi
commented
Oct 23, 2022
@cloud-fan this fixes a very peculiar bug introduced via AQE in Spark 3.0. With Spark 3.4, the issue disappeared. A user-defined ordering, that starts with the partition columns, is broken by |
AmplabJenkins
commented
Oct 23, 2022
Can one of the admins verify this patch? |
There was a problem hiding this comment.
can we just change access of getFinalPhysicalPlan() to private[sql] instead? I don't think we need a duplicate of executedPlan in this class.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
I am not sure what you mean with "is brought"` in "the missing ordering field of Sort in the top layer is also brought"?
It is also not clear to me what you are referring to with "removing 'AdaptiveSparkPlanExec'". Do you mean the change in this this PR? The 'AdaptiveSparkPlanExec' is not removed but replaced with the final plan. It is the same plan that is otherwise used when calling .execute, so AQE should work as before.
There was a problem hiding this comment.
V1WriteCommand is a concept introduced after Spark 3.3. The issue addressed in this PR does not exist post Spark 3.3 as the FieFormatWriter does not see AdaptiveSparkPlanExec but the final plan (exactly what this change is trying to achieve).
There was a problem hiding this comment.
I understand what you mean. The problem of #38356 is also caused by enforces the ordering at V1WriteCommand, but not the same case.
EnricoMi
commented
Oct 31, 2022
@cloud-fan@sunchao is there a chance to get this regression fix into 3.2 before the upcoming 3.2.3 release? There is currently no Spark 3 release that does not suffer from this regression (see SPARK-40588). |
EnricoMi
commented
Oct 31, 2022
@HyukjinKwon this PR targets |
f09d844 to
0233c81CompareEnricoMi
commented
Oct 31, 2022
@HyukjinKwon never mind, I have looked at the wrong workflow ("Build") but branch 3.3 has the old workflows ("Build and test"). |
sunchao
commented
Oct 31, 2022
Yes, we can get this back ported to Spark 3.2.3 once this PR is merged. |
kristopherkane
commented
Nov 1, 2022
Thanks for the fix! Is it possible this could land in 3.1 as well? |
cloud-fan
commented
Nov 2, 2022
@kristopherkane 3.1 is EOL unfortunately. @zzzzming95 Does this PR fix your problem? |
zzzzming95
commented
Nov 3, 2022
I have no problem with this issue. Another similar issue I found #38356 is not the same case as this issue. |
EnricoMi
commented
Nov 3, 2022
@zzzzming95 Your query is affected by this issue as well (Spark 3.3): The outer But you are right, the issue in #38356 is different and has been introduced in Spark 3.4. For completeness, this is how nullable string partition columns look like after the fix (Spark 3.3): Btw., this is what I would expect from Spark 3.4 when #38356 is fixed. |
0233c81 to
019707dComparesunchao
commented
Nov 7, 2022
Hi, curious what's the status of this PR? @EnricoMi@cloud-fan . I plan to start the 3.2.3 release process this week. Will this be fixed soon? |
cloud-fan
commented
Nov 8, 2022
@sunchao I don't think this blocks 3.3. It's not a new regression in 3.3, but a long-standing issue since we have AQE. |
EnricoMi
commented
Nov 8, 2022
There is no Spark 3.x release that does not suffer from this. This blocks people from moving to Spark 3, while Spark 3.0 and 3.1 are already EOL. Please reconsider providing a fix before the Spark 3.4 release. |
There was a problem hiding this comment.
looking at the code again, I think it's risky to call getFinalPhysicalPlan directly. Other places call withFinalPlanUpdate which can handle UI update. How about we add a new function here?
def finalPhysicalPlan = withFinalPlanUpdate(identity)
Uh oh!
There was an error while loading. Please reload this page.
cloud-fan
commented
Nov 8, 2022
@EnricoMi I updated my comment... #38358 (comment) |
0cf39d9 to
2052190Compare60db4dc to
52b7bb6CompareEnricoMi
commented
Nov 8, 2022
All done, all green: https://github.com/G-Research/spark/actions/runs/3420780216 |
cloud-fan
commented
Nov 9, 2022
thanks, merging to 3.3/3.2! |
… outputOrdering ### What changes were proposed in this pull request? The `FileFormatWriter` materializes an `AdaptiveQueryPlan` before accessing the plan's `outputOrdering`. This is required for Spark 3.0 to 3.3. Spark 3.4 does not need this because `FileFormatWriter` gets the final plan. ### Why are the changes needed? `FileFormatWriter` enforces an ordering if the written plan does not provide that ordering. An `AdaptiveQueryPlan` does not know its final ordering (Spark 3.0 to 3.3), in which case `FileFormatWriter` enforces the ordering (e.g. by column `"a"`) even if the plan provides a compatible ordering (e.g. by columns `"a", "b"`). In case of spilling, that order (e.g. by columns `"a", "b"`) gets broken (see SPARK-40588). ### Does this PR introduce _any_ user-facing change? This fixes SPARK-40588, which was introduced in 3.0. This restores behaviour from Spark 2.4. ### How was this patch tested? The final plan that is written to files cannot be extracted from `FileFormatWriter`. The bug explained in [SPARK-40588](https://issues.apache.org/jira/browse/SPARK-40588) can only be asserted on the result files when spilling occurs. This is very hard to control in an unit test scenario. Therefore, this was tested manually. The [example to reproduce this issue](https://issues.apache.org/jira/browse/SPARK-40588?focusedCommentId=17621032&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17621032) given in SPARK-40588 now produces sorted files. The actual plan written into the files changed from ``` Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0 +- AdaptiveSparkPlan isFinalPlan=false +- Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- Exchange hashpartitioning(day#2L, 2), REPARTITION_BY_NUM, [id=#30] +- BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastExchange IdentityBroadcastMode, [id=#28] : +- Project [id#0L AS day#2L] : +- Range (0, 2, step=1, splits=2) +- Range (0, 10000000, step=1, splits=2) ``` where `FileFormatWriter` enforces order with `Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0`, to ``` *(3) Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- AQEShuffleRead coalesced +- ShuffleQueryStage 1 +- Exchange hashpartitioning(day#2L, 200), REPARTITION_BY_COL, [id=#68] +- *(2) BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastQueryStage 0 : +- BroadcastExchange IdentityBroadcastMode, [id=#42] : +- *(1) Project [id#0L AS day#2L] : +- *(1) Range (0, 2, step=1, splits=2) +- *(2) Range (0, 1000000, step=1, splits=2) ``` where the sort given by the user is the outermost sort now. Closes#38358 from EnricoMi/branch-3.3-materialize-aqe-plan. Authored-by: Enrico Minack <github@enrico.minack.dev> Signed-off-by: Wenchen Fan <wenchen@databricks.com>
… outputOrdering The `FileFormatWriter` materializes an `AdaptiveQueryPlan` before accessing the plan's `outputOrdering`. This is required for Spark 3.0 to 3.3. Spark 3.4 does not need this because `FileFormatWriter` gets the final plan. `FileFormatWriter` enforces an ordering if the written plan does not provide that ordering. An `AdaptiveQueryPlan` does not know its final ordering (Spark 3.0 to 3.3), in which case `FileFormatWriter` enforces the ordering (e.g. by column `"a"`) even if the plan provides a compatible ordering (e.g. by columns `"a", "b"`). In case of spilling, that order (e.g. by columns `"a", "b"`) gets broken (see SPARK-40588). This fixes SPARK-40588, which was introduced in 3.0. This restores behaviour from Spark 2.4. The final plan that is written to files cannot be extracted from `FileFormatWriter`. The bug explained in [SPARK-40588](https://issues.apache.org/jira/browse/SPARK-40588) can only be asserted on the result files when spilling occurs. This is very hard to control in an unit test scenario. Therefore, this was tested manually. The [example to reproduce this issue](https://issues.apache.org/jira/browse/SPARK-40588?focusedCommentId=17621032&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17621032) given in SPARK-40588 now produces sorted files. The actual plan written into the files changed from ``` Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0 +- AdaptiveSparkPlan isFinalPlan=false +- Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- Exchange hashpartitioning(day#2L, 2), REPARTITION_BY_NUM, [id=#30] +- BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastExchange IdentityBroadcastMode, [id=#28] : +- Project [id#0L AS day#2L] : +- Range (0, 2, step=1, splits=2) +- Range (0, 10000000, step=1, splits=2) ``` where `FileFormatWriter` enforces order with `Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0`, to ``` *(3) Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- AQEShuffleRead coalesced +- ShuffleQueryStage 1 +- Exchange hashpartitioning(day#2L, 200), REPARTITION_BY_COL, [id=#68] +- *(2) BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastQueryStage 0 : +- BroadcastExchange IdentityBroadcastMode, [id=#42] : +- *(1) Project [id#0L AS day#2L] : +- *(1) Range (0, 2, step=1, splits=2) +- *(2) Range (0, 1000000, step=1, splits=2) ``` where the sort given by the user is the outermost sort now. Closes#38358 from EnricoMi/branch-3.3-materialize-aqe-plan. Authored-by: Enrico Minack <github@enrico.minack.dev> Signed-off-by: Wenchen Fan <wenchen@databricks.com> (cherry picked from commit f0cad7a) Signed-off-by: Wenchen Fan <wenchen@databricks.com>
EnricoMi
commented
Nov 9, 2022
Thank you! |
EnricoMi
commented
Jan 5, 2023
Unfortunately, a similar issue exists for Spark 3.4.0 as well, created issue SPARK-41914 to track that. |
cloud-fan
commented
Jan 6, 2023
shall we simply port this PR to master? It will be a noop when planned write is enabled, as there will be no |
Fixed in #39431. |
@EnricoMi It seems it will remove the table location if a importorg.apache.hadoop.fs.{FileSystem, Path}
importorg.apache.spark.sql.QueryTestimportorg.apache.spark.sql.catalyst.TableIdentifier
sql("CREATE TABLE IF NOT EXISTS spark32_overwrite(amt1 int) STORED AS ORC")
sql("CREATE TABLE IF NOT EXISTS spark32_overwrite2(amt1 long) STORED AS ORC")
sql("INSERT OVERWRITE TABLE spark32_overwrite2 select 6000044164")
sql("set spark.sql.ansi.enabled=true")
valloc=
spark.sessionState.catalog.getTableMetadata(TableIdentifier("spark32_overwrite")).location
valfs=FileSystem.get(loc, spark.sparkContext.hadoopConfiguration)
println("Location exists: "+ fs.exists(newPath(loc)))
try {
sql("INSERT OVERWRITE TABLE spark32_overwrite select amt1 from "+"(select cast(amt1 as int) as amt1 from spark32_overwrite2 distribute by amt1)")
} finally {
println("Location exists: "+ fs.exists(newPath(loc)))
} |
EnricoMi
commented
Mar 6, 2023
Yes, it looks like it removes the empty table location after overwriting the table failed due to the @cloud-fan do you consider the removal of an empty table location after overwriting the table fails is a regression? |
cloud-fan
commented
Mar 7, 2023
@wangyum do you know why it's a problem only in 3.2? |
lordk911
commented
Mar 15, 2023
Spark3.2.1 don't have this problem. |
… outputOrdering The `FileFormatWriter` materializes an `AdaptiveQueryPlan` before accessing the plan's `outputOrdering`. This is required for Spark 3.0 to 3.3. Spark 3.4 does not need this because `FileFormatWriter` gets the final plan. `FileFormatWriter` enforces an ordering if the written plan does not provide that ordering. An `AdaptiveQueryPlan` does not know its final ordering (Spark 3.0 to 3.3), in which case `FileFormatWriter` enforces the ordering (e.g. by column `"a"`) even if the plan provides a compatible ordering (e.g. by columns `"a", "b"`). In case of spilling, that order (e.g. by columns `"a", "b"`) gets broken (see SPARK-40588). This fixes SPARK-40588, which was introduced in 3.0. This restores behaviour from Spark 2.4. The final plan that is written to files cannot be extracted from `FileFormatWriter`. The bug explained in [SPARK-40588](https://issues.apache.org/jira/browse/SPARK-40588) can only be asserted on the result files when spilling occurs. This is very hard to control in an unit test scenario. Therefore, this was tested manually. The [example to reproduce this issue](https://issues.apache.org/jira/browse/SPARK-40588?focusedCommentId=17621032&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17621032) given in SPARK-40588 now produces sorted files. The actual plan written into the files changed from ``` Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0 +- AdaptiveSparkPlan isFinalPlan=false +- Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- Exchange hashpartitioning(day#2L, 2), REPARTITION_BY_NUM, [id=apache#30] +- BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastExchange IdentityBroadcastMode, [id=apache#28] : +- Project [id#0L AS day#2L] : +- Range (0, 2, step=1, splits=2) +- Range (0, 10000000, step=1, splits=2) ``` where `FileFormatWriter` enforces order with `Sort [input[0, bigint, false] ASC NULLS FIRST], false, 0`, to ``` *(3) Sort [day#2L ASC NULLS FIRST, id#4L ASC NULLS FIRST], false, 0 +- AQEShuffleRead coalesced +- ShuffleQueryStage 1 +- Exchange hashpartitioning(day#2L, 200), REPARTITION_BY_COL, [id=apache#68] +- *(2) BroadcastNestedLoopJoin BuildLeft, Inner :- BroadcastQueryStage 0 : +- BroadcastExchange IdentityBroadcastMode, [id=apache#42] : +- *(1) Project [id#0L AS day#2L] : +- *(1) Range (0, 2, step=1, splits=2) +- *(2) Range (0, 1000000, step=1, splits=2) ``` where the sort given by the user is the outermost sort now. Closesapache#38358 from EnricoMi/branch-3.3-materialize-aqe-plan. Authored-by: Enrico Minack <github@enrico.minack.dev> Signed-off-by: Wenchen Fan <wenchen@databricks.com> (cherry picked from commit f0cad7a) Signed-off-by: Wenchen Fan <wenchen@databricks.com>
…cute in `FileFormatWriter#write` ### What changes were proposed in this pull request? Trigger `committer.setupJob` before plan execute in `FileFormatWriter#write` ### Why are the changes needed? In this issue, the case where `outputOrdering` might not work if AQE is enabled has been resolved. #38358 However, since it materializes the AQE plan in advance (triggers getFinalPhysicalPlan) , it may cause the committer.setupJob(job) to not execute When `AdaptiveSparkPlanExec#getFinalPhysicalPlan()` is executed with an error. ### Does this PR introduce _any_ user-facing change? no ### How was this patch tested? add UT Closes#41154 from zzzzming95/spark3-SPARK-43327. Lead-authored-by: zzzzming95 <505306252@qq.com> Co-authored-by: zhiming she <505306252@qq.com> Signed-off-by: Wenchen Fan <wenchen@databricks.com>
What changes were proposed in this pull request?
The
FileFormatWritermaterializes anAdaptiveQueryPlanbefore accessing the plan'soutputOrdering. This is required for Spark 3.0 to 3.3. Spark 3.4 does not need this becauseFileFormatWritergets the final plan.Why are the changes needed?
FileFormatWriterenforces an ordering if the written plan does not provide that ordering. AnAdaptiveQueryPlandoes not know its final ordering (Spark 3.0 to 3.3), in which caseFileFormatWriterenforces the ordering (e.g. by column"a") even if the plan provides a compatible ordering (e.g. by columns"a", "b"). In case of spilling, that order (e.g. by columns"a", "b") gets broken (see SPARK-40588).Does this PR introduce any user-facing change?
This fixes SPARK-40588, which was introduced in 3.0. This restores behaviour from Spark 2.4.
How was this patch tested?
The final plan that is written to files cannot be extracted from
FileFormatWriter. The bug explained in SPARK-40588 can only be asserted on the result files when spilling occurs. This is very hard to control in an unit test scenario.Therefore, this was tested manually. The example to reproduce this issue given in SPARK-40588 now produces sorted files.
The actual plan written into the files changed from
where
FileFormatWriterenforces order withSort [input[0, bigint, false] ASC NULLS FIRST], false, 0, towhere the sort given by the user is the outermost sort now.