feat: add GroupColumn support for Duration in multi-column GROUP BY - #23783
Conversation
…lumn GROUP BY `multi_group_by::group_column_supported_type` gates which GROUP BY columns can use the column-wise `GroupValuesColumn` fast path. Any unsupported column forces the entire grouping onto the byte-encoded `GroupValuesRows` fallback, so a single `Duration` key dragged an otherwise-qualifying multi-column GROUP BY onto the slow path. `Duration` shares the `i64` native representation of `Timestamp`, so it reuses the existing `PrimitiveGroupValueBuilder` with no new builder type: - dispatch the four `Duration*Type` units in `make_group_column` - accept `Duration(_)` in `group_column_supported_type` (all four units are valid Arrow types, unlike Time32/Time64) - extend the `group_column_supported_type` <-> `make_group_column` consistency fuzz with the four Duration units - add an end-to-end unit test (Duration GROUP BY dedups including nulls and preserves the Duration output type) and a Duration GROUP BY block (single- and multi-column keys) in aggregate.slt - add a `(Duration, Int32)` group-count benchmark to `benches/multi_group_by.rs` Part of apache#22715
| fn test_group_values_column_duration() { | ||
| use arrow::datatypes::TimeUnit; | ||
|
|
||
| let schema = Arc::new(Schema::new(vec![Field::new( |
There was a problem hiding this comment.
Nice addition to cover Duration group keys. One small thought: this regression is specifically about the multi-column all-or-nothing gate, but this unit test exercises a single-column Duration GroupValuesColumn. The SQL logic test already covers the multi-column behaviour end to end, but it might be worth making this unit test use (Duration(Microsecond), Int64) input, or adding a small second unit test that does. That would exercise the GroupValuesColumn helper at the same boundary as the fix and make the regression a little more direct.
There was a problem hiding this comment.
appreciate your review kosiew
updated test to use Duration(Microsecond), Int64, it should be more direct now
|
Thank you for opening this pull request! Reviewer note: cargo-semver-checks reported the current version number is not SemVer-compatible with the changes in this pull request (compared against the base branch). Details |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #23783 +/- ##
==========================================
+ Coverage 80.71% 80.85% +0.14%
==========================================
Files 1089 1099 +10
Lines 368760 374350 +5590
Branches 368760 374350 +5590
==========================================
+ Hits 297647 302684 +5037
- Misses 53372 53605 +233
- Partials 17741 18061 +320 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…he GroupColumn unit test Per kosiew's review: a single-column Duration test doesn't exercise the all-or-nothing multi-column gate this PR is actually about. Switching to (Duration(Microsecond), Int64) does — rows 3 and 4 now repeat row 0 and the (null, null) pair across both columns, so dedup is proven on the composite key rather than the Duration value alone. Also renumber the bench to Experiment 9 (float16 apache#23785 takes 8) and trim the slt/test comments to match the sibling PRs.
The 30-days case duplicated the slt, which already proves 1 month and 30 days don't fold. Dropping it leaves the assertions unique to the unit level: null keys dedup, the Int32 key splits equal intervals, and emit gives back Interval rather than the raw native. Also renumber the bench to Experiment 10 (float16 apache#23785 takes 8, duration apache#23783 takes 9), trim comments to match the sibling PRs, and normalize the blank lines after the new slt block to two, matching upstream.
Duration apache#23783 landed on main and touched the same regions as this PR. Kept both sides: - mod.rs: unioned the arrow imports, kept both unit tests, Float16 added to the supported arms - benches: Float16 stays Experiment 8, Duration keeps 9 - group_by.slt: both coverage blocks
Duration apache#23783 landed on main and touched the same regions as this PR. Kept both sides: - mod.rs: unioned the arrow imports, kept both unit tests, Interval added to the supported arms and the dispatcher - benches: Duration keeps Experiment 9, Interval stays 10 - group_by.slt: both coverage blocks
Which issue does this PR close?
Rationale for this change
multi_group_by::group_column_supported_typegates which GROUP BY columns mayuse the column-wise
GroupValuesColumnfast path, and the gate isall-or-nothing: a single unsupported column forces the entire grouping onto
the byte-encoded
GroupValuesRowsfallback, even when every other key columnwould have qualified. A
Durationkey triggers exactly that today, so anotherwise-qualifying multi-column
GROUP BYpays the row-encoding tax because ofone column.
Durationshares thei64native representation already used byTimestamp,so supporting it is a pure slot-in of the existing
PrimitiveGroupValueBuilder—no new builder type and no new comparison/hash logic.
What changes are included in this PR?
Duration(_)ingroup_column_supported_type(all fourTimeUnits arevalid Arrow types, unlike the restricted
Time32/Time64set).Duration*Typeunits inmake_group_column.group_column_supported_type↔make_group_columnconsistency fuzzwith all four Duration units.
(Duration, Int32)group-count benchmark tobenches/multi_group_by.rs.Are these changes tested?
Yes.
test_group_values_column_duration: a(Duration(Microsecond), Int64)key stays on theGroupValuesColumnpath,dedups on the composite key (including the
(null, null)pair), andround-trips with the
Durationoutput type preserved (not the barei64).Durationunit routes through thedispatcher.
DurationGROUP BYcoverage ingroup_by.slt.Are there any user-facing changes?
No API changes.
GROUP BYqueries with aDurationkey now use the column-wisefast path instead of the row-encoded fallback; results are unchanged.