2727import io .milvus .common .utils .Float16Utils ;
2828import io .milvus .common .utils .GTsDict ;
2929import io .milvus .common .utils .JsonUtils ;
30+ import io .milvus .exception .ParamException ;
3031import io .milvus .grpc .*;
3132import io .milvus .orm .iterator .QueryIterator ;
3233import io .milvus .orm .iterator .SearchIterator ;
6364import java .util .*;
6465import java .util .concurrent .ExecutionException ;
6566import java .util .concurrent .TimeUnit ;
67+ import java .util .function .Function ;
68+
6669
6770@ Testcontainers (disabledWithoutDocker = true )
6871class MilvusClientDockerTest {
@@ -1345,18 +1348,6 @@ void testMultipleVectorFields() {
13451348 R <RpcStatus > createR = client .createCollection (createParam );
13461349 Assertions .assertEquals (R .Status .Success .getCode (), createR .getStatus ().intValue ());
13471350
1348- // insert data to multiple vector fields
1349- int rowCount = 10000 ;
1350- List <InsertParam .Field > fields = generateColumnsData (schema , rowCount , 0 );
1351-
1352- InsertParam insertParam = InsertParam .newBuilder ()
1353- .withCollectionName (randomCollectionName )
1354- .withFields (fields )
1355- .build ();
1356-
1357- R <MutationResult > insertR = client .insert (insertParam );
1358- Assertions .assertEquals (R .Status .Success .getCode (), insertR .getStatus ().intValue ());
1359-
13601351 // create indexes on multiple vector fields
13611352 CreateIndexParam indexParam = CreateIndexParam .newBuilder ()
13621353 .withCollectionName (randomCollectionName )
@@ -1397,53 +1388,86 @@ void testMultipleVectorFields() {
13971388 .build ());
13981389 Assertions .assertEquals (R .Status .Success .getCode (), loadR .getStatus ().intValue ());
13991390
1400- // search on multiple vector fields
1401- AnnSearchParam param1 = AnnSearchParam .newBuilder ()
1402- .withVectorFieldName (DataType .FloatVector .name ())
1403- .withFloatVectors (utils .generateFloatVectors (1 ))
1404- .withMetricType (MetricType .COSINE )
1405- .withParams ("{\" nprobe\" : 32}" )
1406- .withLimit (10L )
1407- .build ();
1408-
1409- AnnSearchParam param2 = AnnSearchParam .newBuilder ()
1410- .withVectorFieldName (DataType .BinaryVector .name ())
1411- .withBinaryVectors (utils .generateBinaryVectors (1 ))
1412- .withMetricType (MetricType .HAMMING )
1413- .withParams ("{}" )
1414- .withLimit (5L )
1415- .build ();
1416-
1417- AnnSearchParam param3 = AnnSearchParam .newBuilder ()
1418- .withVectorFieldName (DataType .SparseFloatVector .name ())
1419- .withSparseFloatVectors (utils .generateSparseVectors (1 ))
1420- .withMetricType (MetricType .IP )
1421- .withParams ("{\" drop_ratio_search\" :0.2}" )
1422- .withLimit (7L )
1423- .build ();
1391+ // prepare sub requests
1392+ int nq = 5 ;
1393+ long topk = 10L ;
1394+ Function <Integer , HybridSearchParam > genRequestFunc =
1395+ sparseCount -> {
1396+ AnnSearchParam param1 = AnnSearchParam .newBuilder ()
1397+ .withVectorFieldName (DataType .FloatVector .name ())
1398+ .withFloatVectors (utils .generateFloatVectors (nq ))
1399+ .withMetricType (MetricType .COSINE )
1400+ .withParams ("{\" nprobe\" : 32}" )
1401+ .withLimit (15L )
1402+ .build ();
1403+
1404+ AnnSearchParam param2 = AnnSearchParam .newBuilder ()
1405+ .withVectorFieldName (DataType .BinaryVector .name ())
1406+ .withBinaryVectors (utils .generateBinaryVectors (nq ))
1407+ .withMetricType (MetricType .HAMMING )
1408+ .withParams ("{}" )
1409+ .withLimit (5L )
1410+ .build ();
1411+
1412+ List <SortedMap <Long , Float >> sparseVEctors = sparseCount > 0 ?
1413+ utils .generateSparseVectors (sparseCount ) : new ArrayList <>();
1414+ AnnSearchParam param3 = AnnSearchParam .newBuilder ()
1415+ .withVectorFieldName (DataType .SparseFloatVector .name ())
1416+ .withSparseFloatVectors (sparseVEctors )
1417+ .withMetricType (MetricType .IP )
1418+ .withParams ("{\" drop_ratio_search\" :0.2}" )
1419+ .withLimit (7L )
1420+ .build ();
1421+
1422+ // search with an empty nq, return error
1423+ return HybridSearchParam .newBuilder ()
1424+ .withCollectionName (randomCollectionName )
1425+ .addOutField (DataType .SparseFloatVector .name ())
1426+ .addSearchRequest (param1 )
1427+ .addSearchRequest (param2 )
1428+ .addSearchRequest (param3 )
1429+ .withLimit (topk )
1430+ .withConsistencyLevel (ConsistencyLevelEnum .STRONG )
1431+ .withRanker (WeightedRanker .newBuilder ()
1432+ .withWeights (Lists .newArrayList (0.5f , 0.5f , 1.0f ))
1433+ .build ())
1434+ .withOutFields (Collections .singletonList ("*" ))
1435+ .build ();
1436+ };
1437+
1438+ // search with an empty nq, return error
1439+ Assertions .assertThrows (ParamException .class , ()->genRequestFunc .apply (0 ));
1440+
1441+ // unequal nq, return error
1442+ Assertions .assertThrows (ParamException .class , ()->genRequestFunc .apply (1 ));
1443+
1444+ // search on empty collection, no result returned
1445+ R <SearchResults > searchR = client .hybridSearch (genRequestFunc .apply (nq ));
1446+ Assertions .assertEquals (R .Status .Success .getCode (), searchR .getStatus ().intValue ());
1447+ SearchResultsWrapper results = new SearchResultsWrapper (searchR .getData ().getResults ());
1448+ for (int i = 0 ; i < results .getNumQueries (); ++i ) {
1449+ List <SearchResultsWrapper .IDScore > scores = results .getIDScore (0 );
1450+ Assertions .assertTrue (scores .isEmpty ());
1451+ }
14241452
1425- HybridSearchParam searchParam = HybridSearchParam .newBuilder ()
1453+ // insert data to multiple vector fields
1454+ int rowCount = 10000 ;
1455+ List <InsertParam .Field > fields = generateColumnsData (schema , rowCount , 0 );
1456+ InsertParam insertParam = InsertParam .newBuilder ()
14261457 .withCollectionName (randomCollectionName )
1427- .addOutField (DataType .SparseFloatVector .name ())
1428- .addSearchRequest (param1 )
1429- .addSearchRequest (param2 )
1430- .addSearchRequest (param3 )
1431- .withLimit (3L )
1432- .withConsistencyLevel (ConsistencyLevelEnum .STRONG )
1433- .withRanker (WeightedRanker .newBuilder ()
1434- .withWeights (Lists .newArrayList (0.5f , 0.5f , 1.0f ))
1435- .build ())
1436- .withOutFields (Collections .singletonList ("*" ))
1458+ .withFields (fields )
14371459 .build ();
1460+ R <MutationResult > insertR = client .insert (insertParam );
1461+ Assertions .assertEquals (R .Status .Success .getCode (), insertR .getStatus ().intValue ());
14381462
1439- R <SearchResults > searchR = client .hybridSearch (searchParam );
1463+ // search on multiple vector fields
1464+ searchR = client .hybridSearch (genRequestFunc .apply (nq ));
14401465 Assertions .assertEquals (R .Status .Success .getCode (), searchR .getStatus ().intValue ());
14411466
1442- // print search result
1443- SearchResultsWrapper results = new SearchResultsWrapper (searchR .getData ().getResults ());
1467+ // check search result
1468+ results = new SearchResultsWrapper (searchR .getData ().getResults ());
14441469 List <SearchResultsWrapper .IDScore > scores = results .getIDScore (0 );
14451470 for (SearchResultsWrapper .IDScore score : scores ) {
1446- System .out .println (score );
14471471 Object id = score .get ("id" );
14481472 Assertions .assertInstanceOf (Long .class , id );
14491473 Object fv = score .get (DataType .FloatVector .name ());
@@ -1457,6 +1481,10 @@ void testMultipleVectorFields() {
14571481 Object sv = score .get (DataType .SparseFloatVector .name ());
14581482 Assertions .assertInstanceOf (SortedMap .class , sv );
14591483 }
1484+ for (int i = 0 ; i < results .getNumQueries (); ++i ) {
1485+ scores = results .getIDScore (i );
1486+ Assertions .assertEquals (topk , scores .size ());
1487+ }
14601488
14611489 // drop collection
14621490 DropCollectionParam dropParam = DropCollectionParam .newBuilder ()
0 commit comments