Repository navigation
[SPARK-59981][SQL] Derive the partition-key ordering when a V2 scan's reported ordering keeps no sort order #59257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dd545ce
8adb7cc
b82b427
7cd0e19
abc3638
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -419,8 +419,8 @@ case class GroupPartitionsExec( | |
| override def outputOrdering: Seq[SortOrder] = { | ||
| if (!hasCoalescing) { | ||
| // No coalescing: each output partition is exactly one input partition. The child's | ||
| // within-partition ordering is fully preserved (including any key-derived ordering that | ||
| // `DataSourceV2ScanExecBase` already prepended). | ||
| // within-partition ordering is fully preserved, including an ordering that | ||
| // `DataSourceV2ScanExecBase` derives from the partition keys. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
With The conf is off by default, so this is minor. Should the merge be feasible only when the child's ordering has a sort order beyond the partition keys?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd leave this:
A gate on a sort order beyond the partition keys would lose the second case. |
||
| child.outputOrdering | ||
| } else if (usesSortedMerge) { | ||
| // Coalescing with sorted merge: SortedMergeCoalescedRDD performs a k-way merge by the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,15 +95,16 @@ object V2ScanPartitioningAndOrdering extends Rule[LogicalPlan] with AliasHelper | |
| log"Spark ignores the ordering reported by ${MDC(RELATION_NAME, relation.name)} " + | ||
| log"(scan ${MDC(CLASS_NAME, scan.getClass.getName)}) because the ordering columns " + | ||
| log"cannot be resolved: ${MDC(COLUMN_NAMES, unresolvedColumns.mkString(", "))}.") | ||
| // Use None, not Some(Nil): only None lets DataSourceV2ScanExecBase.outputOrdering derive an | ||
| // ordering from a kept key-grouped partitioning, which does not depend on the dropped | ||
| // report. | ||
| // `None` and `Some(Nil)` mean the same to DataSourceV2ScanExecBase.outputOrdering, which | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As a result, the canonical form and the physical ordering follow different rules. With keys Could the comment say this holds for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in b82b42717c7. The comment now says that the two restrict the ordering by different rules. A plain |
||
| // can still derive an ordering from a kept key-grouped partitioning. | ||
| d.copy(ordering = None) | ||
| } else { | ||
| // The ordering is kept as reported, even where it references columns pruned out of the | ||
| // scan output: truncating it here would also drop the sort orders on a partition key past a | ||
| // pruned column, which still hold. `DataSourceV2ScanRelation.doCanonicalize` and | ||
| // `DataSourceV2ScanExecBase.outputOrdering` restrict it to the scan output instead. | ||
| // `DataSourceV2ScanExecBase.outputOrdering` restrict it to the scan output instead, by | ||
| // different rules. `doCanonicalize` only feeds plan equality, so a plain `takeWhile` that | ||
| // drops the pruned columns is enough there. | ||
| // A nested sort key such as `s.x` resolves to a new `Alias(GetStructField(...))` on every | ||
| // run of this rule. Strip the alias so repeated runs give equal plans and, when the scan | ||
| // reads the whole struct, the ordering can satisfy a required ordering on the same field | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: This is the rule a connector author has to know, but the public Javadoc of
SupportsReportOrdering.outputOrdering()(SupportsReportOrdering.java:36-47) does not mention it. That Javadoc already describes how Spark treats an unresolvable report, a transform, and a sort order on a partition key, so it reads as the full contract. After this PR, an empty array, or an ordering Spark keeps nothing of, makes a scan with aKeyGroupedPartitioningreport[key ASC]and drop a sort above it. A connector that returns an empty array to mean "unsorted" learns this only from the 4.4 migration note. Could we add a sentence there, for example that when Spark keeps none of the reported sort orders, including for an empty array, it may treat each partition as sorted by the partition keys that are not transforms (seespark.sql.sources.v2.bucketing.partitionKeyOrdering.enabled)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in abc3638a222.