@@ -413,52 +413,57 @@ pub(crate) fn build_segment_term_collector(
413413 // `num_terms`. `saturating_add` guards the HashMap fallback, where `max_column_val` is a raw
414414 // numeric column value that can reach `u64::MAX`; term ordinals never come close.
415415 let num_terms = max_column_val. saturating_add ( 1 ) ;
416- if is_top_level && max_column_val < MAX_NUM_TERMS_FOR_VEC && !has_sub_aggregations {
417- let term_buckets = VecTermBuckets :: < ( ) > :: new ( num_terms, & mut bucket_id_provider) ;
418- Ok ( boxed_high_card_collector (
419- term_buckets,
420- None ,
421- bucket_id_provider,
422- max_column_val,
423- terms_req_data,
424- ) )
425- } else if is_top_level && max_column_val < MAX_NUM_TERMS_FOR_VEC {
426- let term_buckets = VecTermBuckets :: < BucketId > :: new ( num_terms, & mut bucket_id_provider) ;
427- let sub_agg = sub_agg_collector. map ( LowCardBufferedSubAggs :: new) ;
428- let collector: SegmentTermCollector < _ , LowCardSubAggBuffer > = SegmentTermCollector {
429- parent_buckets : vec ! [ term_buckets] ,
430- sub_agg,
431- bucket_id_provider,
432- max_term_id : max_column_val,
433- terms_req_data,
434- } ;
435- Ok ( Box :: new ( collector) )
436- } else if max_column_val < 8_000_000 && is_top_level {
437- // Build sub-aggregation blueprint (flat pairs)
438- let sub_agg = sub_agg_collector. map ( BufferedSubAggs :: new) ;
416+ if is_top_level && max_column_val < MAX_NUM_TERMS_FOR_VEC {
417+ // Low cardinality: dense `Vec` storage. With sub aggregations it pairs with the `LowCard`
418+ // buffer, which groups docs in a per-bucket `Vec` — a better fit for the few buckets here
419+ // than the partitioned `HighCard` buffer the branches below use (docs arrive in doc order,
420+ // so `HighCard` would only merge consecutive same-bucket docs).
439421 if has_sub_aggregations {
440- let term_buckets = PagedTermMap :: < BucketId > :: new ( num_terms, & mut bucket_id_provider) ;
441- Ok ( boxed_high_card_collector (
442- term_buckets,
443- sub_agg,
422+ let term_buckets = VecTermBuckets :: < BucketId > :: new ( num_terms, & mut bucket_id_provider) ;
423+ let collector : SegmentTermCollector < _ , LowCardSubAggBuffer > = SegmentTermCollector {
424+ parent_buckets : vec ! [ term_buckets] ,
425+ sub_agg : sub_agg_collector . map ( LowCardBufferedSubAggs :: new ) ,
444426 bucket_id_provider,
445- max_column_val,
427+ max_term_id : max_column_val,
446428 terms_req_data,
447- ) )
429+ } ;
430+ Ok ( Box :: new ( collector) )
448431 } else {
449- let term_buckets = PagedTermMap :: < ( ) > :: new ( num_terms, & mut bucket_id_provider) ;
432+ let term_buckets = VecTermBuckets :: < ( ) > :: new ( num_terms, & mut bucket_id_provider) ;
450433 Ok ( boxed_high_card_collector (
451434 term_buckets,
452- sub_agg ,
435+ None ,
453436 bucket_id_provider,
454437 max_column_val,
455438 terms_req_data,
456439 ) )
457440 }
458441 } else {
459- // Build sub-aggregation blueprint (flat pairs)
442+ // Higher cardinality: every remaining storage uses the partitioned `HighCard` sub-agg
443+ // buffer, so it is built once here.
460444 let sub_agg = sub_agg_collector. map ( BufferedSubAggs :: new) ;
461- if has_sub_aggregations {
445+ if max_column_val < 8_000_000 && is_top_level {
446+ if has_sub_aggregations {
447+ let term_buckets =
448+ PagedTermMap :: < BucketId > :: new ( num_terms, & mut bucket_id_provider) ;
449+ Ok ( boxed_high_card_collector (
450+ term_buckets,
451+ sub_agg,
452+ bucket_id_provider,
453+ max_column_val,
454+ terms_req_data,
455+ ) )
456+ } else {
457+ let term_buckets = PagedTermMap :: < ( ) > :: new ( num_terms, & mut bucket_id_provider) ;
458+ Ok ( boxed_high_card_collector (
459+ term_buckets,
460+ sub_agg,
461+ bucket_id_provider,
462+ max_column_val,
463+ terms_req_data,
464+ ) )
465+ }
466+ } else if has_sub_aggregations {
462467 let term_buckets = HashMapTermBuckets :: < BucketId > :: default ( ) ;
463468 Ok ( boxed_high_card_collector (
464469 term_buckets,
0 commit comments