andygrove opened a new pull request, #6475:
URL: https://github.com/apache/datafusion-comet/pull/6475

   ## Which issue does this PR close?
   
   Closes #5507.
   
   Part of #6385: the "nested sort keys and rank (#5507)" step.
   
   ## Rationale for this change
   
   Spark orders floats with `SQLOrderingUtil.compareDoubles` at every depth of 
an array or struct: `-0.0` equals `0.0`, all NaNs are equal, and NaN sorts 
above every other value. #5469 made Comet normalize scalar `FLOAT` and `DOUBLE` 
sort and window keys so that Arrow's total order agrees with Spark's, but a key 
that nests floats in an array or struct was compared raw. There `-0.0` sorts 
below `0.0`, and a NaN with the sign bit set sorts below `-Infinity`. Negating 
a NaN sets that bit on any platform, and on x86-64 every NaN that arithmetic 
produces has it.
   
   With rows holding `-0.0`, `0.0`, a canonical NaN and a sign-bit NaN, among 
others:
   
   | Query | Spark | Comet before |
   | --- | --- | --- |
   | `SELECT id FROM t ORDER BY array(IF(s, -d, d)), id DESC` | `8, 9, 7, 2, 1, 
3, 6, 5, 4` | `8, 5, 9, 7, 1, 2, 3, 6, 4` |
   
   The two zeros (ids 1 and 2) and the two NaNs (ids 4 and 5) are peers in 
Spark, so the tiebreaker orders them; Comet split them and sorted the sign-bit 
NaN first. `RANK`, `DENSE_RANK`, window frames and rank limits over such keys 
had the same gap. `spark.comet.exec.strictFloatingPoint=true` made these keys 
fall back to Spark, unless `spark.comet.expression.SortOrder.allowIncompatible` 
was set.
   
   ## What changes are included in this PR?
   
   - `create_normalized_key_expr`, which builds the keys of Sort, TopK, Window 
and WindowGroupLimit, wraps an array or struct key with a float at any depth in 
`NormalizeNestedFloats`, as it already wrapped a scalar float key in 
`NormalizeNaNAndZero`. Only the comparison key is normalized, so the rows keep 
their original values, zero signs and NaN payloads included.
   - `CometSortOrder` is compatible for every key type, so strict 
floating-point mode no longer makes these keys fall back. Maps cannot be sort 
keys in Spark.
   - Range partitioning needs no change: the native range partitioner only 
accepts scalar keys, and a nested key goes to the JVM shuffle, which partitions 
with Spark's own ordering.
   - The floating-point compatibility guide, the operator compatibility and 
tuning guides, the `spark.comet.exec.strictFloatingPoint` description, the 
native shuffle contributor guide and the shuffle review skill no longer 
describe nested keys as a gap.
   
   ## How are these changes tested?
   
   - `windows/nested_float_order_keys.sql` (new, run with strict floating-point 
mode off and on, and with `SortOrder.allowIncompatible=false` so strict mode 
applies the shipped policy): arrays, structs, arrays of structs and structs of 
arrays of `DOUBLE` and `FLOAT` holding both zeros and both kinds of NaN, as 
keys of `ORDER BY` in both directions, TopK, `RANK`, `DENSE_RANK`, running sums 
over the default `RANGE` frame, and rank limits. Every `ORDER BY` ends with a 
unique tiebreaker, so peers must come out in its order. On `main` its first 
query returns the wrong order shown above, and in strict mode `main` falls back 
to Spark instead.
     - Two nested-null differences that do not involve floats stay out of the 
fixture: the queries keep the default null orders, and the running sums leave 
out the row whose keys hold a null element. Spark orders a null element below 
every value whatever `NULLS FIRST` or `NULLS LAST` says, while the native sort 
ties nested nulls to that option, and DataFusion's `RANGE` frame bounds order a 
null element above every value. Both show up with `INT` keys too, so they need 
their own fix.
   - The rank-limit unit test 
`floating_sort_keys_preserve_window_group_limit_peers` runs its sign-bit, 
payload and signaling NaNs, zeros and nulls through a one-element list and a 
one-field struct as well as bare, and checks the same peers and the same bits. 
It fails at the first list key without the change.
   - `CometExpressionSuite`: the two tests that asserted the strict-mode 
fallback for array and struct sort keys now check that the sort runs natively 
and matches Spark, over data written to Parquet with a unique `id` sorted last. 
A new test sorts on `array(d)` and `named_struct('v', d)` over a local relation 
and checks that NaN payloads and zero signs come back unchanged, with the zeros 
and the two NaNs as peers.
   - Results on macOS aarch64 with the default Spark 4.1 profile:
     - `CometSqlFileTestSuite`: 593, including both runs of the new fixture.
     - `CometExecSuite`: 152. `CometWindowExecSuite`: 67. 
`CometExpressionSuite` floating-point tests: 23.
     - Unit tests in core: 579.
   


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