dongjoon-hyun commented on code in PR #59323:
URL: https://github.com/apache/spark/pull/59323#discussion_r4283222345


##########
sql/core/src/test/scala/org/apache/spark/sql/connector/KeyGroupedPartitioningSuite.scala:
##########
@@ -5645,6 +5664,46 @@ class KeyGroupedPartitioningSuite
     }
   }
 
+  test("SPARK-59971: a side is laid out on another only if its keys cover 
every join key") {

Review Comment:
   The migration guide says "A cogroup changes the same way", but this test and 
the changed ones only run joins. The existing cogroup tests in 
`EnsureRequirementsSuite`, e.g. SPARK-59080 "pushed-down positions index into 
the child's own partition expressions", use keyed sides that cover the cogroup 
key.
   
   Could we add a cogroup case where the keyed side covers only some of the 
cogroup keys? For example, a `FlatMapCoGroupsInPandasExec` over a keyed child 
and an unpartitioned child, checking that both sides are shuffled with the conf 
on and only the unpartitioned one with it off.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/physical/partitioning.scala:
##########
@@ -2470,6 +2487,11 @@ case class KeyedShuffleSpec(
       // cannot rewrite it. This also keeps the unprojected spec returned by 
`createShuffleSpec`
       // for a marked narrowing projection from being chosen as the best spec.
       keyPositions.forall(_.nonEmpty) &&
+      // A child lined up on these keys is co-partitioned only on the cluster 
keys they cover. So
+      // the co-partition key requirement applies here too. It uses the 
coverage rule of
+      // `referencesAllClusterKeys`, not the positional match of 
`HashShuffleSpec`.
+      (!SQLConf.get.getConf(SQLConf.REQUIRE_ALL_CLUSTER_KEYS_FOR_CO_PARTITION) 
||

Review Comment:
   This checks coverage against this side's own clustering only. When that 
clustering repeats a key, the child shuffled onto this layout can still end up 
on only some of its own join keys.
   
   For `x.a = y.c AND x.a = y.d`, with `x` partitioned on `a` and `y` 
unpartitioned, the left clustering is `[a, a]`. `[a]` covers it, so `x` is 
picked as the layout. `y` is then shuffled with `createPartitioning([c, d])`. 
`keyPositions` of `a` is `{0, 1}`, and `clustering(positionSet.head)` at L2516 
takes `c`, so `y` is partitioned on `c` alone and `d` is not covered.
   
   This is a different path from my earlier comment on L2490, which is about 
the side paired through `isCompatibleWith`. I found it by reading the code and 
have not run it. The answer is still correct, since the matched rows have `c = 
d`. But the migration guide says the rule holds when the other side "is 
shuffled onto those keys". Either the guide should leave out a repeated join 
key, or `pickCoPartitionTarget` should also check the coverage of the 
partitioning it builds for the re-shuffled child.



##########
sql/core/src/test/scala/org/apache/spark/sql/execution/exchange/EnsureRequirementsSuite.scala:
##########
@@ -1467,9 +1467,11 @@ class EnsureRequirementsSuite extends SharedSparkSession 
{
         KeyedPartitioning(Seq(id, t1), keys))))
     val unpartitioned = DummySparkPlan(outputPartitioning = 
UnknownPartitioning(0))
 
+    // The coarse member covers only `id`, so the co-partition key requirement 
is turned off.

Review Comment:
   With the conf now off here and in the test at L1615, no test covers the 
default case for a collection: the coarse member `[id, t2]` cannot serve, and 
the re-shuffled side has to land on `[id, t1]`.
   
   Could we also run this test with the conf on, and assert the same placement? 
Otherwise, under the default conf, a regression in `pickCoPartitionTarget` that 
picks the coarse member, or no member at all, would not fail any test.



##########
docs/sql-performance-tuning.md:
##########
@@ -684,7 +684,7 @@ The following SQL properties enable Storage Partition Join 
in different join que
       <td><code>spark.sql.sources.v2.bucketing.shuffle.enabled</code></td>
       <td>false</td>
       <td>
-        When enabled, try to avoid shuffle on one side of the join, by 
recognizing the partitioning reported by a V2 data source on the other side.
+        When enabled, try to avoid shuffle on one side of the join, by 
recognizing the partitioning reported by a V2 data source on the other side. 
With <code>spark.sql.requireAllClusterKeysForCoPartition</code> on, the 
partition keys must cover every join key.

Review Comment:
   A correction to this comment: this page does document 
`spark.sql.requireAllClusterKeysForCoPartition`, in the row at L652-656 of the 
same table, so the pointer here is fine.
   
   That row still describes the conf only for storage-partitioned join, though. 
Could we update it as well, to say that the conf now also decides whether a 
one-side shuffle can run on partition keys that cover only some of the join 
keys?



-- 
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]

Reply via email to