andygrove opened a new issue, #6770:
URL: https://github.com/apache/datafusion-comet/issues/6770

   ### Describe the bug
   
   With `spark.comet.exec.forceShuffledHashJoin=true`, a local sort above a 
sort-merge join is lost when `RewriteJoin` converts that join to a hash join. 
Spark's `RemoveRedundantSorts` runs before Comet's rules and deletes the 
`SortExec`, because the sort-merge join's output ordering already satisfies it. 
`RewriteJoin` then replaces the join with a `ShuffledHashJoinExec` and drops 
its input sorts, so the ordering is gone and nothing puts it back. It only 
happens when the join's ordering satisfies the sort, which means the sort keys 
are the join keys or a leading prefix of them.
   
   Two things break:
   
   - `sortWithinPartitions(k)` and `SORT BY k` return partitions that are not 
sorted. The rows are right, and nothing reports the problem.
   - A partitioned insert whose partition column is the join key fails. Spark's 
planned write (`V1Writes`) adds a local sort on the partition columns, and that 
is the sort that gets removed. Spark's single dynamic-partition writer expects 
sorted input. When a partition value comes back, it opens the same file name 
again and the task fails with `FileAlreadyExistsException`.
   
   ### Steps to reproduce
   
   Parquet tables `big` as `(i % 100, i)` for 10000 rows and `small` as `(i * 
10, i)` for 10 rows, with:
   
   ```
   spark.comet.exec.forceShuffledHashJoin=true
   spark.sql.autoBroadcastJoinThreshold=-1
   spark.sql.adaptive.autoBroadcastJoinThreshold=-1
   spark.sql.shuffle.partitions=2
   ```
   
   Unsorted partitions, with AQE on or off:
   
   ```scala
   val df = spark
     .sql("SELECT big._1 AS k, big._2 AS v FROM big JOIN small ON big._1 = 
small._1")
     .sortWithinPartitions("k")
   df.rdd
     .mapPartitions { it =>
       val ks = it.map(_.getInt(0)).toArray
       Iterator(ks.sameElements(ks.sorted))
     }
     .collect()
   // Array(false, false) here, Array(true, true) with 
forceShuffledHashJoin=false
   ```
   
   Appending `SORT BY k` to the query gives the same result. The plan has 
`CometHashJoin` directly under the final `CometProject`, with no sort above it.
   
   Failed insert, with AQE on or off:
   
   ```sql
   CREATE TABLE out (v INT, w INT, k INT) USING parquet PARTITIONED BY (k);
   INSERT OVERWRITE TABLE out
   SELECT big._2, small._2, big._1 FROM big JOIN small ON big._1 = small._1;
   ```
   
   ```
   org.apache.spark.SparkException: [TASK_WRITE_FAILED] Task failed while 
writing rows to file:/.../out. SQLSTATE: 58030
   ...
   Caused by: org.apache.hadoop.fs.FileAlreadyExistsException: File already 
exists: file:/.../out/_temporary/.../k=10/part-00000-<job 
id>.c000.snappy.parquet
   ```
   
   With `forceShuffledHashJoin=false`, the insert writes one file per partition 
and all 1000 rows. That plan has `WriteFiles` directly over 
`CometSortMergeJoin` with no sort between them, because Spark already removed 
the write's sort as redundant. With the force config on, a `CometHashJoin` sits 
in the same place.
   
   Reproduced on `main` with Spark 4.1.
   
   ### Expected behavior
   
   The same result as Spark: every partition sorted by `k`, and the insert 
succeeds.
   
   ### Additional context
   
   Setting `spark.sql.execution.removeRedundantSorts=false` works around both 
cases. Spark then keeps the `SortExec`, the partitions come back sorted and the 
insert succeeds.
   
   #6384 adds a pass after the rewrite that restores any ordering an operator 
above still requires. That fixes a kept sort-merge join above a rewritten one 
(#6673) and a window over one, but it can't fix this. Nothing left in the plan 
requires the ordering, because `WriteFilesExec` declares no required child 
ordering. `sortWithinPartitions` output is still unsorted on that branch.
   
   `branch-1.1` has the same rewrite, so 1.1.0 is affected too.
   
   One way to fix it is to choose the hash join before `EnsureRequirements` and 
`RemoveRedundantSorts` run, for example in a planner strategy, so that Spark 
places and keeps the sorts itself.
   


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