@@ -1386,7 +1386,6 @@ impl GroupedHashAggregateStream {
13861386mod tests {
13871387 use super :: * ;
13881388 use crate :: InputOrderMode ;
1389- use crate :: execution_plan:: ExecutionPlan ;
13901389 use crate :: test:: TestMemoryExec ;
13911390 use arrow:: array:: { Int32Array , Int64Array } ;
13921391 use arrow:: datatypes:: { DataType , Field , Schema } ;
@@ -1501,152 +1500,6 @@ mod tests {
15011500 Ok ( ( ) )
15021501 }
15031502
1504- #[ tokio:: test]
1505- async fn test_skip_aggregation_probe_not_locked_until_skip ( ) -> Result < ( ) > {
1506- // Test that the probe is not locked until we actually decide to skip.
1507- // This allows us to continue evaluating the skip condition across multiple batches.
1508- //
1509- // Scenario:
1510- // - Batch 1: Hits rows threshold but NOT ratio threshold (low cardinality) -> don't skip
1511- // - Batch 2: Now hits ratio threshold (high cardinality) -> skip
1512- //
1513- // Without the fix, the probe would be locked after batch 1, preventing the skip
1514- // decision from being made on batch 2.
1515-
1516- let schema = Arc :: new ( Schema :: new ( vec ! [
1517- Field :: new( "group_col" , DataType :: Int32 , false ) ,
1518- Field :: new( "value_col" , DataType :: Int32 , false ) ,
1519- ] ) ) ;
1520-
1521- // Configure thresholds:
1522- // - probe_rows_threshold: 100 rows
1523- // - probe_ratio_threshold: 0.8 (80%)
1524- let probe_rows_threshold = 100 ;
1525- let probe_ratio_threshold = 0.8 ;
1526-
1527- // Batch 1: 100 rows with only 10 unique groups
1528- // Ratio: 10/100 = 0.1 (10%) < 0.8 -> should NOT skip
1529- // This will hit the rows threshold but not the ratio threshold
1530- let batch1_rows = 100 ;
1531- let batch1_groups = 10 ;
1532- let mut group_ids_batch1 = Vec :: new ( ) ;
1533- for i in 0 ..batch1_rows {
1534- group_ids_batch1. push ( ( i % batch1_groups) as i32 ) ;
1535- }
1536- let values_batch1: Vec < i32 > = vec ! [ 1 ; batch1_rows] ;
1537-
1538- let batch1 = RecordBatch :: try_new (
1539- Arc :: clone ( & schema) ,
1540- vec ! [
1541- Arc :: new( Int32Array :: from( group_ids_batch1) ) ,
1542- Arc :: new( Int32Array :: from( values_batch1) ) ,
1543- ] ,
1544- ) ?;
1545-
1546- // Batch 2: 360 rows with 360 unique NEW groups (starting from group 10)
1547- // After batch 2, total: 460 rows, 370 groups
1548- // Ratio: 370/460 ≈ 0.804 (80.4%) > 0.8 -> SHOULD decide to skip
1549- let batch2_rows = 360 ;
1550- let batch2_groups = 360 ;
1551- let group_ids_batch2: Vec < i32 > = ( batch1_groups..( batch1_groups + batch2_groups) )
1552- . map ( |x| x as i32 )
1553- . collect ( ) ;
1554- let values_batch2: Vec < i32 > = vec ! [ 1 ; batch2_rows] ;
1555-
1556- let batch2 = RecordBatch :: try_new (
1557- Arc :: clone ( & schema) ,
1558- vec ! [
1559- Arc :: new( Int32Array :: from( group_ids_batch2) ) ,
1560- Arc :: new( Int32Array :: from( values_batch2) ) ,
1561- ] ,
1562- ) ?;
1563-
1564- // Batch 3: This batch should be skipped since we decided to skip after batch 2
1565- // 100 rows with 100 unique groups (continuing from where batch 2 left off)
1566- let batch3_rows = 100 ;
1567- let batch3_groups = 100 ;
1568- let batch3_start_group = batch1_groups + batch2_groups;
1569- let group_ids_batch3: Vec < i32 > = ( batch3_start_group
1570- ..( batch3_start_group + batch3_groups) )
1571- . map ( |x| x as i32 )
1572- . collect ( ) ;
1573- let values_batch3: Vec < i32 > = vec ! [ 1 ; batch3_rows] ;
1574-
1575- let batch3 = RecordBatch :: try_new (
1576- Arc :: clone ( & schema) ,
1577- vec ! [
1578- Arc :: new( Int32Array :: from( group_ids_batch3) ) ,
1579- Arc :: new( Int32Array :: from( values_batch3) ) ,
1580- ] ,
1581- ) ?;
1582-
1583- let input_partitions = vec ! [ vec![ batch1, batch2, batch3] ] ;
1584-
1585- let runtime = RuntimeEnvBuilder :: default ( ) . build_arc ( ) ?;
1586- let mut task_ctx = TaskContext :: default ( ) . with_runtime ( runtime) ;
1587-
1588- // Configure skip aggregation settings
1589- let mut session_config = task_ctx. session_config ( ) . clone ( ) ;
1590- session_config = session_config. set (
1591- "datafusion.execution.skip_partial_aggregation_probe_rows_threshold" ,
1592- & datafusion_common:: ScalarValue :: UInt64 ( Some ( probe_rows_threshold) ) ,
1593- ) ;
1594- session_config = session_config. set (
1595- "datafusion.execution.skip_partial_aggregation_probe_ratio_threshold" ,
1596- & datafusion_common:: ScalarValue :: Float64 ( Some ( probe_ratio_threshold) ) ,
1597- ) ;
1598- task_ctx = task_ctx. with_session_config ( session_config) ;
1599- let task_ctx = Arc :: new ( task_ctx) ;
1600-
1601- // Create aggregate: COUNT(*) GROUP BY group_col
1602- let group_expr = vec ! [ ( col( "group_col" , & schema) ?, "group_col" . to_string( ) ) ] ;
1603- let aggr_expr = vec ! [ Arc :: new(
1604- AggregateExprBuilder :: new( count_udaf( ) , vec![ col( "value_col" , & schema) ?] )
1605- . schema( Arc :: clone( & schema) )
1606- . alias( "count_value" )
1607- . build( ) ?,
1608- ) ] ;
1609-
1610- let exec = TestMemoryExec :: try_new ( & input_partitions, Arc :: clone ( & schema) , None ) ?;
1611- let exec = Arc :: new ( TestMemoryExec :: update_cache ( & Arc :: new ( exec) ) ) ;
1612-
1613- // Use Partial mode
1614- let aggregate_exec = AggregateExec :: try_new (
1615- AggregateMode :: Partial ,
1616- PhysicalGroupBy :: new_single ( group_expr) ,
1617- aggr_expr,
1618- vec ! [ None ] ,
1619- exec,
1620- Arc :: clone ( & schema) ,
1621- ) ?;
1622-
1623- // Execute and collect results
1624- let mut stream =
1625- GroupedHashAggregateStream :: new ( & aggregate_exec, & Arc :: clone ( & task_ctx) , 0 ) ?;
1626- let mut results = Vec :: new ( ) ;
1627-
1628- while let Some ( result) = stream. next ( ) . await {
1629- let batch = result?;
1630- results. push ( batch) ;
1631- }
1632-
1633- // Check that skip aggregation actually happened
1634- // The key metric is skipped_aggregation_rows
1635- let metrics = aggregate_exec. metrics ( ) . unwrap ( ) ;
1636- let skipped_rows = metrics
1637- . sum_by_name ( "skipped_aggregation_rows" )
1638- . map ( |m| m. as_usize ( ) )
1639- . unwrap_or ( 0 ) ;
1640-
1641- // We expect batch 3's rows to be skipped (100 rows)
1642- assert_eq ! (
1643- skipped_rows, batch3_rows,
1644- "Expected batch 3's rows ({batch3_rows}) to be skipped" ,
1645- ) ;
1646-
1647- Ok ( ( ) )
1648- }
1649-
16501503 #[ tokio:: test]
16511504 async fn test_emit_early_with_partially_sorted ( ) -> Result < ( ) > {
16521505 // Reproducer for #20445: EmitEarly with PartiallySorted panics in
@@ -1730,25 +1583,4 @@ mod tests {
17301583
17311584 Ok ( ( ) )
17321585 }
1733-
1734- #[ test]
1735- fn test_skip_aggregation_probe_equality_does_not_skip ( ) {
1736- // When num_groups / input_rows == probe_ratio_threshold, the `>` boundary
1737- // means we must NOT skip — equality is not sufficient to trigger skip.
1738- let threshold_ratio = 0.5_f64 ;
1739- let threshold_rows = 10_usize ;
1740- let mut probe = SkipAggregationProbe :: new (
1741- threshold_rows,
1742- threshold_ratio,
1743- metrics:: Count :: new ( ) ,
1744- ) ;
1745-
1746- // 10 rows, 5 groups → ratio = 5/10 = 0.5 exactly equals threshold
1747- probe. update_state ( 10 , 5 ) ;
1748-
1749- assert ! (
1750- !probe. should_skip( ) ,
1751- "ratio == threshold should not trigger skip (boundary is exclusive)"
1752- ) ;
1753- }
17541586}
0 commit comments