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 ;
6668
6769@ Testcontainers (disabledWithoutDocker = true )
6870class MilvusClientDockerTest {
@@ -1345,18 +1347,6 @@ void testMultipleVectorFields() {
13451347 R <RpcStatus > createR = client .createCollection (createParam );
13461348 Assertions .assertEquals (R .Status .Success .getCode (), createR .getStatus ().intValue ());
13471349
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-
13601350 // create indexes on multiple vector fields
13611351 CreateIndexParam indexParam = CreateIndexParam .newBuilder ()
13621352 .withCollectionName (randomCollectionName )
@@ -1397,53 +1387,86 @@ void testMultipleVectorFields() {
13971387 .build ());
13981388 Assertions .assertEquals (R .Status .Success .getCode (), loadR .getStatus ().intValue ());
13991389
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 ();
1390+ // prepare sub requests
1391+ int nq = 5 ;
1392+ long topk = 10L ;
1393+ Function <Integer , HybridSearchParam > genRequestFunc =
1394+ sparseCount -> {
1395+ AnnSearchParam param1 = AnnSearchParam .newBuilder ()
1396+ .withVectorFieldName (DataType .FloatVector .name ())
1397+ .withFloatVectors (utils .generateFloatVectors (nq ))
1398+ .withMetricType (MetricType .COSINE )
1399+ .withParams ("{\" nprobe\" : 32}" )
1400+ .withLimit (15L )
1401+ .build ();
1402+
1403+ AnnSearchParam param2 = AnnSearchParam .newBuilder ()
1404+ .withVectorFieldName (DataType .BinaryVector .name ())
1405+ .withBinaryVectors (utils .generateBinaryVectors (nq ))
1406+ .withMetricType (MetricType .HAMMING )
1407+ .withParams ("{}" )
1408+ .withLimit (5L )
1409+ .build ();
1410+
1411+ List <SortedMap <Long , Float >> sparseVEctors = sparseCount > 0 ?
1412+ utils .generateSparseVectors (sparseCount ) : new ArrayList <>();
1413+ AnnSearchParam param3 = AnnSearchParam .newBuilder ()
1414+ .withVectorFieldName (DataType .SparseFloatVector .name ())
1415+ .withSparseFloatVectors (sparseVEctors )
1416+ .withMetricType (MetricType .IP )
1417+ .withParams ("{\" drop_ratio_search\" :0.2}" )
1418+ .withLimit (7L )
1419+ .build ();
1420+
1421+ // search with an empty nq, return error
1422+ return HybridSearchParam .newBuilder ()
1423+ .withCollectionName (randomCollectionName )
1424+ .addOutField (DataType .SparseFloatVector .name ())
1425+ .addSearchRequest (param1 )
1426+ .addSearchRequest (param2 )
1427+ .addSearchRequest (param3 )
1428+ .withLimit (topk )
1429+ .withConsistencyLevel (ConsistencyLevelEnum .STRONG )
1430+ .withRanker (WeightedRanker .newBuilder ()
1431+ .withWeights (Lists .newArrayList (0.5f , 0.5f , 1.0f ))
1432+ .build ())
1433+ .withOutFields (Collections .singletonList ("*" ))
1434+ .build ();
1435+ };
1436+
1437+ // search with an empty nq, return error
1438+ Assertions .assertThrows (ParamException .class , ()->genRequestFunc .apply (0 ));
1439+
1440+ // unequal nq, return error
1441+ Assertions .assertThrows (ParamException .class , ()->genRequestFunc .apply (1 ));
1442+
1443+ // search on empty collection, no result returned
1444+ R <SearchResults > searchR = client .hybridSearch (genRequestFunc .apply (nq ));
1445+ Assertions .assertEquals (R .Status .Success .getCode (), searchR .getStatus ().intValue ());
1446+ SearchResultsWrapper results = new SearchResultsWrapper (searchR .getData ().getResults ());
1447+ for (int i = 0 ; i < results .getNumQueries (); ++i ) {
1448+ List <SearchResultsWrapper .IDScore > scores = results .getIDScore (0 );
1449+ Assertions .assertTrue (scores .isEmpty ());
1450+ }
14241451
1425- HybridSearchParam searchParam = HybridSearchParam .newBuilder ()
1452+ // insert data to multiple vector fields
1453+ int rowCount = 10000 ;
1454+ List <InsertParam .Field > fields = generateColumnsData (schema , rowCount , 0 );
1455+ InsertParam insertParam = InsertParam .newBuilder ()
14261456 .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 ("*" ))
1457+ .withFields (fields )
14371458 .build ();
1459+ R <MutationResult > insertR = client .insert (insertParam );
1460+ Assertions .assertEquals (R .Status .Success .getCode (), insertR .getStatus ().intValue ());
14381461
1439- R <SearchResults > searchR = client .hybridSearch (searchParam );
1462+ // search on multiple vector fields
1463+ searchR = client .hybridSearch (genRequestFunc .apply (nq ));
14401464 Assertions .assertEquals (R .Status .Success .getCode (), searchR .getStatus ().intValue ());
14411465
1442- // print search result
1443- SearchResultsWrapper results = new SearchResultsWrapper (searchR .getData ().getResults ());
1466+ // check search result
1467+ results = new SearchResultsWrapper (searchR .getData ().getResults ());
14441468 List <SearchResultsWrapper .IDScore > scores = results .getIDScore (0 );
14451469 for (SearchResultsWrapper .IDScore score : scores ) {
1446- System .out .println (score );
14471470 Object id = score .get ("id" );
14481471 Assertions .assertInstanceOf (Long .class , id );
14491472 Object fv = score .get (DataType .FloatVector .name ());
@@ -1457,6 +1480,10 @@ void testMultipleVectorFields() {
14571480 Object sv = score .get (DataType .SparseFloatVector .name ());
14581481 Assertions .assertInstanceOf (SortedMap .class , sv );
14591482 }
1483+ for (int i = 0 ; i < results .getNumQueries (); ++i ) {
1484+ scores = results .getIDScore (i );
1485+ Assertions .assertEquals (topk , scores .size ());
1486+ }
14601487
14611488 // drop collection
14621489 DropCollectionParam dropParam = DropCollectionParam .newBuilder ()
0 commit comments