peter-toth commented on code in PR #59189:
URL: https://github.com/apache/spark/pull/59189#discussion_r4158880681
##########
sql/core/src/test/scala/org/apache/spark/sql/connector/KeyGroupedPartitioningSuite.scala:
##########
@@ -5461,6 +5461,41 @@ class KeyGroupedPartitioningSuite
}
}
+ test("SPARK-59905: ORDER BY the join-key expression of a one-side shuffle") {
Review Comment:
Thanks, confirmed and done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2).
On master with only `sorting.enabled`, the broadcast form returns `b` as 0 to
6, and the `p.s.a` and `p.b + p.c` forms fail as in the shuffle case. The test
now runs every query through both a one-side shuffle and a broadcast join, and
the description no longer says the shuffle conf is needed.
The same expansion also reaches #59165's wrong result with every conf at its
default
([comment](https://github.com/apache/spark/pull/59165#issuecomment-5937582338)).
##########
sql/core/src/test/scala/org/apache/spark/sql/connector/KeyGroupedPartitioningSuite.scala:
##########
@@ -5461,6 +5461,41 @@ class KeyGroupedPartitioningSuite
}
}
+ test("SPARK-59905: ORDER BY the join-key expression of a one-side shuffle") {
+ createTable("ident", Array(Column.create("id", LongType)),
Array(identity("id")))
+ sql("INSERT INTO testcat.ns.ident VALUES " + (94 to 100).map(i =>
s"($i)").mkString(", "))
+ createTable("plain", Array(Column.create("b", LongType),
Column.create("c", LongType),
+ Column.create("s", new StructType().add("a", LongType))), Array.empty)
+ sql("INSERT INTO testcat.ns.plain VALUES " +
+ (0 to 6).map(b => s"($b, 94, named_struct('a', ${94 +
b}L))").mkString(", "))
+
+ // The join shuffles `plain` onto `ident`'s keys and reports the join key,
e.g. `100 - b`, as
+ // its partition expression. The ORDER BY over it is served by the key
order, so the one-side
+ // shuffle is the only one. The keys come out ascending, so only a
descending order needs a
+ // `GroupPartitionsExec` to sort the partitions. AQE stays off, since its
plan validation fails
+ // on `b + c` until SPARK-59901 is fixed.
+ withSQLConf(
+ SQLConf.ADAPTIVE_EXECUTION_ENABLED.key -> "false",
Review Comment:
Done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2).
The single-column queries run with AQE on and off. Only `p.b + p.c` stays off
until #59165 lands.
##########
sql/core/src/test/scala/org/apache/spark/sql/connector/KeyGroupedPartitioningSuite.scala:
##########
@@ -5461,6 +5461,41 @@ class KeyGroupedPartitioningSuite
}
}
+ test("SPARK-59905: ORDER BY the join-key expression of a one-side shuffle") {
+ createTable("ident", Array(Column.create("id", LongType)),
Array(identity("id")))
+ sql("INSERT INTO testcat.ns.ident VALUES " + (94 to 100).map(i =>
s"($i)").mkString(", "))
+ createTable("plain", Array(Column.create("b", LongType),
Column.create("c", LongType),
+ Column.create("s", new StructType().add("a", LongType))), Array.empty)
+ sql("INSERT INTO testcat.ns.plain VALUES " +
+ (0 to 6).map(b => s"($b, 94, named_struct('a', ${94 +
b}L))").mkString(", "))
+
+ // The join shuffles `plain` onto `ident`'s keys and reports the join key,
e.g. `100 - b`, as
+ // its partition expression. The ORDER BY over it is served by the key
order, so the one-side
+ // shuffle is the only one. The keys come out ascending, so only a
descending order needs a
+ // `GroupPartitionsExec` to sort the partitions. AQE stays off, since its
plan validation fails
+ // on `b + c` until SPARK-59901 is fixed.
+ withSQLConf(
+ SQLConf.ADAPTIVE_EXECUTION_ENABLED.key -> "false",
+ SQLConf.V2_BUCKETING_SHUFFLE_ENABLED.key -> "true",
+ SQLConf.V2_BUCKETING_SORTING_ENABLED.key -> "true") {
+ val ids = (94 to 100).map(i => Row(i.toLong))
+ Seq(
Review Comment:
Added in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2),
with your `ident2(x, y)` shape ordered by `100 - p.b, p.c DESC`. It needs the
mixed-direction `GroupPartitionsExec`, and master returns its rows in the wrong
order on both routes.
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/exchange/EnsureRequirements.scala:
##########
@@ -139,10 +139,16 @@ case class EnsureRequirements(
// OrderedDistribution requires grouped KeyedPartitioning with
sorted keys
// according to the distribution's ordering.
val satisfyingKeyedPartitioning = resolution.fold(identity, _._1)
- // The single-column invariant in
KeyedPartitioning.supportsExpressions guarantees
- // one attribute per partition expression.
- val attrs =
satisfyingKeyedPartitioning.expressions.flatMap(_.references)
- val keyRowOrdering = RowOrdering.create(o.ordering, attrs)
+ // A key row holds the values of the partition expressions.
`keysSatisfy` admits a
+ // partitioning here only when those expressions are the
ordering's, position by
+ // position, so each sort order reads its position of the key
row. The expression
+ // need not be a bare column, e.g. a shuffled side's join key
`100 - b`.
+ val keyRowOrdering = RowOrdering.create(
Review Comment:
Done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2),
with the assertion.
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/exchange/EnsureRequirements.scala:
##########
@@ -139,10 +139,16 @@ case class EnsureRequirements(
// OrderedDistribution requires grouped KeyedPartitioning with
sorted keys
// according to the distribution's ordering.
val satisfyingKeyedPartitioning = resolution.fold(identity, _._1)
- // The single-column invariant in
KeyedPartitioning.supportsExpressions guarantees
- // one attribute per partition expression.
- val attrs =
satisfyingKeyedPartitioning.expressions.flatMap(_.references)
- val keyRowOrdering = RowOrdering.create(o.ordering, attrs)
+ // A key row holds the values of the partition expressions.
`keysSatisfy` admits a
+ // partitioning here only when those expressions are the
ordering's, position by
+ // position, so each sort order reads its position of the key
row. The expression
+ // need not be a bare column, e.g. a shuffled side's join key
`100 - b`.
Review Comment:
Done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2).
Both now say that a scan reports one column per expression, and that `reorder`
gives up on a join key like `b + c`.
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/exchange/EnsureRequirements.scala:
##########
@@ -139,10 +139,16 @@ case class EnsureRequirements(
// OrderedDistribution requires grouped KeyedPartitioning with
sorted keys
// according to the distribution's ordering.
val satisfyingKeyedPartitioning = resolution.fold(identity, _._1)
- // The single-column invariant in
KeyedPartitioning.supportsExpressions guarantees
- // one attribute per partition expression.
- val attrs =
satisfyingKeyedPartitioning.expressions.flatMap(_.references)
- val keyRowOrdering = RowOrdering.create(o.ordering, attrs)
+ // A key row holds the values of the partition expressions.
`keysSatisfy` admits a
+ // partitioning here only when those expressions are the
ordering's, position by
+ // position, so each sort order reads its position of the key
row. The expression
+ // need not be a bare column, e.g. a shuffled side's join key
`100 - b`.
+ val keyRowOrdering = RowOrdering.create(
+ o.ordering.zipWithIndex.map { case (order, i) =>
+ SortOrder(BoundReference(i, order.child.dataType, nullable =
true),
Review Comment:
Done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2).
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/exchange/EnsureRequirements.scala:
##########
@@ -139,10 +139,16 @@ case class EnsureRequirements(
// OrderedDistribution requires grouped KeyedPartitioning with
sorted keys
// according to the distribution's ordering.
val satisfyingKeyedPartitioning = resolution.fold(identity, _._1)
- // The single-column invariant in
KeyedPartitioning.supportsExpressions guarantees
- // one attribute per partition expression.
- val attrs =
satisfyingKeyedPartitioning.expressions.flatMap(_.references)
- val keyRowOrdering = RowOrdering.create(o.ordering, attrs)
+ // A key row holds the values of the partition expressions.
`keysSatisfy` admits a
+ // partitioning here only when those expressions are the
ordering's, position by
+ // position, so each sort order reads its position of the key
row. The expression
+ // need not be a bare column, e.g. a shuffled side's join key
`100 - b`.
+ val keyRowOrdering = RowOrdering.create(
+ o.ordering.zipWithIndex.map { case (order, i) =>
+ SortOrder(BoundReference(i, order.child.dataType, nullable =
true),
+ order.direction, order.nullOrdering, Seq.empty)
Review Comment:
Done in
[8f061e0](https://github.com/apache/spark/pull/59189/commits/8f061e0e8384854e2d87e041471523f56db367c2).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]