Skip to content

Feat: add dictionaries as a supported group column type - #23187

Open
Rich-T-kid wants to merge 6 commits into
apache:mainfrom
Rich-T-kid:rich-T-kid/dictionary-groupValuesColumn-impl
Open

Feat: add dictionaries as a supported group column type#23187
Rich-T-kid wants to merge 6 commits into
apache:mainfrom
Rich-T-kid:rich-T-kid/dictionary-groupValuesColumn-impl

Conversation

@Rich-T-kid

@Rich-T-kid Rich-T-kid commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

This PR introduces a specialized GroupColumn implementation for dictionary-typed columns inside GroupValuesColumn, allowing dictionary columns to participate in the columnar, vectorized aggregation path instead of the row-based fallback.

The Implementation is only about 175+ lines of code. the remaining LOC is adding extensive test at the GroupColumn trait level as well as testing the GroupValuesColumn GroupValues trait and how it inter-opts with multi-dictionary group by's.

What changes are included in this PR?

  • Adds a DictionaryGroupValueBuilder struct implementing the GroupColumn trait for Dictionary-typed group-by columns, supporting a configurable subset of value types
  • Extends the type-check gate in GroupValuesColumn::try_new (the matches! block) to accept Dictionary(_, value_type) where value_type is already supported.
  • Adds schema-level support so emitted dictionary group key columns round-trip through the output schema correctly
  • removes casting thats done for each dictionary array in emit

Are these changes tested?

yes. a majority of this PR is test

Are there any user-facing changes?

no. this is a pure perf boost for users.

