Skip to content

Commit 0e9cafe

Browse files
committed
test: cover unsorted contiguous groups in one partition
1 parent b0b5471 commit 0e9cafe

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

  • datafusion/physical-plan/src/aggregates

‎datafusion/physical-plan/src/aggregates/mod.rs‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4945,6 +4945,83 @@ mod tests {
49454945
Ok(())
49464946
}
49474947

4948+
#[tokio::test]
4949+
async fn unsorted_contiguous_groups_use_final_emission() -> Result<()> {
4950+
let schema = Arc::new(Schema::new(vec![
4951+
Field::new("key", DataType::Int32, false),
4952+
Field::new("time_bin", DataType::Int64, false),
4953+
Field::new("value", DataType::Int64, false),
4954+
]));
4955+
// Two sorted logical runs are emitted as batches in one DataFusion
4956+
// partition. Every distinct grouping tuple occupies one contiguous range,
4957+
// but tuple order resets at the batch boundary, so (key, time_bin) is not
4958+
// globally sorted.
4959+
let input_batches = vec![
4960+
RecordBatch::try_new(
4961+
Arc::clone(&schema),
4962+
vec![
4963+
Arc::new(Int32Array::from(vec![1, 1, 2, 2])),
4964+
Arc::new(Int64Array::from(vec![20, 20, 20, 20])),
4965+
Arc::new(Int64Array::from(vec![10, 20, 30, 40])),
4966+
],
4967+
)?,
4968+
RecordBatch::try_new(
4969+
Arc::clone(&schema),
4970+
vec![
4971+
Arc::new(Int32Array::from(vec![1, 1, 2, 2])),
4972+
Arc::new(Int64Array::from(vec![0, 0, 0, 0])),
4973+
Arc::new(Int64Array::from(vec![50, 60, 70, 80])),
4974+
],
4975+
)?,
4976+
];
4977+
let group_by = PhysicalGroupBy::new_single(vec![
4978+
(col("key", &schema)?, "key".to_string()),
4979+
(col("time_bin", &schema)?, "time_bin".to_string()),
4980+
]);
4981+
let aggr_expr = Arc::new(
4982+
AggregateExprBuilder::new(sum_udaf(), vec![col("value", &schema)?])
4983+
.schema(Arc::clone(&schema))
4984+
.alias("SUM(value)")
4985+
.build()?,
4986+
);
4987+
let input: Arc<dyn ExecutionPlan> =
4988+
TestMemoryExec::try_new_exec(&[input_batches], Arc::clone(&schema), None)?;
4989+
assert_eq!(input.output_partitioning().partition_count(), 1);
4990+
4991+
let aggregate = AggregateExec::try_new(
4992+
AggregateMode::Single,
4993+
group_by,
4994+
vec![aggr_expr],
4995+
vec![None],
4996+
input,
4997+
schema,
4998+
)?;
4999+
5000+
assert_eq!(aggregate.input_order_mode(), &InputOrderMode::Linear);
5001+
// This captures the behavior before #24438. When the source can declare
5002+
// `(key, time_bin)` group-contiguous, the corresponding case can use
5003+
// `EmissionType::Incremental`.
5004+
assert_eq!(aggregate.cache().emission_type, EmissionType::Final);
5005+
5006+
let task_ctx = new_migrated_hash_ctx(1024);
5007+
let stream = aggregate.execute_typed(0, &task_ctx)?;
5008+
assert!(matches!(stream, StreamType::SingleHash(_)));
5009+
let stream: SendableRecordBatchStream = stream.into();
5010+
let output = collect(stream).await?;
5011+
assert_snapshot!(batches_to_sort_string(&output), @r"
5012+
+-----+----------+------------+
5013+
| key | time_bin | SUM(value) |
5014+
+-----+----------+------------+
5015+
| 1 | 0 | 110 |
5016+
| 1 | 20 | 30 |
5017+
| 2 | 0 | 150 |
5018+
| 2 | 20 | 70 |
5019+
+-----+----------+------------+
5020+
");
5021+
5022+
Ok(())
5023+
}
5024+
49485025
/// Ensures for ordered input, `OrderedPartialAggregateStream` is used.
49495026
#[tokio::test]
49505027
async fn ordered_partial_aggregate_planning() -> Result<()> {

0 commit comments

Comments
 (0)