1818use std:: marker:: PhantomData ;
1919use std:: sync:: Arc ;
2020
21- use arrow:: array:: { ArrayRef , AsArray , new_null_array} ;
21+ use arrow:: array:: { ArrayRef , AsArray , UInt64Array , new_null_array} ;
2222use arrow:: datatypes:: SchemaRef ;
2323use arrow:: record_batch:: RecordBatch ;
24+ use datafusion_common:: hash_utils:: create_hashes;
2425use datafusion_common:: { Result , internal_err} ;
2526use datafusion_execution:: memory_pool:: proxy:: VecAllocExt ;
2627use datafusion_expr:: { EmitTo , GroupsAccumulator } ;
@@ -31,7 +32,8 @@ use crate::aggregates::group_values::{GroupByMetrics, GroupValues, new_group_val
3132use crate :: aggregates:: grouped_hash_stream:: create_group_accumulator;
3233use crate :: aggregates:: order:: GroupOrdering ;
3334use crate :: aggregates:: {
34- AggregateExec , PhysicalGroupBy , aggregate_expressions, evaluate_group_by,
35+ AGGREGATION_HASH_SEED , AggregateExec , PhysicalGroupBy , aggregate_expressions,
36+ evaluate_group_by, schema_with_group_hash,
3537} ;
3638
3739/// Marker for raw rows -> partial state aggregation.
@@ -136,6 +138,8 @@ impl<AggrMode> AggregateHashTable<AggrMode> {
136138 group_by : Arc :: clone ( & agg. group_by ) ,
137139 group_values,
138140 batch_group_indices : Default :: default ( ) ,
141+ group_hashes : Default :: default ( ) ,
142+ batch_hashes : Default :: default ( ) ,
139143 accumulators,
140144 } ) ,
141145 _mode : PhantomData ,
@@ -183,6 +187,8 @@ impl<AggrMode> AggregateHashTable<AggrMode> {
183187
184188 acc + state. group_values . size ( )
185189 + state. batch_group_indices . allocated_size ( )
190+ + state. group_hashes . allocated_size ( )
191+ + state. batch_hashes . allocated_size ( )
186192 }
187193 AggregateHashTableState :: OutputtingMaterialized ( output) => {
188194 output. memory_size ( )
@@ -212,6 +218,7 @@ impl<AggrMode> AggregateHashTable<AggrMode> {
212218 } ;
213219
214220 state. batch_group_indices = Vec :: new ( ) ;
221+ state. batch_hashes = Vec :: new ( ) ;
215222 self . state = AggregateHashTableState :: Outputting ( state) ;
216223 }
217224}
@@ -287,6 +294,12 @@ pub(super) struct AggregateHashTableBuffer {
287294 /// accumulator to update that group's aggregate state.
288295 pub ( super ) batch_group_indices : Vec < usize > ,
289296
297+ /// Hash value for each stored group, indexed by group index.
298+ pub ( super ) group_hashes : Vec < u64 > ,
299+
300+ /// Scratch hash vector for the current input batch.
301+ pub ( super ) batch_hashes : Vec < u64 > ,
302+
290303 /// One item per aggregate expression.
291304 ///
292305 /// Example: `COUNT(x), SUM(y)` creates two items. Each item owns the input
@@ -343,6 +356,64 @@ impl MaterializedAggregateOutput {
343356 }
344357}
345358
359+ pub ( super ) fn try_new_internal_batch (
360+ output_schema : SchemaRef ,
361+ mut columns : Vec < ArrayRef > ,
362+ has_group_hash : bool ,
363+ ) -> Result < RecordBatch > {
364+ if has_group_hash {
365+ Ok ( RecordBatch :: try_new (
366+ schema_with_group_hash ( & output_schema) ,
367+ columns,
368+ ) ?)
369+ } else {
370+ Ok ( RecordBatch :: try_new (
371+ output_schema,
372+ std:: mem:: take ( & mut columns) ,
373+ ) ?)
374+ }
375+ }
376+
377+ impl AggregateHashTableBuffer {
378+ pub ( super ) fn create_batch_hashes (
379+ & mut self ,
380+ group_values : & [ ArrayRef ] ,
381+ ) -> Result < & [ u64 ] > {
382+ self . batch_hashes . clear ( ) ;
383+ let num_rows = group_values. first ( ) . map ( |array| array. len ( ) ) . unwrap_or ( 0 ) ;
384+ self . batch_hashes . resize ( num_rows, 0 ) ;
385+ create_hashes ( group_values, & AGGREGATION_HASH_SEED , & mut self . batch_hashes ) ?;
386+ Ok ( & self . batch_hashes )
387+ }
388+
389+ pub ( super ) fn reuse_batch_hashes ( & mut self , input_hashes : & UInt64Array ) -> & [ u64 ] {
390+ self . batch_hashes . clear ( ) ;
391+ self . batch_hashes . extend_from_slice ( input_hashes. values ( ) ) ;
392+ & self . batch_hashes
393+ }
394+
395+ pub ( super ) fn record_new_group_hashes (
396+ & mut self ,
397+ starting_num_groups : usize ,
398+ total_num_groups : usize ,
399+ ) {
400+ self . group_hashes . resize ( total_num_groups, 0 ) ;
401+ for ( row, group_index) in self . batch_group_indices . iter ( ) . enumerate ( ) {
402+ if * group_index >= starting_num_groups {
403+ self . group_hashes [ * group_index] = self . batch_hashes [ row] ;
404+ }
405+ }
406+ }
407+
408+ pub ( super ) fn emit_hashes ( & mut self , emit_to : EmitTo ) -> ArrayRef {
409+ let hashes = match emit_to {
410+ EmitTo :: All => std:: mem:: take ( & mut self . group_hashes ) ,
411+ EmitTo :: First ( n) => self . group_hashes . drain ( ..n) . collect ( ) ,
412+ } ;
413+ Arc :: new ( UInt64Array :: from ( hashes) )
414+ }
415+ }
416+
346417impl HashAggregateAccumulator {
347418 pub ( super ) fn new (
348419 aggregate_expr : Arc < AggregateFunctionExpr > ,
0 commit comments