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

   ## Which issue does this PR close?
   
   Part of #6385: the "canonicalize NaN in `hash` / `xxhash64`" step.
   
   This is stacked on #6400, so until that merges this diff also contains 
#6400's commits. Only the last commit, 71d6e7be9, is new here. I'll rebase once 
#6400 is in.
   
   ## Rationale for this change
   
   Spark hashes a float through `doubleToLongBits` or `floatToIntBits`. Both 
canonicalize NaN, so every NaN hashes alike. Comet hashed the raw bits. A NaN 
with the sign bit set therefore hashed differently from Spark. Negating a NaN 
produces one on every platform, and on x86-64 every NaN produced by arithmetic 
has the sign bit set:
   
   | Query | Spark | Comet before |
   | --- | --- | --- |
   | `SELECT hash(-d), xxhash64(-d) FROM t WHERE id = 3` | `-1281358385, 
-3127944061524951246` | `-1489914710, 9200374361256412029` |
   
   The hash serde reports float arguments as compatible, so these queries did 
not fall back to Spark.
   
   ## What changes are included in this PR?
   
   - `float_semantics::hash_input` now returns `normalize_float`: `-0.0` hashes 
as `0.0`, as before, and every NaN hashes as the canonical NaN. Since #6400 
every float hash path goes through `hash_input`. That covers `hash`, 
`xxhash64`, list, struct and dictionary elements, the native shuffle's hash 
partitioner, and `approx_count_distinct`.
   - At the default seed, `xxhash64` handed "compatible" arguments to 
datafusion-spark's `SparkXxhash64`, which also hashes a NaN's raw bits. Floats, 
and types containing them, now stay on Comet's kernel. `xxhash64_diff.rs` lists 
the new divergence with a test, like its other known differences from upstream.
   - `approx_count_distinct` no longer runs a separate float normalization pass 
before hashing, because `xxhash64` now gives the same hash on its own. Spark's 
HLL normalizes and then hashes, and gets the same result.
   
   Effects beyond the two functions:
   
   - Native shuffle hash partitioning now sends a row with a non-canonical NaN 
key to the partition Spark picks. This matters when a Comet exchange has to 
agree with a Spark exchange. Joins were not affected, because Spark normalizes 
join keys before the exchange.
   - Runtime bloom filters hash their keys with `xxhash64`. A filter built by 
one engine and probed by the other now agrees on NaN keys.
   
   The extra NaN check costs about 0.17 ns per value in the float hash loop. On 
an M3 Max a batch of 8192 doubles goes from 4.7 µs to 6.1 µs, still about 2x 
faster than before #6400.
   
   datafusion-spark's `SparkXxhash64` has the same gap, which I can report 
upstream.
   
   ## How are these changes tested?
   
   - `hash.sql` gains NaN rows, compared against Spark. One query hashes `d`, 
`-d`, `f` and `-f` with `hash` and `xxhash64`. Another hashes arrays and 
structs of negated values. Against the old library the first query fails with 
the values in the table above. It passes now.
   - A new `CometNativeShuffleSuite` test compares `spark_partition_id()` per 
row against Spark for float keys, including negated NaNs, and asserts that the 
exchange ran natively. With the old hash, the NaN row went to partition 0, 
where Spark puts it in partition 5.
   - New unit tests, each of which fails under the old rule:
     - Spark's hash values for canonical, sign-bit and payload NaNs in the 
`murmur3` and `xxhash64` float tests.
     - Both hashes of non-canonical NaNs inside lists, large lists, fixed-size 
lists, structs and dictionaries.
     - `approx_count_distinct` counting the two zeros as one value and all NaNs 
as one.
     - The `xxhash64` expression path keeping floats on Comet's kernel.
   - Results on macOS aarch64 with the default Spark 4.1 profile:
     - Unit tests: 1025 in spark-expr, 552 in core, 171 in shuffle.
     - `CometSqlFileTestSuite`: 578.
     - `CometHashExpressionSuite` and `CometNativeShuffleSuite`: 100.
   


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