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

   ### Is your feature request related to a problem or challenge?
   
   After #26228 (fixing #26226), `HashJoinExec` keeps build-side rows in input 
order on both build paths (`ArrayMap` and `JoinHashMap`). For `LeftSemi`, 
`LeftAnti` and `LeftMark`, every output row comes from the final visited-bitmap 
emission. That emission walks the bitmap in build index order and runs in a 
single stream (the last probe partition to finish), so the output already 
follows the build side's order, in both `CollectLeft` and `Partitioned` mode.
   
   The planner doesn't know this, because `maintains_input_order` only ever 
reports the probe side:
   
   ```rust
   fn maintains_input_order(join_type: JoinType) -> Vec<bool> {
       vec![false, !need_produce_result_in_final(join_type)]
   }
   ```
   
   So the order is an implementation detail, protected only by the tests added 
in #26228. Comet relies on it for null-aware anti joins (`NOT IN`), where 
Spark's streamed side becomes DataFusion's build side, and currently restores a 
sort above the native join instead (apache/datafusion-comet#6787, 
apache/datafusion-comet#6810).
   
   ### Describe the solution you'd like
   
   Report the build side as order-preserving for these join types:
   
   ```rust
   vec![
       matches!(join_type, JoinType::LeftSemi | JoinType::LeftAnti | 
JoinType::LeftMark),
       !need_produce_result_in_final(join_type),
   ]
   ```
   
   `join_equivalence_properties` and `calculate_join_output_ordering` already 
handle `[true, false]` for these join types by passing the left ordering 
through. No right-side ordering is appended, so #25052 doesn't apply. This also 
makes the property symmetric under `JoinSelection`'s input swap, since 
`RightSemi` / `RightAnti` / `RightMark` already report probe-side order.
   
   Things to test:
   
   - A sort above a `LeftSemi` / `LeftAnti` / `LeftMark` hash join over a 
sorted build side is removed, and multi-batch builds keep their order on both 
map paths.
   - Null-aware anti and mark joins keep the order. Their final-index 
post-processing only filters rows, so it should hold.
   - Plan diffs: with the left side order-preserving, `EnforceDistribution` / 
`EnforceSorting` may choose differently under a `CollectLeft` build side, e.g. 
an order-preserving merge instead of `CoalescePartitionsExec`.
   
   Interactions with planned work:
   
   - #22929 (emit `LeftSemi` output incrementally) would emit matched rows in 
probe order, so `LeftSemi` would have to stop reporting build order if that 
lands. If that's likely, starting with `LeftAnti` and `LeftMark` avoids the 
conflict, since neither can emit anything before the probe side is exhausted.
   - #24768 (spilling hash join) emits unmatched build rows per bucket once 
something spills, so the property would need to be dropped under 
`enable_hash_join_spilling`, the same way that epic already plans to drop the 
probe-side property.
   
   ### Describe alternatives you've considered
   
   Document the build-side order on `HashJoinExec` without reporting it to the 
planner. Embedders would get a documented contract, but DataFusion couldn't use 
it to remove sorts.
   
   ### Additional context
   
   - #26226 / #26228: makes the build-side order independent of which map the 
build uses
   - apache/datafusion-comet#6787, apache/datafusion-comet#6810
   


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