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

   ## Which issue does this PR close?
   
   Part of #4098.
   
   ## Rationale for this change
   
   `approx_count_distinct` (Spark's `HyperLogLogPlusPlus`) was unsupported, so 
any query using it fell back to Spark. Neither DataFusion nor the 
`datafusion-spark` crate provides a Spark-compatible HyperLogLog++, and 
DataFusion's own `approx_distinct` uses a different hash and algorithm, so its 
estimates would not match Spark. This PR ports Spark's `HyperLogLogPlusPlus` 
exactly so the result is bit-identical.
   
   Note: Spark's `approx_count_distinct` uses the legacy `HyperLogLogPlusPlus`, 
which is a different algorithm from the Apache DataSketches `hll_sketch_agg` 
family. They are not interchangeable, so this does not reuse the DataSketches 
sketch.
   
   ## What changes are included in this PR?
   
   - A native `HllPlusPlus` aggregate 
(`native/spark-expr/src/agg_funcs/hll_plus_plus.rs`) porting 
`HyperLogLogPlusPlusHelper`:
     - Hashes each non-null input with Comet's existing Spark-compatible 
`xxhash64` (seed 42), normalizing floats (`-0.0 -> 0.0`, canonical `NaN`) 
first, exactly as Spark's `NormalizeNaNAndZero` does before hashing.
     - Stores registers in Spark's identical packed-`Long` buffer layout (10 
six-bit registers per 64-bit word), so the partial-aggregation state matches 
Spark's `aggBufferSchema` (`numWords` `Long` columns).
     - Estimates cardinality with linear counting for small inputs and 
bias-corrected HLL otherwise, using the bias-correction tables ported verbatim 
from Spark (`hll_plus_plus_const.rs`, generated from the Spark source).
     - Provides both a scalar `Accumulator` and a vectorized 
`GroupsAccumulator`.
   - `HllPlusPlus` protobuf message (child + precision) and wiring in 
`planner.rs`.
   - `CometApproxCountDistinct` serde, which computes the precision `p` from 
`relativeSD` with Spark's exact formula and passes it through the protobuf. 
Restricts inputs to the atomic types Comet's `xxhash64` hashes identically to 
Spark; other types fall back.
   - Benchmark coverage in `CometAggregateExpressionBenchmark`.
   - Documentation updates (expression support status, expression audit notes).
   
   The 2-argument `HyperLogLogPlusPlus` implementation (algorithm and tables) 
is identical across Spark 3.4.3, 3.5.8, 4.0.1, and 4.1.1, so no version shim is 
needed.
   
   This implementation was scaffolded with the `implement-comet-expression` 
project skill.
   
   ## How are these changes tested?
   
   - A SQL file test 
`spark/src/test/resources/sql-tests/expressions/aggregate/approx_count_distinct.sql`
 that runs each query through both Spark and Comet and asserts equal results 
and native execution. It covers a range of cardinalities from a few up to 50000 
distinct (exercising linear counting, bias correction, and plain HLL), the 
`relativeSD` argument, grouped and global aggregation, all supported input 
types, NULL handling, the empty-table (returns 0) case, and float `-0.0`/`NaN` 
normalization. Equality passing confirms the port is bit-identical to Spark.
   - Rust unit tests in `hll_plus_plus.rs` covering exact small-cardinality 
counts, NULL handling, string inputs, precision derivation, merge equivalence, 
grouped-vs-scalar agreement, and large-cardinality accuracy.


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