31
31
import org .hibernate .search .integrationtest .backend .tck .testsupport .operations .AggregationDescriptor ;
32
32
import org .hibernate .search .integrationtest .backend .tck .testsupport .operations .RangeAggregationDescriptor ;
33
33
import org .hibernate .search .integrationtest .backend .tck .testsupport .types .FieldTypeDescriptor ;
34
+ import org .hibernate .search .integrationtest .backend .tck .testsupport .types .IntegerFieldTypeDescriptor ;
34
35
import org .hibernate .search .integrationtest .backend .tck .testsupport .types .StandardFieldTypeDescriptor ;
36
+ import org .hibernate .search .integrationtest .backend .tck .testsupport .util .SimpleFieldModel ;
35
37
import org .hibernate .search .integrationtest .backend .tck .testsupport .util .SimpleFieldModelsByType ;
36
38
import org .hibernate .search .integrationtest .backend .tck .testsupport .util .TckConfiguration ;
37
39
import org .hibernate .search .integrationtest .backend .tck .testsupport .util .ValueWrapper ;
@@ -558,14 +560,333 @@ void rangeOverlap_parmeters(FieldTypeDescriptor<F, ?> fieldType, DataSet<F> data
558
560
);
559
561
}
560
562
563
+ @ ParameterizedTest (name = "{0}" )
564
+ @ MethodSource ("params" )
565
+ void rangesBucket_countDocuments (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
566
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
567
+
568
+ AggregationKey <Map <Range <F >, Long >> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
569
+
570
+ assertThatQuery (
571
+ matchAllQuery ()
572
+ .aggregation ( aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
573
+ .ranges ( Arrays .asList (
574
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
575
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
576
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
577
+ ) ).value ( f .countDocuments () )
578
+ )
579
+ .routing ( dataSet .name )
580
+ .toQuery ()
581
+ ).aggregation (
582
+ aggregationKey ,
583
+ containsExactly ( c -> {
584
+ c .accept ( Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ), 3L );
585
+ c .accept ( Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
586
+ 2L );
587
+ c .accept ( Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ), 2L );
588
+ } )
589
+ );
590
+ }
591
+
592
+ @ ParameterizedTest (name = "{0}" )
593
+ @ MethodSource ("params" )
594
+ void rangesBucket_min (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
595
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
596
+
597
+ AggregationKey <Map <Range <F >, F >> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
598
+
599
+ assertThatQuery (
600
+ matchAllQuery ()
601
+ .aggregation (
602
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
603
+ .ranges ( Arrays .asList (
604
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
605
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
606
+ dataSet .ascendingValues .get ( 5 ) ),
607
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
608
+ ) ).value ( f .min ().field ( fieldPath , fieldType .getJavaType () ) )
609
+ )
610
+ .routing ( dataSet .name )
611
+ .toQuery ()
612
+ ).aggregation (
613
+ aggregationKey ,
614
+ containsExactly ( c -> {
615
+ c .accept (
616
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
617
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 0 ) )
618
+ );
619
+ c .accept (
620
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
621
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 3 ) )
622
+ );
623
+ c .accept (
624
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
625
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 5 ) )
626
+ );
627
+ } )
628
+ );
629
+ }
630
+
631
+ @ ParameterizedTest (name = "{0}" )
632
+ @ MethodSource ("params" )
633
+ void rangesBucket_max (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
634
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
635
+
636
+ AggregationKey <Map <Range <F >, F >> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
637
+
638
+ assertThatQuery (
639
+ matchAllQuery ()
640
+ .aggregation (
641
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
642
+ .ranges ( Arrays .asList (
643
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
644
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
645
+ dataSet .ascendingValues .get ( 5 ) ),
646
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
647
+ ) ).value ( f .max ().field ( fieldPath , fieldType .getJavaType () ) )
648
+ )
649
+ .routing ( dataSet .name )
650
+ .toQuery ()
651
+ ).aggregation (
652
+ aggregationKey ,
653
+ containsExactly ( c -> {
654
+ c .accept (
655
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
656
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 2 ) )
657
+ );
658
+ c .accept (
659
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
660
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 4 ) )
661
+ );
662
+ c .accept (
663
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
664
+ dataSet .fieldType .normalize ( dataSet .ascendingValues .get ( 6 ) )
665
+ );
666
+ } )
667
+ );
668
+ }
669
+
670
+ @ ParameterizedTest (name = "{0}" )
671
+ @ MethodSource ("params" )
672
+ void rangesBucket_countValues (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
673
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
674
+
675
+ AggregationKey <Map <Range <F >, Long >> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
676
+
677
+ assertThatQuery (
678
+ matchAllQuery ()
679
+ .aggregation (
680
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
681
+ .ranges ( Arrays .asList (
682
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
683
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
684
+ dataSet .ascendingValues .get ( 5 ) ),
685
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
686
+ ) ).value ( f .countValues ().field ( index .binding ().bucketMultiValue .relativeFieldName ) )
687
+ )
688
+ .routing ( dataSet .name )
689
+ .toQuery ()
690
+ ).aggregation (
691
+ aggregationKey ,
692
+ containsExactly ( c -> {
693
+ c .accept (
694
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
695
+ 12L
696
+ );
697
+ c .accept (
698
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
699
+ 8L
700
+ );
701
+ c .accept (
702
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
703
+ 8L
704
+ );
705
+ } )
706
+ );
707
+ }
708
+
709
+ @ ParameterizedTest (name = "{0}" )
710
+ @ MethodSource ("params" )
711
+ void rangesBucket_countDistinctValues (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
712
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
713
+
714
+ AggregationKey <Map <Range <F >, Long >> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
715
+
716
+ assertThatQuery (
717
+ matchAllQuery ()
718
+ .aggregation (
719
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
720
+ .ranges ( Arrays .asList (
721
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
722
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
723
+ dataSet .ascendingValues .get ( 5 ) ),
724
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
725
+ ) )
726
+ .value ( f .countDistinctValues ()
727
+ .field ( index .binding ().bucketMultiValue .relativeFieldName ) )
728
+ )
729
+ .routing ( dataSet .name )
730
+ .toQuery ()
731
+ ).aggregation (
732
+ aggregationKey ,
733
+ containsExactly ( c -> {
734
+ c .accept (
735
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
736
+ 5L // 10 * 0 0 0 0 -- hence odd number in this range
737
+ );
738
+ c .accept (
739
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
740
+ 4L
741
+ );
742
+ c .accept (
743
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
744
+ 4L
745
+ );
746
+ } )
747
+ );
748
+ }
749
+
750
+ @ ParameterizedTest (name = "{0}" )
751
+ @ MethodSource ("params" )
752
+ void rangesBucket_terms_countImplicit (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
753
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
754
+
755
+ AggregationKey <Map <Range <F >, Map <Integer , Long >>> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
756
+
757
+ assertThatQuery (
758
+ matchAllQuery ()
759
+ .aggregation (
760
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
761
+ .ranges ( Arrays .asList (
762
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
763
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
764
+ dataSet .ascendingValues .get ( 5 ) ),
765
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
766
+ ) )
767
+ .value ( f .terms ().field ( index .binding ().bucketMultiValue .relativeFieldName ,
768
+ Integer .class ) )
769
+ )
770
+ .routing ( dataSet .name )
771
+ .toQuery ()
772
+ ).aggregation (
773
+ aggregationKey ,
774
+ containsExactly ( c -> {
775
+ c .accept (
776
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
777
+ Map .of ( 0 , 1L , 1 , 1L , 2 , 1L , 10 , 1L , 20 , 1L )
778
+ );
779
+ c .accept (
780
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
781
+ Map .of ( 3 , 1L , 4 , 1L , 30 , 1L , 40 , 1L )
782
+ );
783
+ c .accept (
784
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
785
+ Map .of ( 5 , 1L , 6 , 1L , 50 , 1L , 60 , 1L )
786
+ );
787
+ } )
788
+ );
789
+ }
790
+
791
+ @ ParameterizedTest (name = "{0}" )
792
+ @ MethodSource ("params" )
793
+ void rangesBucket_terms_sum (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
794
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
795
+
796
+ AggregationKey <Map <Range <F >, Map <Integer , Integer >>> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
797
+
798
+ assertThatQuery (
799
+ matchAllQuery ()
800
+ .aggregation (
801
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
802
+ .ranges ( Arrays .asList (
803
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
804
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
805
+ dataSet .ascendingValues .get ( 5 ) ),
806
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
807
+ ) )
808
+ .value ( f .terms ()
809
+ .field ( index .binding ().bucketMultiValue .relativeFieldName , Integer .class )
810
+ .value ( f .sum ().field ( index .binding ().bucketMultiValue .relativeFieldName ,
811
+ Integer .class ) ) )
812
+ )
813
+ .routing ( dataSet .name )
814
+ .toQuery ()
815
+ ).aggregation (
816
+ aggregationKey ,
817
+ containsExactly ( c -> {
818
+ c .accept (
819
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
820
+ Map .of ( 0 , 0 , 1 , 13 , 2 , 26 , 10 , 13 , 20 , 26 )
821
+ );
822
+ c .accept (
823
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ),
824
+ Map .of ( 3 , 39 , 4 , 52 , 30 , 39 , 40 , 52 )
825
+ );
826
+ c .accept (
827
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
828
+ Map .of ( 5 , 65 , 6 , 78 , 50 , 65 , 60 , 78 )
829
+ );
830
+ } )
831
+ );
832
+ }
833
+
834
+ @ ParameterizedTest (name = "{0}" )
835
+ @ MethodSource ("params" )
836
+ void rangesBucket_range_countExplicit (FieldTypeDescriptor <F , ?> fieldType , DataSet <F > dataSet ) {
837
+ String fieldPath = index .binding ().fieldModels .get ( fieldType ).relativeFieldName ;
838
+
839
+ AggregationKey <Map <Range <F >, Map <Range <F >, Long >>> aggregationKey = AggregationKey .of ( AGGREGATION_NAME );
840
+
841
+ assertThatQuery (
842
+ matchAllQuery ()
843
+ .aggregation (
844
+ aggregationKey , f -> f .range ().field ( fieldPath , fieldType .getJavaType () )
845
+ .ranges ( Arrays .asList (
846
+ Range .canonical ( null , dataSet .ascendingValues .get ( 5 ) ),
847
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
848
+ ) ).value ( f .range ().field ( fieldPath , fieldType .getJavaType () )
849
+ .ranges ( Arrays .asList (
850
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ),
851
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ),
852
+ dataSet .ascendingValues .get ( 5 ) ),
853
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null )
854
+ ) ) )
855
+ )
856
+ .routing ( dataSet .name )
857
+ .toQuery ()
858
+ ).aggregation (
859
+ aggregationKey ,
860
+ containsExactly ( c -> {
861
+ c .accept (
862
+ Range .canonical ( null , dataSet .ascendingValues .get ( 5 ) ),
863
+ Map .of (
864
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ), 3L ,
865
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ), 2L ,
866
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ), 0L
867
+ )
868
+ );
869
+ c .accept (
870
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ),
871
+ Map .of (
872
+ Range .canonical ( null , dataSet .ascendingValues .get ( 3 ) ), 0L ,
873
+ Range .canonical ( dataSet .ascendingValues .get ( 3 ), dataSet .ascendingValues .get ( 5 ) ), 0L ,
874
+ Range .canonical ( dataSet .ascendingValues .get ( 5 ), null ), 2L
875
+ )
876
+ );
877
+ } )
878
+ );
879
+ }
880
+
881
+
561
882
private void assumeNonCanonicalRangesSupported () {
562
883
assumeTrue (
563
884
TckConfiguration .get ().getBackendFeatures ().nonCanonicalRangeInAggregations (),
564
885
"Non-canonical ranges are not supported for aggregations with this backend"
565
886
);
566
887
}
567
888
568
- private SearchQueryOptionsStep <? , ?, DocumentReference , ?, ?, ?> matchAllQuery () {
889
+ private SearchQueryOptionsStep <Object , ?, DocumentReference , ?, ?, ?> matchAllQuery () {
569
890
return index .createScope ().query ().where ( f -> f .matchAll () );
570
891
}
571
892
@@ -593,10 +914,18 @@ private DataSet(FieldTypeDescriptor<F, ?> fieldType) {
593
914
private void init () {
594
915
BulkIndexer indexer = index .bulkIndexer ();
595
916
for ( int i = 0 ; i < documentFieldValues .size (); i ++ ) {
596
- F value = documentFieldValues .get ( i );
917
+ final F value = documentFieldValues .get ( i );
918
+ final int bucketValue = i ;
597
919
indexer .add ( name + "_document_" + i , name , document -> {
598
920
document .addValue ( index .binding ().fieldModels .get ( fieldType ).reference , value );
599
921
document .addValue ( index .binding ().fieldWithConverterModels .get ( fieldType ).reference , value );
922
+
923
+ document .addValue ( index .binding ().bucketValue .reference , bucketValue );
924
+
925
+ document .addValue ( index .binding ().bucketMultiValue .reference , bucketValue );
926
+ document .addValue ( index .binding ().bucketMultiValue .reference , bucketValue );
927
+ document .addValue ( index .binding ().bucketMultiValue .reference , bucketValue );
928
+ document .addValue ( index .binding ().bucketMultiValue .reference , bucketValue * 10 );
600
929
} );
601
930
}
602
931
indexer .add ( name + "_document_empty" , name , document -> {} );
@@ -608,6 +937,8 @@ private static class IndexBinding {
608
937
final SimpleFieldModelsByType fieldModels ;
609
938
final SimpleFieldModelsByType fieldWithConverterModels ;
610
939
final SimpleFieldModelsByType fieldWithAggregationDisabledModels ;
940
+ final SimpleFieldModel <Integer > bucketValue ;
941
+ final SimpleFieldModel <Integer > bucketMultiValue ;
611
942
612
943
IndexBinding (IndexSchemaElement root ) {
613
944
fieldModels = SimpleFieldModelsByType .mapAll ( supportedFieldTypes , root ,
@@ -622,6 +953,11 @@ private static class IndexBinding {
622
953
fieldWithAggregationDisabledModels = SimpleFieldModelsByType .mapAll ( supportedFieldTypes , root ,
623
954
"nonAggregable_" , c -> c .aggregable ( Aggregable .NO )
624
955
);
956
+ bucketValue = SimpleFieldModel .mapper ( IntegerFieldTypeDescriptor .INSTANCE , c -> c .aggregable ( Aggregable .YES ) )
957
+ .map ( root , "bucketValue" );
958
+ bucketMultiValue =
959
+ SimpleFieldModel .mapper ( IntegerFieldTypeDescriptor .INSTANCE , c -> c .aggregable ( Aggregable .YES ) )
960
+ .mapMultiValued ( root , "bucketMultiValue" );
625
961
}
626
962
}
627
963
0 commit comments