13
13
// limitations under the License.
14
14
15
15
use std:: {
16
- collections:: { HashMap , HashSet } ,
16
+ collections:: { BTreeMap , HashMap , HashSet } ,
17
17
default:: Default ,
18
18
fmt:: Debug ,
19
19
} ;
@@ -220,13 +220,13 @@ pub struct QueryResponse {
220
220
/// A list of tags only returned when the results are for a single time
221
221
/// series. If results are aggregated, this value may be null or an empty
222
222
/// map
223
- pub ( crate ) tags : HashMap < String , String > ,
223
+ pub ( crate ) tags : BTreeMap < String , String > ,
224
224
/// If more than one timeseries were included in the result set, i.e. they
225
225
/// were aggregated, this will display a list of tag names that were found
226
226
/// in common across all time series.
227
227
#[ serde( rename = "aggregatedTags" ) ]
228
228
pub ( crate ) aggregated_tags : Vec < String > ,
229
- pub ( crate ) dps : HashMap < String , f64 > ,
229
+ pub ( crate ) dps : BTreeMap < String , f64 > ,
230
230
}
231
231
232
232
#[ derive( Default ) ]
@@ -237,10 +237,10 @@ struct QueryConverter {
237
237
// (column_name, index)
238
238
tags_idx : Vec < ( String , usize ) > ,
239
239
aggregated_tags : Vec < String > ,
240
- // (tags_key , (tagk, tagv))
241
- tags : HashMap < String , HashMap < String , String > > ,
242
- // (tags_key , (timestamp, value))
243
- values : HashMap < String , HashMap < String , f64 > > ,
240
+ // (time_series , (tagk, tagv))
241
+ tags : BTreeMap < String , BTreeMap < String , String > > ,
242
+ // (time_series , (timestamp, value))
243
+ values : BTreeMap < String , BTreeMap < String , f64 > > ,
244
244
245
245
resp : Vec < QueryResponse > ,
246
246
}
@@ -249,18 +249,18 @@ impl QueryConverter {
249
249
fn try_new (
250
250
schema : & RecordSchema ,
251
251
metric : String ,
252
- timestamp_col_name : & str ,
253
- field_col_name : & str ,
252
+ timestamp_col_name : String ,
253
+ field_col_name : String ,
254
254
tags : Vec < String > ,
255
255
aggregated_tags : Vec < String > ,
256
256
) -> Result < Self > {
257
257
let timestamp_idx = schema
258
- . index_of ( timestamp_col_name)
258
+ . index_of ( & timestamp_col_name)
259
259
. context ( InternalNoCause {
260
260
msg : "Timestamp column is missing in query response" ,
261
261
} ) ?;
262
262
263
- let value_idx = schema. index_of ( field_col_name) . context ( InternalNoCause {
263
+ let value_idx = schema. index_of ( & field_col_name) . context ( InternalNoCause {
264
264
msg : "Value column is missing in query response" ,
265
265
} ) ?;
266
266
@@ -316,7 +316,8 @@ impl QueryConverter {
316
316
fn add_batch ( & mut self , record_batch : RecordBatch ) -> Result < ( ) > {
317
317
let row_num = record_batch. num_rows ( ) ;
318
318
for row_idx in 0 ..row_num {
319
- let mut tags = HashMap :: with_capacity ( self . tags_idx . len ( ) ) ;
319
+ let mut tags = BTreeMap :: new ( ) ;
320
+ // tags_key is used to identify a time series
320
321
let mut tags_key = String :: new ( ) ;
321
322
for ( tag_key, idx) in & self . tags_idx {
322
323
let tag_value = record_batch
@@ -404,8 +405,8 @@ pub(crate) fn convert_output_to_response(
404
405
QueryConverter :: try_new (
405
406
record_schema,
406
407
metric,
407
- & timestamp_col_name,
408
- & field_col_name,
408
+ timestamp_col_name,
409
+ field_col_name,
409
410
tags,
410
411
aggregated_tags,
411
412
) ?
@@ -467,19 +468,30 @@ mod tests {
467
468
. unwrap ( ) ,
468
469
)
469
470
. unwrap ( )
471
+ . add_normal_column (
472
+ column_schema:: Builder :: new ( "tag2" . to_string ( ) , DatumKind :: String )
473
+ . is_tag ( true )
474
+ . build ( )
475
+ . unwrap ( ) ,
476
+ )
477
+ . unwrap ( )
470
478
. build ( )
471
479
. unwrap ( )
472
480
}
473
481
474
482
fn build_record_batch ( schema : & Schema ) -> RecordBatchVec {
475
- let tsid: ArrayRef = Arc :: new ( UInt64Array :: from ( vec ! [ 1 ] ) ) ;
476
- let timestamp: ArrayRef = Arc :: new ( TimestampMillisecondArray :: from ( vec ! [ 11111111 ] ) ) ;
477
- let values: ArrayRef = Arc :: new ( Float64Array :: from ( vec ! [ 100.0 ] ) ) ;
478
- let tag1: ArrayRef = Arc :: new ( StringArray :: from ( vec ! [ "a" ] ) ) ;
483
+ let tsid: ArrayRef = Arc :: new ( UInt64Array :: from ( vec ! [ 1 , 1 , 2 , 3 , 3 ] ) ) ;
484
+ let timestamp: ArrayRef = Arc :: new ( TimestampMillisecondArray :: from ( vec ! [
485
+ 11111111 , 11111112 , 11111113 , 11111111 , 11111112 ,
486
+ ] ) ) ;
487
+ let values: ArrayRef =
488
+ Arc :: new ( Float64Array :: from ( vec ! [ 100.0 , 101.0 , 200.0 , 300.0 , 301.0 ] ) ) ;
489
+ let tag1: ArrayRef = Arc :: new ( StringArray :: from ( vec ! [ "a" , "a" , "b" , "c" , "c" ] ) ) ;
490
+ let tag2: ArrayRef = Arc :: new ( StringArray :: from ( vec ! [ "x" , "x" , "y" , "z" , "z" ] ) ) ;
479
491
480
492
let batch = ArrowRecordBatch :: try_new (
481
493
schema. to_arrow_schema_ref ( ) ,
482
- vec ! [ tsid, timestamp, values, tag1] ,
494
+ vec ! [ tsid, timestamp, values, tag1, tag2 ] ,
483
495
)
484
496
. unwrap ( ) ;
485
497
@@ -489,7 +501,7 @@ mod tests {
489
501
#[ test]
490
502
fn test_convert_output_to_response ( ) {
491
503
let metric = "metric" . to_string ( ) ;
492
- let tags = vec ! [ "tag1" . to_string( ) ] ;
504
+ let tags = vec ! [ "tag1" . to_string( ) , "tag2" . to_string ( ) ] ;
493
505
let schema = build_schema ( ) ;
494
506
let record_batch = build_record_batch ( & schema) ;
495
507
let result = convert_output_to_response (
@@ -498,19 +510,56 @@ mod tests {
498
510
DEFAULT_FIELD . to_string ( ) ,
499
511
TIMESTAMP_COLUMN . to_string ( ) ,
500
512
tags,
501
- vec ! [ "tag1" . to_string ( ) ] ,
513
+ vec ! [ ] ,
502
514
)
503
515
. unwrap ( ) ;
504
516
505
517
assert_eq ! (
506
- vec![ QueryResponse {
507
- metric: metric. clone( ) ,
508
- tags: vec![ ( "tag1" . to_string( ) , "a" . to_string( ) ) , ]
518
+ vec![
519
+ QueryResponse {
520
+ metric: metric. clone( ) ,
521
+ tags: vec![
522
+ ( "tag1" . to_string( ) , "a" . to_string( ) ) ,
523
+ ( "tag2" . to_string( ) , "x" . to_string( ) ) ,
524
+ ]
525
+ . into_iter( )
526
+ . collect( ) ,
527
+ aggregated_tags: vec![ ] ,
528
+ dps: vec![
529
+ ( "11111111" . to_string( ) , 100.0 ) ,
530
+ ( "11111112" . to_string( ) , 101.0 ) ,
531
+ ]
532
+ . into_iter( )
533
+ . collect( ) ,
534
+ } ,
535
+ QueryResponse {
536
+ metric: metric. clone( ) ,
537
+ tags: vec![
538
+ ( "tag1" . to_string( ) , "b" . to_string( ) ) ,
539
+ ( "tag2" . to_string( ) , "y" . to_string( ) ) ,
540
+ ]
541
+ . into_iter( )
542
+ . collect( ) ,
543
+ aggregated_tags: vec![ ] ,
544
+ dps: vec![ ( "11111113" . to_string( ) , 200.0 ) , ] . into_iter( ) . collect( ) ,
545
+ } ,
546
+ QueryResponse {
547
+ metric: metric. clone( ) ,
548
+ tags: vec![
549
+ ( "tag1" . to_string( ) , "c" . to_string( ) ) ,
550
+ ( "tag2" . to_string( ) , "z" . to_string( ) ) ,
551
+ ]
552
+ . into_iter( )
553
+ . collect( ) ,
554
+ aggregated_tags: vec![ ] ,
555
+ dps: vec![
556
+ ( "11111111" . to_string( ) , 300.0 ) ,
557
+ ( "11111112" . to_string( ) , 301.0 ) ,
558
+ ]
509
559
. into_iter( )
510
560
. collect( ) ,
511
- aggregated_tags: vec![ "tag1" . to_string( ) ] ,
512
- dps: vec![ ( "11111111" . to_string( ) , 100.0 ) , ] . into_iter( ) . collect( ) ,
513
- } ] ,
561
+ } ,
562
+ ] ,
514
563
result
515
564
) ;
516
565
}
0 commit comments