Uh oh!
There was an error while loading. Please reload this page.
Add support for dictionary for approx_distinct - #24646
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## main #24646 +/- ##
==========================================
- Coverage 81.63% 81.59% -0.05%
==========================================
Files 1123 1123 Lines 410298 410970 +672 Branches 410298 410970 +672 ==========================================
+ Hits 334965 335333 +368 - Misses 55642 55893 +251 - Partials 19691 19744 +53 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
mkleen
commented
Aug 25, 2026
kumarUjjawal
left a comment
There was a problem hiding this comment.
Thank you @mkleen this looks good overall. I had two comments please check.
| | DataType::Map(_, _) | ||
| | DataType::Struct(_) | ||
| | DataType::Union(_, _) | ||
| | DataType::Dictionary(_, _) |
There was a problem hiding this comment.
Would it work to match on the value type instead, so a dictionary is supported exactly when its values would be? Something like DataType::Dictionary(_, value_type)
There was a problem hiding this comment.
Good point. Floats will be unsupported see #23084, So we should exclude them in all container types.
There was a problem hiding this comment.
i still feel we can support floats here if we already support it in regular distinct count 🤔
also for reference seems duckdb supports:
memory D select approx_count_distinct(a) fromvalues (1.5::double), (1.5), ('nan'::double), (null), (0) t(a);
┌──────────────────────────┐
│ approx_count_distinct(a) │
│ int64 │
├──────────────────────────┤
│ 3 │
└──────────────────────────┘There was a problem hiding this comment.
Ok makes sense. I will look into this.
There was a problem hiding this comment.
The unconditional arm accepts dictionaries whose value type remains intentionally unsupported.
For example, Dictionary(Int32, Float64) reaches HLLAccumulator, whose hashing path supports floats, although plain Float64 returns NotImplemented. Grouped aggregation also bypasses the restriction through GroupsAccumulatorAdapter.
We can validate the value type recursively with a shared supported-type predicate and add a negative float-dictionary regression.
| | DataType::Map(_, _) | ||
| | DataType::Struct(_) | ||
| | DataType::Union(_, _) | ||
| | DataType::Dictionary(_, _) |
There was a problem hiding this comment.
would it make sense to have both dictionary arms on the value type, so Dictionary(_, value_type) is accepted only when is_hll_groups_type(value_type) is true?
There was a problem hiding this comment.
That's a good idea. Thank you!
Rich-T-kid
left a comment
There was a problem hiding this comment.
you beat me to it #24731 😆.
f2593d7 to
a3520c7Comparea3520c7 to
5f60729Comparec898a95 to
9f9aa29Compare| /// [`HllGroupsAccumulator`]. The fixed-domain types (booleans / small ints) and | ||
| /// `Null` fall back to the per-group [`Accumulator`] path. | ||
| fn is_hll_groups_type(data_type: &DataType) -> bool { | ||
| if let DataType::Dictionary(_, value_type) = data_type { |
There was a problem hiding this comment.
Recursing here returns false for dictionaries containing Boolean, small integers, or Null, because those plain types use specialized scalar accumulators. The grouped executor then creates one HLLAccumulator per group through GroupsAccumulatorAdapter; each accumulator embeds a 16 KiB sketch. A dictionary-encoded Boolean with 100,000 groups can therefore consume about 1.5 GiB for sketches alone. Please route every supported dictionary through HllGroupsAccumulator, or provide a compact dictionary-aware fallback, and add a path-sensitive regression for a fixed-domain dictionary.
| | DataType::Map(_, _) | ||
| | DataType::Struct(_) | ||
| | DataType::Union(_, _) | ||
| | DataType::Dictionary(_, _) |
There was a problem hiding this comment.
The unconditional arm accepts dictionaries whose value type remains intentionally unsupported.
For example, Dictionary(Int32, Float64) reaches HLLAccumulator, whose hashing path supports floats, although plain Float64 returns NotImplemented. Grouped aggregation also bypasses the restriction through GroupsAccumulatorAdapter.
We can validate the value type recursively with a shared supported-type predicate and add a negative float-dictionary regression.
mkleen
commented
Sep 4, 2026
@kumarUjjawal Thanks for the review. Could you do one more pass please? |
kumarUjjawal
left a comment
There was a problem hiding this comment.
Thank you @mkleen for all the iterations.
Uh oh!
There was an error while loading. Please reload this page.
…24646) Resolves merge conflict between HEAD's type-specific HLL accumulators and the upstream dictionary support commit. Implements dictionary handling via a DictionaryAccumulator wrapper that casts to the value type before delegating to the appropriate inner accumulator. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…24646) Resolves merge conflict between HEAD's type-specific HLL accumulators and the upstream dictionary support commit. Implements dictionary handling via a DictionaryAccumulator wrapper that casts to the value type before delegating to the appropriate inner accumulator. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anch [cherry-pick] Add support for dictionary for approx_distinct (apache#24646) Co-authored-by: Rich-T-kid <richard.baah@datadoghq.com> Co-authored-by: mkleen <mkleen@gmail.com>
…anch-55 [Cherry-pick] Add support for dictionary for approx_distinct (apache#24646)
Which issue does this PR close?
approx_distinctfunction #22989 but does not close it. More types are coming.Rationale for this change
Dictionaryforapprox_distinctWhat changes are included in this PR?
HLLAccumulatorandHllGroupsAccumulatorto supportDictionaryAre these changes tested?
Yes
Are there any user-facing changes?
Yes,
approx_distinctsupports nowDictionarybut no breaking changes.