@github-actions github-actions Bot added the physical-plan Changes to the physical-plan crate label Jun 25, 2026
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch 2 times, most recently from 3f7ff57 to e6b6dce Compare July 1, 2026 04:25
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@kumarUjjawal could you run the dictionary benchmarks on this PR? Thx

}
}
DataType::Dictionary(key_dt, value_dt) => {
let new_field = Field::new("", *value_dt.clone(), true);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this field is never read again it may be fine to ignore the name field.

should be weary of similar issues to #21765 (comment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of annoying that make_group_column takes a field instead of a DataType. Maybe we can change that in a follow up PR?

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
@Rich-T-kid

Rich-T-kid commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@kumarUjjawal wanted to bump this 😄

@geoffreyclaude

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c4856707692-778-smmmp 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing rich-T-kid/dictionary-groupValuesColumn-impl (eb41915) to 01bf68c (merge-base) diff using: dictionary_group_values
Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                                                             HEAD                                   rich-T-kid_dictionary-groupValuesColumn-impl
-----                                                                             ----                                   --------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.15    869.8±5.08µs 71.9 MElem/sec    1.00  756.8±139.44µs 82.6 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.22    779.9±5.80µs 80.1 MElem/sec    1.00   636.7±43.49µs 98.2 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.17    809.2±5.84µs 77.2 MElem/sec    1.00  692.8±108.32µs 90.2 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      2.45      6.3±0.01ms 10.0 MElem/sec    1.00      2.6±0.04ms 24.5 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.24    800.2±6.35µs 78.1 MElem/sec    1.00    645.5±6.09µs 96.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.42    160.1±0.87µs 48.8 MElem/sec    1.00   112.7±15.66µs 69.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.28    104.0±1.39µs 75.1 MElem/sec    1.00     81.5±0.45µs 95.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.30    121.2±1.05µs 64.5 MElem/sec    1.00     92.9±9.63µs 84.1 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.17    109.7±1.26µs 71.2 MElem/sec    1.00    94.1±13.82µs 83.0 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        2.66    678.0±2.09µs 11.5 MElem/sec    1.00   255.3±12.37µs 30.6 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.04      4.4±0.02ms 57.4 MElem/sec    1.00      4.2±0.01ms 59.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.02      4.1±0.02ms 60.5 MElem/sec    1.00      4.1±0.01ms 61.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.01      4.2±0.02ms 59.2 MElem/sec    1.00      4.2±0.01ms 60.1 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.54     16.5±0.05ms 15.2 MElem/sec    1.00     10.7±0.06ms 23.4 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.01      4.2±0.02ms 59.3 MElem/sec    1.00      4.2±0.01ms 60.2 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.13    618.7±3.27µs 50.5 MElem/sec    1.00    549.9±6.40µs 56.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.00    512.1±3.06µs 61.0 MElem/sec    1.00    511.2±3.10µs 61.1 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.05    550.0±3.63µs 56.8 MElem/sec    1.00    522.5±2.60µs 59.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.02    526.6±2.85µs 59.3 MElem/sec    1.00    515.0±2.45µs 60.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.74   1479.0±6.20µs 21.1 MElem/sec    1.00    847.9±5.26µs 36.9 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 380.1s
Peak memory 592.6 MiB
Avg memory 94.8 MiB
CPU user 227.9s
CPU sys 14.8s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 330.1s
Peak memory 464.6 MiB
Avg memory 67.9 MiB
CPU user 225.8s
CPU sys 19.2s
Peak spill 0 B

File an issue against this benchmark runner

@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch 2 times, most recently from 770abfe to 243a557 Compare July 1, 2026 15:32
@Rich-T-kid Rich-T-kid changed the title [Draft][22715] introduce dictionarys as a supported group column type Feat:[Draft][22715] add dictionaries as a supported group column type Jul 1, 2026
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@codex review

@kumarUjjawal

Copy link
Copy Markdown
Contributor

@kumarUjjawal wanted to bump this 😄

@Rich-T-kid Thank you! I have been sick so I won't be available for review. I will probably get back next week.

@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@Rich-T-kid Thank you! I have been sick so I won't be available for review. I will probably get back next week.

@kumarUjjawal Sorry to hear that. I hope you feel better! no rush on the review!

@Rich-T-kid Rich-T-kid left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revision #2

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/mod.rs Outdated
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch from 4ee52da to 7af7080 Compare July 2, 2026 19:18

@Rich-T-kid Rich-T-kid left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revision #3

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/mod.rs Outdated
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch from 152c1f0 to f3387c5 Compare July 5, 2026 03:59
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author
Image 7-6-26 at 4 05 PM Latest PR speeds up the low cardinality case

@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@geoffreyclaude could you run the benchmarks command again when you get a chance. Thanks 🚀

@geoffreyclaude

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c4897199089-877-zms2m 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing rich-T-kid/dictionary-groupValuesColumn-impl (3d1e1c9) to 01bf68c (merge-base) diff using: dictionary_group_values
Results will be posted here when complete


File an issue against this benchmark runner

@Rich-T-kid Rich-T-kid left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revision #4 Last revision before making this open for review

cached_combined: Option<ArrayRef>,
/// Per-call group equality cache for the low-cardinality path. `Mutex`
/// because `vectorized_equal_to` takes `&self`; always uncontended.
group_eq_cache: Mutex<Vec<Option<bool>>>,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a work around needed because vectorized_equal_to takes in a &self as opposed to &mut self. This means the alternative is needing to allocate target_batch_size arrays for each intern() call instead of re-using the vector.

Originally planned to use RefCell but its not Send + Sync

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't incur any overhead since there no contention but I'm happy to explore other ideas.

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                                                             HEAD                                   rich-T-kid_dictionary-groupValuesColumn-impl
-----                                                                             ----                                   --------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.23    871.4±8.87µs 71.7 MElem/sec    1.00    707.5±5.34µs 88.3 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.30    790.0±9.68µs 79.1 MElem/sec    1.00    608.0±7.50µs 102.8 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.23   815.1±10.24µs 76.7 MElem/sec    1.00    665.2±5.90µs 94.0 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      2.51      6.2±0.02ms 10.0 MElem/sec    1.00      2.5±0.01ms 25.1 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.23    804.8±8.79µs 77.7 MElem/sec    1.00    655.6±9.93µs 95.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.35    161.5±1.39µs 48.4 MElem/sec    1.00   119.8±17.59µs 65.2 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.31    104.8±1.68µs 74.5 MElem/sec    1.00     80.0±0.85µs 97.7 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.34    123.0±1.59µs 63.5 MElem/sec    1.00    92.0±10.05µs 84.9 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.29    112.0±6.33µs 69.7 MElem/sec    1.00    86.6±30.70µs 90.2 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        2.70    681.0±3.01µs 11.5 MElem/sec    1.00    252.0±1.80µs 31.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.45      4.4±0.03ms 57.1 MElem/sec    1.00      3.0±0.01ms 82.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.58      4.2±0.02ms 60.1 MElem/sec    1.00      2.6±0.02ms 94.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.48      4.2±0.02ms 58.9 MElem/sec    1.00      2.9±0.01ms 87.4 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.40     17.0±0.13ms 14.7 MElem/sec    1.00     12.2±0.13ms 20.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.51      4.2±0.03ms 59.1 MElem/sec    1.00      2.8±0.02ms 89.1 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.29    620.6±3.17µs 50.4 MElem/sec    1.00    480.4±1.96µs 65.1 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.54    513.2±3.32µs 60.9 MElem/sec    1.00    332.5±5.61µs 94.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.48    549.7±3.56µs 56.8 MElem/sec    1.00    370.5±1.52µs 84.3 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.53    528.9±3.45µs 59.1 MElem/sec    1.00    344.6±4.98µs 90.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.52   1486.9±5.41µs 21.0 MElem/sec    1.00    975.5±4.94µs 32.0 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 290.1s
Peak memory 587.7 MiB
Avg memory 124.8 MiB
CPU user 227.7s
CPU sys 15.5s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 320.1s
Peak memory 486.4 MiB
Avg memory 71.3 MiB
CPU user 210.2s
CPU sys 15.2s
Peak spill 0 B

File an issue against this benchmark runner

@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

🤔 benchmarks show good improvement in every case but it should be much larger. Currently every intern() call causes the cache to be rebuilt from the bottom up. Instead of a flat vector it may make sense to use a hashtable that last in-between calls.

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch from 38d656f to fb60ab3 Compare July 27, 2026 14:43
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

thank you for the review @zhuqi-lucas, the two latest PR's should address your comments + test.

@kumarUjjawal @zhuqi-lucas can we run the benchmarks one more time to make sure theres no meaningful regressions

@zhuqi-lucas

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

Benchmark for this request failed.

Last 20 lines of output:

Click to expand
 * [new tag]             48.0.0-rc1     -> 48.0.0-rc1
 * [new tag]             48.0.0-rc2     -> 48.0.0-rc2
 * [new tag]             5.0.0          -> 5.0.0
 * [new tag]             5.0.0-rc1      -> 5.0.0-rc1
 * [new tag]             5.0.0-rc3      -> 5.0.0-rc3
 * [new tag]             6.0.0          -> 6.0.0
 * [new tag]             6.0.0-rc0      -> 6.0.0-rc0
 * [new tag]             7.0.0          -> 7.0.0
 * [new tag]             7.0.0-rc2      -> 7.0.0-rc2
 * [new tag]             8.0.0          -> 8.0.0
 * [new tag]             8.0.0-rc1      -> 8.0.0-rc1
 * [new tag]             8.0.0-rc2      -> 8.0.0-rc2
 * [new tag]             9.0.0          -> 9.0.0
 * [new tag]             9.0.0-rc1      -> 9.0.0-rc1
 * [new tag]             ballista-0.5.0 -> ballista-0.5.0
 * [new tag]             ballista-0.6.0 -> ballista-0.6.0
 * [new tag]             ballista-0.7.0 -> ballista-0.7.0
 * [new tag]             python-0.3.0   -> python-0.3.0
 * [new tag]             python-0.4.0   -> python-0.4.0
Switched to branch 'rich-T-kid/dictionary-groupValuesColumn-impl'

File an issue against this benchmark runner

@zhuqi-lucas

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5101303899-1282-xgvq9 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing rich-T-kid/dictionary-groupValuesColumn-impl (e994180) to bb75d92 (merge-base) diff using: dictionary_group_values
Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                                                             HEAD                                   rich-T-kid_dictionary-groupValuesColumn-impl
-----                                                                             ----                                   --------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.75    868.4±6.55µs 72.0 MElem/sec    1.00    496.4±4.75µs 125.9 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.85    773.8±5.83µs 80.8 MElem/sec    1.00    418.0±6.17µs 149.5 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.80    805.1±9.12µs 77.6 MElem/sec    1.00    448.2±5.47µs 139.4 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      1.00      6.2±0.01ms 10.1 MElem/sec    1.00      6.2±0.02ms 10.1 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.81    792.5±6.70µs 78.9 MElem/sec    1.00    439.0±7.10µs 142.4 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.25    160.4±1.28µs 48.7 MElem/sec    1.00   128.5±21.99µs 60.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.58    103.2±1.06µs 75.7 MElem/sec    1.00    65.2±91.26µs 119.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.55    120.2±1.02µs 65.0 MElem/sec    1.00     77.8±9.43µs 100.4 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.73    109.2±1.07µs 71.5 MElem/sec    1.00     63.0±0.85µs 124.1 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        1.27    673.2±2.55µs 11.6 MElem/sec    1.00    531.2±2.23µs 14.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.80      4.2±0.01ms 58.9 MElem/sec    1.00      2.4±0.00ms 105.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.83      4.1±0.01ms 61.6 MElem/sec    1.00      2.2±0.01ms 112.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.79      4.1±0.01ms 60.6 MElem/sec    1.00      2.3±0.00ms 108.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.08     17.1±0.06ms 14.6 MElem/sec    1.00     15.9±0.15ms 15.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.79      4.1±0.01ms 60.9 MElem/sec    1.00      2.3±0.01ms 109.3 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.49    592.1±1.72µs 52.8 MElem/sec    1.00    396.6±1.44µs 78.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.79    490.9±1.48µs 63.7 MElem/sec    1.00    274.6±2.07µs 113.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.68    524.5±2.41µs 59.6 MElem/sec    1.00    313.0±2.15µs 99.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.75    504.2±1.44µs 62.0 MElem/sec    1.00    288.0±2.15µs 108.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.23   1451.6±5.64µs 21.5 MElem/sec    1.00   1179.7±3.71µs 26.5 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 375.1s
Peak memory 580.2 MiB
Avg memory 125.0 MiB
CPU user 229.5s
CPU sys 11.5s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 375.1s
Peak memory 858.9 MiB
Avg memory 81.1 MiB
CPU user 224.5s
CPU sys 15.3s
Peak spill 0 B

File an issue against this benchmark runner

@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

nice no regressions 🚀

Comment thread datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs Outdated
let old_inner_len = self.inner.len();
let all_inner_values = self.inner.take_n(old_inner_len);

let emitted =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Draining all inner values may be required by the trait, but returning all of them in the emitted dictionary is not. Once all_inner_values is available, the values referenced by the emitted groups can be compacted and their keys remapped separately from the remaining groups.

The bytes example copies the remaining data, but its output contains only the requested prefix. Here, every partial batch still retains and may serialize values needed only by later batches, so the quadratic output cost remains.

Rich-T-kid and others added 5 commits July 30, 2026 14:46
 add schema support for dictionarys

introduce high level GroupValuesColumn test

 introduce groupColumn trait test

git issues

introduce edge case/ regression section

inital impl

working implementation of dictionary for groupValuesCOlumns

benchmarks show perf boost over groupvaluerows, TODO:dedupe items before inner append

fix clippy errors & inline final builder

add cache for arc ptr

trim down test

trim test LOC again

trim PR

revision 3

speed up low cardinlaity case

working version

introduce inter-batch caching

break complex types into seperate parts

fixed breaking test, re-allocate hashtable on each intern() call

 re-introduce cache

remove mutex

add cache to concat pointers to avoid un-needed allocations

remove ptr caches and concat call

reduce LOC

revised PR comments

 add regression test to align with GroupValueRows & re-order overflow check

add test to assert de-duplicated output dictionary

tmp low card speed up

optimize low-card case

wip

re-use allocations across calls

add test

final clean up
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch from e994180 to cc5923e Compare July 31, 2026 04:16
@Rich-T-kid
Rich-T-kid force-pushed the rich-T-kid/dictionary-groupValuesColumn-impl branch from cc5923e to c98c47f Compare July 31, 2026 04:19
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@kumarUjjawal commit c98c47f:

  • Fix take_n null-slot ordering: After compaction, null is always placed at the last slot so check_key_overflow can correctly exclude it from the key count, previously take_n could reorder null to a mid-slot position, causing a valid Int8 dictionary to panic at capacity. also added a test asserting this behavior
  • Compact emitted values in take_n: The emitted dictionary now only contains values referenced by the emitted groups (via take()) rather than all distinct values ever seen, eliminating the quadratic serialization cost on partial emits.

is there anything else?

@Rich-T-kid
Rich-T-kid requested a review from kumarUjjawal July 31, 2026 04:30
@kumarUjjawal

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5139289178-1321-q5dkt 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing rich-T-kid/dictionary-groupValuesColumn-impl (c98c47f) to 30ae8bf (merge-base) diff

Run configuration
run benchmark dictionary_group_values

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing rich-T-kid/dictionary-groupValuesColumn-impl (c98c47f) to 30ae8bf (merge-base) diff

Run configuration
run benchmark dictionary_group_values
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                                                             HEAD                                   rich-T-kid_dictionary-groupValuesColumn-impl
-----                                                                             ----                                   --------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.76    869.7±6.63µs 71.9 MElem/sec    1.00    494.8±3.92µs 126.3 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.86    779.0±5.49µs 80.2 MElem/sec    1.00   418.7±10.22µs 149.3 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.80    808.5±4.98µs 77.3 MElem/sec    1.00    448.1±4.75µs 139.5 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      1.02      6.1±0.01ms 10.2 MElem/sec    1.00      6.0±0.01ms 10.4 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.83    804.3±8.17µs 77.7 MElem/sec    1.00    438.9±6.71µs 142.4 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.25    159.7±1.12µs 48.9 MElem/sec    1.00    127.2±1.90µs 61.4 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.82    103.3±0.93µs 75.6 MElem/sec    1.00     56.6±0.70µs 138.0 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.58    121.5±1.08µs 64.3 MElem/sec    1.00     77.1±0.50µs 101.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.73    109.8±1.14µs 71.2 MElem/sec    1.00     63.3±9.43µs 123.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        1.22    659.2±2.62µs 11.9 MElem/sec    1.00    538.3±2.83µs 14.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.81      4.3±0.01ms 58.4 MElem/sec    1.00      2.4±0.00ms 106.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.83      4.1±0.01ms 61.6 MElem/sec    1.00      2.2±0.00ms 113.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.78      4.1±0.01ms 60.4 MElem/sec    1.00      2.3±0.00ms 107.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.09     17.1±0.05ms 14.6 MElem/sec    1.00     15.8±0.05ms 15.9 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.80      4.1±0.01ms 60.5 MElem/sec    1.00      2.3±0.00ms 109.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.49    598.9±2.08µs 52.2 MElem/sec    1.00    400.8±1.71µs 78.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.82    493.7±2.33µs 63.3 MElem/sec    1.00    271.4±1.20µs 115.2 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.68    526.0±2.11µs 59.4 MElem/sec    1.00    313.8±2.21µs 99.6 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.77    505.8±2.21µs 61.8 MElem/sec    1.00    285.4±2.00µs 109.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.21   1471.3±6.77µs 21.2 MElem/sec    1.00   1219.6±4.86µs 25.6 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 530.1s
Peak memory 505.7 MiB
Avg memory 95.8 MiB
CPU user 230.5s
CPU sys 10.4s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 530.1s
Peak memory 886.9 MiB
Avg memory 64.6 MiB
CPU user 228.9s
CPU sys 14.0s
Peak spill 0 B

File an issue against this benchmark runner

if all_inner_values.is_null(old) {
None
} else {
Some(K::Native::usize_as(emit_old_to_new[old]))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null participates in emitted slot ordering. At key capacity, the final value gets index 128 for Int8 or 256 for UInt8. Int8 panics; UInt8 wraps and returns the wrong value. Move null last or exclude it. Add repeated boundary-emission tests.

}

fn take_n(&mut self, n: usize) -> ArrayRef {
let old_inner_len = self.inner.len();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every partial emit still drains, hashes, and rebuilds all surviving values, retaining the O(G² / batch_size) cost and high peak memory. Also, Arrow take retains full backing storage for Utf8View, BinaryView, and nested dictionaries.

// Keys are raw slot indices. The null slot is excluded from key count
// only when it occupies the last position — any non-null slot above it
// still emits that slot's raw index as a key.
let inner_len = self.inner.len();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null first plus the maximum non-null values fails, while the same values with null last succeeds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

physical-plan Changes to the physical-plan crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants