Skip to content

Commit 2a6150c

Browse files
committed
HSEARCH-3661 Add more tests around aggregations to the backend TCK
1 parent 66b6444 commit 2a6150c

File tree

6 files changed

+442
-3
lines changed

6 files changed

+442
-3
lines changed

integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/aggregation/RangeAggregationSpecificsIT.java

Lines changed: 338 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
import org.hibernate.search.integrationtest.backend.tck.testsupport.operations.AggregationDescriptor;
3232
import org.hibernate.search.integrationtest.backend.tck.testsupport.operations.RangeAggregationDescriptor;
3333
import org.hibernate.search.integrationtest.backend.tck.testsupport.types.FieldTypeDescriptor;
34+
import org.hibernate.search.integrationtest.backend.tck.testsupport.types.IntegerFieldTypeDescriptor;
3435
import org.hibernate.search.integrationtest.backend.tck.testsupport.types.StandardFieldTypeDescriptor;
36+
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.SimpleFieldModel;
3537
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.SimpleFieldModelsByType;
3638
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.TckConfiguration;
3739
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.ValueWrapper;
@@ -558,14 +560,333 @@ void rangeOverlap_parmeters(FieldTypeDescriptor<F, ?> fieldType, DataSet<F> data
558560
);
559561
}
560562

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+
561882
private void assumeNonCanonicalRangesSupported() {
562883
assumeTrue(
563884
TckConfiguration.get().getBackendFeatures().nonCanonicalRangeInAggregations(),
564885
"Non-canonical ranges are not supported for aggregations with this backend"
565886
);
566887
}
567888

568-
private SearchQueryOptionsStep<?, ?, DocumentReference, ?, ?, ?> matchAllQuery() {
889+
private SearchQueryOptionsStep<Object, ?, DocumentReference, ?, ?, ?> matchAllQuery() {
569890
return index.createScope().query().where( f -> f.matchAll() );
570891
}
571892

@@ -593,10 +914,18 @@ private DataSet(FieldTypeDescriptor<F, ?> fieldType) {
593914
private void init() {
594915
BulkIndexer indexer = index.bulkIndexer();
595916
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;
597919
indexer.add( name + "_document_" + i, name, document -> {
598920
document.addValue( index.binding().fieldModels.get( fieldType ).reference, value );
599921
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 );
600929
} );
601930
}
602931
indexer.add( name + "_document_empty", name, document -> {} );
@@ -608,6 +937,8 @@ private static class IndexBinding {
608937
final SimpleFieldModelsByType fieldModels;
609938
final SimpleFieldModelsByType fieldWithConverterModels;
610939
final SimpleFieldModelsByType fieldWithAggregationDisabledModels;
940+
final SimpleFieldModel<Integer> bucketValue;
941+
final SimpleFieldModel<Integer> bucketMultiValue;
611942

612943
IndexBinding(IndexSchemaElement root) {
613944
fieldModels = SimpleFieldModelsByType.mapAll( supportedFieldTypes, root,
@@ -622,6 +953,11 @@ private static class IndexBinding {
622953
fieldWithAggregationDisabledModels = SimpleFieldModelsByType.mapAll( supportedFieldTypes, root,
623954
"nonAggregable_", c -> c.aggregable( Aggregable.NO )
624955
);
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" );
625961
}
626962
}
627963

0 commit comments

Comments
 (0)