github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/test/testcases/search_test.go (about) 1 //go:build L0 2 3 package testcases 4 5 import ( 6 "fmt" 7 "log" 8 "math/rand" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/milvus-io/milvus-sdk-go/v2/client" 16 "github.com/milvus-io/milvus-sdk-go/v2/entity" 17 "github.com/milvus-io/milvus-sdk-go/v2/test/common" 18 ) 19 20 func TestSearch(t *testing.T) { 21 ctx := createContext(t, time.Second*common.DefaultTimeout) 22 // connect 23 mc := createMilvusClient(ctx, t) 24 25 // create collection with data 26 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 27 28 // load collection 29 errLoad := mc.LoadCollection(ctx, collName, false) 30 common.CheckErr(t, errLoad, true) 31 32 // search vector 33 sp, _ := entity.NewIndexHNSWSearchParam(74) 34 searchResult, errSearch := mc.Search( 35 ctx, collName, 36 []string{common.DefaultPartition}, 37 "", 38 []string{common.DefaultFloatFieldName}, 39 //[]entity.Vector{entity.FloatVector([]float32{0.1, 0.2})}, 40 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 41 common.DefaultFloatVecFieldName, 42 entity.L2, 43 common.DefaultTopK, 44 sp, 45 ) 46 common.CheckErr(t, errSearch, true) 47 common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultFloatFieldName}) 48 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 49 } 50 51 func TestSearchFloatGrowing(t *testing.T) { 52 t.Parallel() 53 for _, idx := range common.GenAllFloatIndex() { 54 ctx := createContext(t, time.Second*common.DefaultTimeout) 55 // connect 56 mc := createMilvusClient(ctx, t) 57 58 // create collection with all datatype 59 cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: true, 60 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 61 collName := createCollection(ctx, t, mc, cp) 62 63 // create index and load 64 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 65 common.CheckErr(t, err, true) 66 err = mc.LoadCollection(ctx, collName, false) 67 common.CheckErr(t, err, true) 68 69 // insert 70 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVec, 71 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 72 _, err = insertData(ctx, t, mc, dp) 73 common.CheckErr(t, err, true) 74 75 // search params 76 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) 77 sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) 78 searchResult, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, 79 common.DefaultFloatVecFieldName, entity.MetricType(idx.Params()["metrics_type"]), common.DefaultTopK, sp, 80 client.WithSearchQueryConsistencyLevel(entity.ClStrong)) 81 common.CheckErr(t, errSearch, true) 82 common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatVecFieldName, 83 common.DefaultFloatFieldName, common.DefaultDynamicFieldName}) 84 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 85 } 86 } 87 88 func TestSearchBinaryGrowing(t *testing.T) { 89 t.Parallel() 90 for _, metricType := range common.SupportBinIvfFlatMetricType { 91 idxBinIvfFlat, _ := entity.NewIndexBinIvfFlat(metricType, 128) 92 ctx := createContext(t, time.Second*common.DefaultTimeout) 93 // connect 94 mc := createMilvusClient(ctx, t) 95 96 // create collection with all datatype 97 cp := CollectionParams{CollectionFieldsType: VarcharBinaryVec, AutoID: false, EnableDynamicField: false, 98 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 99 collName := createCollection(ctx, t, mc, cp) 100 101 // create index and load 102 err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idxBinIvfFlat, false) 103 common.CheckErr(t, err, true) 104 err = mc.LoadCollection(ctx, collName, false) 105 common.CheckErr(t, err, true) 106 107 // insert 108 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: VarcharBinaryVec, 109 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: false, WithRows: false} 110 _, err = insertData(ctx, t, mc, dp) 111 common.CheckErr(t, err, true) 112 113 // search params 114 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector) 115 sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) 116 searchResult, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, 117 common.DefaultBinaryVecFieldName, metricType, common.DefaultTopK, sp, 118 client.WithSearchQueryConsistencyLevel(entity.ClStrong)) 119 common.CheckErr(t, errSearch, true) 120 common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultVarcharFieldName, common.DefaultBinaryVecFieldName}) 121 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 122 } 123 } 124 125 // test search collection not exist 126 func TestSearchCollectionNotExist(t *testing.T) { 127 ctx := createContext(t, time.Second*common.DefaultTimeout) 128 // connect 129 mc := createMilvusClient(ctx, t) 130 131 // search vector 132 sp, _ := entity.NewIndexHNSWSearchParam(74) 133 _, errSearch := mc.Search( 134 ctx, "collName", 135 []string{common.DefaultPartition}, 136 "", 137 []string{common.DefaultFloatFieldName}, 138 //[]entity.Vector{entity.FloatVector([]float32{0.1, 0.2})}, 139 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 140 common.DefaultFloatVecFieldName, 141 entity.L2, 142 common.DefaultTopK, 143 sp, 144 ) 145 common.CheckErr(t, errSearch, false, "can't find collection") 146 } 147 148 // test search empty collection -> return empty 149 func TestSearchEmptyCollection(t *testing.T) { 150 t.Parallel() 151 ctx := createContext(t, time.Second*common.DefaultTimeout) 152 // connect 153 mc := createMilvusClient(ctx, t) 154 155 for _, enableDynamicField := range []bool{true, false} { 156 // empty collection 157 collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards, client.WithEnableDynamicSchema(enableDynamicField)) 158 159 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 160 mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithIndexName("")) 161 162 // load collection 163 errLoad := mc.LoadCollection(ctx, collName, false) 164 common.CheckErr(t, errLoad, true) 165 166 // search vector 167 sp, _ := entity.NewIndexHNSWSearchParam(74) 168 searchRes, errSearch := mc.Search( 169 ctx, collName, 170 []string{common.DefaultPartition}, 171 "", 172 []string{"*"}, 173 //[]entity.Vector{entity.FloatVector([]float32{0.1, 0.2})}, 174 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 175 common.DefaultFloatVecFieldName, 176 entity.L2, 177 common.DefaultTopK, 178 sp, 179 ) 180 common.CheckErr(t, errSearch, true) 181 common.CheckSearchResult(t, searchRes, common.DefaultNq, 0) 182 } 183 } 184 185 func TestSearchEmptyCollection2(t *testing.T) { 186 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 187 // connect 188 mc := createMilvusClient(ctx, t) 189 190 // create -> insert [0, 3000) -> flush -> index -> load 191 cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: true, 192 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 193 194 dp := DataParams{DoInsert: false} 195 196 // index params 197 ips := GenDefaultIndexParamsForAllVectors() 198 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 199 200 // search 201 type mNameVec struct { 202 fieldName string 203 metricType entity.MetricType 204 queryVec []entity.Vector 205 } 206 nameVecs := []mNameVec{ 207 {fieldName: common.DefaultFloatVecFieldName, metricType: entity.L2, queryVec: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector)}, 208 {fieldName: common.DefaultFloat16VecFieldName, metricType: entity.L2, queryVec: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloat16Vector)}, 209 {fieldName: common.DefaultBFloat16VecFieldName, metricType: entity.L2, queryVec: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBFloat16Vector)}, 210 {fieldName: common.DefaultBinaryVecFieldName, metricType: entity.JACCARD, queryVec: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector)}, 211 } 212 sp, _ := entity.NewIndexHNSWSearchParam(100) 213 for _, nv := range nameVecs { 214 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, nv.queryVec, nv.fieldName, 215 nv.metricType, common.DefaultTopK, sp) 216 common.CheckErr(t, errSearch, true) 217 common.CheckSearchResult(t, resSearch, common.DefaultNq, 0) 218 } 219 } 220 221 // test search with partition names []string{}, []string{""} 222 func TestSearchEmptyPartitions(t *testing.T) { 223 ctx := createContext(t, time.Second*common.DefaultTimeout) 224 // connect 225 mc := createMilvusClient(ctx, t) 226 227 for _, enableDynamicField := range []bool{true, false} { 228 // create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition 229 collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards, client.WithEnableDynamicSchema(enableDynamicField)) 230 _, vecColumnDefault, vecColumnPartition := createInsertTwoPartitions(ctx, t, mc, collName, 500) 231 232 // create index 233 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 234 mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 235 236 // load with not exist partition names 237 errLoad := mc.LoadCollection(ctx, collName, false) 238 common.CheckErr(t, errLoad, true) 239 240 // search with empty partition name []string{""} 241 sp, _ := entity.NewIndexHNSWSearchParam(74) 242 _, errSearch := mc.Search( 243 ctx, collName, 244 []string{""}, 245 "", 246 []string{common.DefaultFloatFieldName}, 247 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 248 common.DefaultFloatVecFieldName, 249 entity.L2, 250 common.DefaultTopK, 251 sp, 252 ) 253 common.CheckErr(t, errSearch, false, "Partition name should not be empty") 254 255 // search with empty partition names slice []string{} 256 vecDefaultData := vecColumnDefault.VectorColumn.(*entity.ColumnFloatVector).Data()[0] 257 vecPartitionData := vecColumnPartition.VectorColumn.(*entity.ColumnFloatVector).Data()[0] 258 searchResult, _ := mc.Search( 259 ctx, collName, 260 []string{}, 261 "", 262 []string{common.DefaultFloatFieldName}, 263 []entity.Vector{ 264 entity.FloatVector(vecDefaultData), 265 entity.FloatVector(vecPartitionData), 266 }, 267 common.DefaultFloatVecFieldName, 268 entity.L2, 269 common.DefaultTopK, 270 sp, 271 ) 272 273 // check search result contains search vector, which from all partitions 274 nq0IDs := searchResult[0].IDs.(*entity.ColumnInt64).Data() 275 nq1IDs := searchResult[1].IDs.(*entity.ColumnInt64).Data() 276 common.CheckSearchResult(t, searchResult, 2, common.DefaultTopK) 277 require.Contains(t, nq0IDs, vecColumnDefault.IdsColumn.(*entity.ColumnInt64).Data()[0]) 278 require.Contains(t, nq1IDs, vecColumnPartition.IdsColumn.(*entity.ColumnInt64).Data()[0]) 279 } 280 } 281 282 // test search with an not existed partition -> error 283 func TestSearchPartitionNotExist(t *testing.T) { 284 ctx := createContext(t, time.Second*common.DefaultTimeout) 285 // connect 286 mc := createMilvusClient(ctx, t) 287 288 // create collection with data 289 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, false) 290 291 type notExistPartitions []string 292 293 // search partitions not exist, part exist 294 partitionsNotExist := []notExistPartitions{[]string{"new"}, []string{"new", common.DefaultPartition}} 295 296 for _, partitions := range partitionsNotExist { 297 sp, _ := entity.NewIndexHNSWSearchParam(74) 298 _, errSearch := mc.Search( 299 ctx, collName, 300 partitions, 301 "", 302 []string{common.DefaultFloatFieldName}, 303 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 304 common.DefaultFloatVecFieldName, 305 entity.L2, 306 common.DefaultTopK, 307 sp, 308 ) 309 common.CheckErr(t, errSearch, false, "partition name new not found") 310 } 311 } 312 313 // test search single partition and multi partitions 314 func TestSearchPartitions(t *testing.T) { 315 ctx := createContext(t, time.Second*common.DefaultTimeout) 316 // connect 317 mc := createMilvusClient(ctx, t) 318 319 // create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition 320 collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards) 321 partitionName, vecColumnDefault, vecColumnPartition := createInsertTwoPartitions(ctx, t, mc, collName, 500) 322 323 // create index 324 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 325 mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 326 327 // load with not exist partition names 328 errLoad := mc.LoadCollection(ctx, collName, false) 329 common.CheckErr(t, errLoad, true) 330 331 vecDefaultData := vecColumnDefault.VectorColumn.(*entity.ColumnFloatVector).Data()[0] 332 vecPartitionData := vecColumnPartition.VectorColumn.(*entity.ColumnFloatVector).Data()[0] 333 334 // search single partition 335 sp, _ := entity.NewIndexHNSWSearchParam(74) 336 searchSingleRes, _ := mc.Search( 337 ctx, collName, 338 []string{common.DefaultPartition}, 339 "", 340 []string{common.DefaultFloatFieldName}, 341 []entity.Vector{ 342 entity.FloatVector(vecDefaultData), 343 entity.FloatVector(vecPartitionData), 344 }, 345 common.DefaultFloatVecFieldName, 346 entity.L2, 347 common.DefaultTopK, 348 sp, 349 ) 350 // check search result contains search vector, which from all partitions 351 common.CheckSearchResult(t, searchSingleRes, 2, common.DefaultTopK) 352 require.Contains(t, searchSingleRes[0].IDs.(*entity.ColumnInt64).Data(), vecColumnDefault.IdsColumn.(*entity.ColumnInt64).Data()[0]) 353 354 // search multi partitions 355 searchMultiRes, _ := mc.Search( 356 ctx, collName, 357 []string{common.DefaultPartition, partitionName}, 358 "", 359 []string{common.DefaultFloatFieldName}, 360 []entity.Vector{ 361 entity.FloatVector(vecDefaultData), 362 entity.FloatVector(vecPartitionData), 363 }, 364 common.DefaultFloatVecFieldName, 365 entity.L2, 366 common.DefaultTopK, 367 sp, 368 ) 369 common.CheckSearchResult(t, searchMultiRes, 2, common.DefaultTopK) 370 require.Contains(t, searchMultiRes[0].IDs.(*entity.ColumnInt64).Data(), vecColumnDefault.IdsColumn.(*entity.ColumnInt64).Data()[0]) 371 require.Contains(t, searchMultiRes[1].IDs.(*entity.ColumnInt64).Data(), vecColumnPartition.IdsColumn.(*entity.ColumnInt64).Data()[0]) 372 } 373 374 // test search empty output fields []string{} -> [], []string{""} 375 func TestSearchEmptyOutputFields(t *testing.T) { 376 t.Parallel() 377 ctx := createContext(t, time.Second*common.DefaultTimeout) 378 // connect 379 mc := createMilvusClient(ctx, t) 380 381 for _, enableDynamic := range []bool{true, false} { 382 // create collection with data 383 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true, client.WithEnableDynamicSchema(enableDynamic)) 384 385 // load collection 386 errLoad := mc.LoadCollection(ctx, collName, false) 387 common.CheckErr(t, errLoad, true) 388 389 // search vector output fields []string{} -> [] 390 sp, _ := entity.NewIndexHNSWSearchParam(74) 391 searchResPkOutput, errSearch := mc.Search( 392 ctx, collName, 393 []string{}, 394 "", 395 []string{}, 396 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 397 common.DefaultFloatVecFieldName, 398 entity.L2, 399 common.DefaultTopK, 400 sp, 401 ) 402 common.CheckErr(t, errSearch, true) 403 common.CheckOutputFields(t, searchResPkOutput[0].Fields, []string{}) 404 common.CheckSearchResult(t, searchResPkOutput, common.DefaultNq, common.DefaultTopK) 405 406 // search vector output fields []string{""} 407 res, errSearchExist := mc.Search( 408 ctx, collName, 409 []string{}, 410 "", 411 []string{"a"}, 412 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 413 common.DefaultFloatVecFieldName, 414 entity.L2, 415 common.DefaultTopK, 416 sp, 417 ) 418 419 if enableDynamic { 420 common.CheckErr(t, errSearchExist, true) 421 common.CheckOutputFields(t, res[0].Fields, []string{"a"}) 422 } else { 423 common.CheckErr(t, errSearchExist, false, "not exist") 424 } 425 common.CheckSearchResult(t, searchResPkOutput, common.DefaultNq, common.DefaultTopK) 426 } 427 } 428 429 // test search output fields not exist -> output existed fields 430 func TestSearchNotExistOutputFields(t *testing.T) { 431 t.Parallel() 432 ctx := createContext(t, time.Second*common.DefaultTimeout) 433 // connect 434 mc := createMilvusClient(ctx, t) 435 436 for _, enableDynamic := range []bool{false, true} { 437 // create collection with data 438 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true, client.WithEnableDynamicSchema(enableDynamic)) 439 440 // load collection 441 errLoad := mc.LoadCollection(ctx, collName, false) 442 common.CheckErr(t, errLoad, true) 443 444 type notExistOutputFields []string 445 446 // search vector output fields not exist, part exist 447 outputFields := []notExistOutputFields{[]string{"aaa"}, []string{"fields", common.DefaultFloatFieldName}, 448 []string{"fields", "*"}} 449 sp, _ := entity.NewIndexHNSWSearchParam(74) 450 for _, fields := range outputFields { 451 log.Println(fields) 452 _, errSearch := mc.Search( 453 ctx, collName, 454 []string{}, 455 "", 456 fields, 457 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 458 common.DefaultFloatVecFieldName, 459 entity.L2, 460 common.DefaultTopK, 461 sp, 462 ) 463 if enableDynamic { 464 common.CheckErr(t, errSearch, true) 465 } else { 466 common.CheckErr(t, errSearch, false, "not exist") 467 } 468 } 469 } 470 } 471 472 // test search output fields only pk 473 func TestSearchOutputFields(t *testing.T) { 474 t.Parallel() 475 ctx := createContext(t, time.Second*common.DefaultTimeout) 476 // connect 477 mc := createMilvusClient(ctx, t) 478 479 for _, enableDynamic := range []bool{true, false} { 480 // create collection 481 cp := CollectionParams{CollectionFieldsType: VarcharBinaryVec, AutoID: false, EnableDynamicField: enableDynamic, 482 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 483 collName := createCollection(ctx, t, mc, cp) 484 485 // insert 486 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: VarcharBinaryVec, 487 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: enableDynamic} 488 _, _ = insertData(ctx, t, mc, dp) 489 mc.Flush(ctx, collName, false) 490 491 // index 492 idx, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 128) 493 err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idx, false, client.WithIndexName("")) 494 common.CheckErr(t, err, true) 495 496 // load collection 497 errLoad := mc.LoadCollection(ctx, collName, false) 498 common.CheckErr(t, errLoad, true) 499 500 // search vector output fields not exist 501 outputFields := []string{common.DefaultVarcharFieldName, common.DefaultBinaryVecFieldName} 502 if enableDynamic { 503 outputFields = append(outputFields, common.DefaultDynamicFieldName) 504 } 505 sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) 506 searchRes, _ := mc.Search( 507 ctx, collName, 508 []string{}, 509 "", 510 outputFields, 511 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector), 512 common.DefaultBinaryVecFieldName, 513 entity.JACCARD, 514 common.DefaultTopK, 515 sp, 516 ) 517 common.CheckOutputFields(t, searchRes[0].Fields, outputFields) 518 common.CheckSearchResult(t, searchRes, common.DefaultNq, common.DefaultTopK) 519 } 520 } 521 522 // test search output all * fields when enable dynamic and insert dynamic column data 523 func TestSearchOutputAllFields(t *testing.T) { 524 t.Parallel() 525 ctx := createContext(t, time.Second*common.DefaultTimeout) 526 // connect 527 mc := createMilvusClient(ctx, t) 528 529 for _, enableDynamic := range []bool{false, true} { 530 // create collection 531 cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: enableDynamic, 532 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 533 collName := createCollection(ctx, t, mc, cp) 534 535 // insert 536 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: AllFields, 537 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: enableDynamic} 538 _, _ = insertData(ctx, t, mc, dp) 539 _ = mc.Flush(ctx, collName, false) 540 541 // create index 542 indexHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 543 indexBinary, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 64) 544 for _, fieldName := range common.AllVectorsFieldsName { 545 if fieldName == common.DefaultBinaryVecFieldName { 546 mc.CreateIndex(ctx, collName, fieldName, indexBinary, false) 547 } else { 548 mc.CreateIndex(ctx, collName, fieldName, indexHnsw, false) 549 } 550 } 551 552 // Load collection 553 errLoad := mc.LoadCollection(ctx, collName, false) 554 common.CheckErr(t, errLoad, true) 555 556 // search vector output all scalar fields 557 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) 558 allFields := common.GetAllFieldsName(enableDynamic, false) 559 sp, _ := entity.NewIndexHNSWSearchParam(74) 560 searchRes, _ := mc.Search(ctx, collName, []string{}, 561 "", 562 []string{"*"}, 563 queryVec, 564 common.DefaultFloatVecFieldName, 565 entity.L2, 566 common.DefaultTopK, 567 sp, 568 ) 569 common.CheckOutputFields(t, searchRes[0].Fields, allFields) 570 571 // search with output * fields 572 if enableDynamic { 573 //search output [*, a] fields -> output all fields, no a field 574 _, errNotExist := mc.Search(ctx, collName, []string{}, "", []string{"*", "a"}, queryVec, 575 common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, sp) 576 common.CheckErr(t, errNotExist, true) 577 common.CheckOutputFields(t, searchRes[0].Fields, allFields) 578 579 //search output [*, dynamicNumber] fields -> -> output all fields, $meta replace by dynamicNumber 580 searchRes, _ = mc.Search(ctx, collName, []string{}, "", []string{"*", common.DefaultDynamicNumberField}, 581 queryVec, common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, sp) 582 common.CheckOutputFields(t, searchRes[0].Fields, append(allFields, common.DefaultDynamicNumberField)) 583 584 ///search output [*, dynamicNumber] fields -> -> output all fields, $meta replace by dynamicNumber 585 searchRes, _ = mc.Search(ctx, collName, []string{}, "", []string{common.DefaultDynamicNumberField}, 586 queryVec, common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, sp) 587 common.CheckOutputFields(t, searchRes[0].Fields, []string{common.DefaultDynamicNumberField}) 588 } 589 } 590 } 591 592 // test search with invalid vector field name: not exist; non-vector field, empty fiend name, json and dynamic field -> error 593 func TestSearchInvalidVectorField(t *testing.T) { 594 ctx := createContext(t, time.Second*common.DefaultTimeout) 595 // connect 596 mc := createMilvusClient(ctx, t) 597 598 // create collection with data 599 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 600 601 // load collection 602 errLoad := mc.LoadCollection(ctx, collName, false) 603 common.CheckErr(t, errLoad, true) 604 605 type invalidVectorFieldStruct struct { 606 vectorField string 607 errNil bool 608 errMsg string 609 } 610 611 invalidVectorFields := []invalidVectorFieldStruct{ 612 // not exist field 613 {vectorField: common.DefaultBinaryVecFieldName, errNil: false, errMsg: fmt.Sprintf("failed to get field schema by name: fieldName(%s) not found", common.DefaultBinaryVecFieldName)}, 614 615 // non-vector field 616 {vectorField: common.DefaultIntFieldName, errNil: false, errMsg: fmt.Sprintf("failed to create query plan: field (%s) to search is not of vector data type", common.DefaultIntFieldName)}, 617 618 // json field 619 {vectorField: common.DefaultJSONFieldName, errNil: false, errMsg: fmt.Sprintf("failed to get field schema by name: fieldName(%s) not found", common.DefaultJSONFieldName)}, 620 621 // dynamic field 622 {vectorField: common.DefaultDynamicFieldName, errNil: false, errMsg: fmt.Sprintf("failed to get field schema by name: fieldName(%s) not found", common.DefaultDynamicFieldName)}, 623 624 // allows empty vector field name 625 {vectorField: "", errNil: true, errMsg: ""}, 626 } 627 628 sp, _ := entity.NewIndexHNSWSearchParam(74) 629 for _, invalidVectorField := range invalidVectorFields { 630 t.Run(invalidVectorField.vectorField, func(t *testing.T) { 631 _, errSearchNotExist := mc.Search( 632 ctx, collName, 633 []string{}, 634 "", 635 []string{common.DefaultIntFieldName}, 636 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 637 invalidVectorField.vectorField, 638 entity.L2, 639 common.DefaultTopK, 640 sp, 641 ) 642 common.CheckErr(t, errSearchNotExist, invalidVectorField.errNil, invalidVectorField.errMsg) 643 }) 644 } 645 } 646 647 // test search with invalid vectors 648 func TestSearchInvalidVectors(t *testing.T) { 649 t.Parallel() 650 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 651 // connect 652 mc := createMilvusClient(ctx, t) 653 654 // create collection with data 655 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 656 657 // load collection 658 errLoad := mc.LoadCollection(ctx, collName, false) 659 common.CheckErr(t, errLoad, true) 660 661 type invalidVectorsStruct struct { 662 vectors []entity.Vector 663 errMsg string 664 } 665 666 invalidVectors := []invalidVectorsStruct{ 667 // dim not match 668 {vectors: common.GenSearchVectors(common.DefaultNq, 64, entity.FieldTypeFloatVector), errMsg: "vector dimension mismatch"}, 669 670 //vector type not match 671 {vectors: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector), errMsg: "vector type must be the same"}, 672 673 // empty vectors 674 {vectors: []entity.Vector{}, errMsg: "nq [0] is invalid"}, 675 {vectors: []entity.Vector{entity.FloatVector{}}, errMsg: "vector dimension mismatch"}, 676 } 677 678 sp, _ := entity.NewIndexHNSWSearchParam(74) 679 for _, invalidVector := range invalidVectors { 680 // search vectors empty slice 681 _, errSearchEmpty := mc.Search( 682 ctx, collName, 683 []string{}, 684 "", 685 []string{"*"}, 686 invalidVector.vectors, 687 common.DefaultFloatVecFieldName, 688 entity.L2, 689 common.DefaultTopK, 690 sp, 691 ) 692 common.CheckErr(t, errSearchEmpty, false, invalidVector.errMsg) 693 } 694 } 695 696 // test search with invalid vectors 697 func TestSearchInvalidVectorsEmptyCollection(t *testing.T) { 698 t.Skip("https://github.com/milvus-io/milvus/issues/33639") 699 t.Skip("https://github.com/milvus-io/milvus/issues/33637") 700 t.Parallel() 701 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 702 // connect 703 mc := createMilvusClient(ctx, t) 704 705 // create collection with data 706 collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards) 707 708 // index 709 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 710 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithIndexName("")) 711 common.CheckErr(t, err, true) 712 713 // load collection 714 errLoad := mc.LoadCollection(ctx, collName, false) 715 common.CheckErr(t, errLoad, true) 716 717 type invalidVectorsStruct struct { 718 vectors []entity.Vector 719 errMsg string 720 } 721 722 invalidVectors := []invalidVectorsStruct{ 723 // dim not match 724 {vectors: common.GenSearchVectors(common.DefaultNq, 64, entity.FieldTypeFloatVector), errMsg: "vector dimension mismatch"}, 725 726 //vector type not match 727 {vectors: common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector), errMsg: "vector type must be the same"}, 728 729 // empty vectors 730 {vectors: []entity.Vector{}, errMsg: "nq [0] is invalid"}, 731 {vectors: []entity.Vector{entity.FloatVector{}}, errMsg: "vector dimension mismatch"}, 732 } 733 734 sp, _ := entity.NewIndexHNSWSearchParam(74) 735 for _, invalidVector := range invalidVectors { 736 // search vectors empty slice 737 _, errSearchEmpty := mc.Search(ctx, collName, []string{}, "", []string{"*"}, invalidVector.vectors, 738 common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, sp) 739 common.CheckErr(t, errSearchEmpty, false, invalidVector.errMsg) 740 } 741 } 742 743 // test search metric type isn't the same with index metric type 744 func TestSearchNotMatchMetricType(t *testing.T) { 745 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 746 // connect 747 mc := createMilvusClient(ctx, t) 748 749 // create collection with data 750 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 751 752 // load collection 753 errLoad := mc.LoadCollection(ctx, collName, false) 754 common.CheckErr(t, errLoad, true) 755 756 sp, _ := entity.NewIndexHNSWSearchParam(74) 757 _, errSearchEmpty := mc.Search( 758 ctx, collName, 759 []string{}, 760 "", 761 []string{common.DefaultIntFieldName}, 762 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 763 common.DefaultFloatVecFieldName, 764 entity.IP, 765 common.DefaultTopK, 766 sp, 767 ) 768 common.CheckErr(t, errSearchEmpty, false, "invalid parameter") 769 } 770 771 // test search with invalid topK -> error 772 func TestSearchInvalidTopK(t *testing.T) { 773 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 774 // connect 775 mc := createMilvusClient(ctx, t) 776 777 // create collection with data 778 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, false) 779 780 // create ivf sq8 index 781 idx, _ := entity.NewIndexIvfFlat(entity.L2, 128) 782 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithIndexName("")) 783 common.CheckErr(t, err, true) 784 785 // load collection 786 errLoad := mc.LoadCollection(ctx, collName, false) 787 common.CheckErr(t, errLoad, true) 788 789 invalidTopKs := []int{-1, 0, 16385} 790 791 sp, _ := entity.NewIndexIvfSQ8SearchParam(64) 792 793 for _, invalidTopK := range invalidTopKs { 794 _, errSearchEmpty := mc.Search( 795 ctx, collName, 796 []string{}, 797 "", 798 []string{common.DefaultIntFieldName}, 799 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 800 common.DefaultFloatVecFieldName, 801 entity.L2, 802 invalidTopK, 803 sp, 804 ) 805 common.CheckErr(t, errSearchEmpty, false, "should be in range [1, 16384]") 806 } 807 } 808 809 // test search with invalid search params 810 func TestSearchInvalidSearchParams(t *testing.T) { 811 812 // ivf flat search params nlist [1, 65536], nprobe [1, nlist] 813 invalidNprobe := []int{-1, 0, 65537} 814 for _, nprobe := range invalidNprobe { 815 _, errIvfFlat := entity.NewIndexIvfFlatSearchParam(nprobe) 816 common.CheckErr(t, errIvfFlat, false, "nprobe has to be in range [1, 65536]") 817 } 818 819 // ivf sq8 search param 820 for _, nprobe := range invalidNprobe { 821 _, errIvfSq8 := entity.NewIndexIvfSQ8SearchParam(nprobe) 822 log.Println(nprobe) 823 common.CheckErr(t, errIvfSq8, false, "nprobe has to be in range [1, 65536]") 824 } 825 826 // ivf pq search param 827 for _, nprobe := range invalidNprobe { 828 _, errIvfPq := entity.NewIndexIvfPQSearchParam(nprobe) 829 common.CheckErr(t, errIvfPq, false, "nprobe has to be in range [1, 65536]") 830 } 831 832 // hnsw search params ef [top_k, 32768] 833 invalidEfs := []int{-1, 0, 32769} 834 for _, invalidEf := range invalidEfs { 835 _, errHnsw := entity.NewIndexHNSWSearchParam(invalidEf) 836 common.CheckErr(t, errHnsw, false, "ef has to be in range [1, 32768]") 837 } 838 839 // bin ivf flat 840 for _, nprobe := range invalidNprobe { 841 _, errBinIvfFlat := entity.NewIndexBinIvfFlatSearchParam(nprobe) 842 common.CheckErr(t, errBinIvfFlat, false, "nprobe has to be in range [1, 65536]") 843 } 844 845 // scann index invalid nprobe 846 for _, nprobe := range invalidNprobe { 847 _, errScann := entity.NewIndexSCANNSearchParam(nprobe, 100) 848 common.CheckErr(t, errScann, false, "nprobe has to be in range [1, 65536]") 849 } 850 851 _, errScann := entity.NewIndexSCANNSearchParam(16, 0) 852 common.CheckErr(t, errScann, false, "reorder_k has to be in range [1, 9223372036854775807]") 853 } 854 855 // search with index hnsw search param ef < topK -> error 856 func TestSearchEfHnsw(t *testing.T) { 857 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 858 // connect 859 mc := createMilvusClient(ctx, t) 860 861 // create collection with data 862 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 863 864 // load collection 865 errLoad := mc.LoadCollection(ctx, collName, false) 866 common.CheckErr(t, errLoad, true) 867 868 // ef [top_k, 32768] 869 sp, _ := entity.NewIndexHNSWSearchParam(7) 870 _, errSearchEmpty := mc.Search( 871 ctx, collName, 872 []string{}, 873 "", 874 []string{common.DefaultIntFieldName}, 875 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 876 common.DefaultFloatVecFieldName, 877 entity.L2, 878 common.DefaultTopK, 879 sp, 880 ) 881 common.CheckErr(t, errSearchEmpty, false, "ef(7) should be larger than k(10)") 882 } 883 884 // test search params mismatch index type, hnsw index and ivf sq8 search param -> search with default hnsw params, ef=topK 885 func TestSearchSearchParamsMismatchIndex(t *testing.T) { 886 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 887 // connect 888 mc := createMilvusClient(ctx, t) 889 890 // create collection with data and create hnsw index 891 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 892 893 // load collection 894 errLoad := mc.LoadCollection(ctx, collName, false) 895 common.CheckErr(t, errLoad, true) 896 897 // ef [top_k, 32768] 898 sp, _ := entity.NewIndexIvfSQ8SearchParam(64) 899 resSearch, errSearch := mc.Search( 900 ctx, collName, 901 []string{}, 902 "", 903 []string{common.DefaultIntFieldName}, 904 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 905 common.DefaultFloatVecFieldName, 906 entity.L2, 907 common.DefaultTopK, 908 sp, 909 ) 910 common.CheckErr(t, errSearch, true) 911 common.CheckSearchResult(t, resSearch, common.DefaultNq, common.DefaultTopK) 912 } 913 914 // test search with valid expression 915 func TestSearchExpr(t *testing.T) { 916 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 917 // connect 918 mc := createMilvusClient(ctx, t) 919 920 // create collection with data 921 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 922 923 // load collection 924 errLoad := mc.LoadCollection(ctx, collName, false) 925 common.CheckErr(t, errLoad, true) 926 927 // search vector with expr: int64 < 1000 928 sp, _ := entity.NewIndexHNSWSearchParam(74) 929 searchResult, errSearch := mc.Search( 930 ctx, collName, 931 []string{common.DefaultPartition}, 932 fmt.Sprintf("%s < 1000", common.DefaultFloatFieldName), 933 []string{common.DefaultFloatFieldName}, 934 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 935 common.DefaultFloatVecFieldName, 936 entity.L2, 937 common.DefaultTopK, 938 sp, 939 ) 940 common.CheckErr(t, errSearch, true) 941 // check search ids less than 1000 942 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 943 for _, res := range searchResult { 944 for _, id := range res.IDs.(*entity.ColumnInt64).Data() { 945 require.Less(t, id, int64(1000)) 946 } 947 } 948 949 // search vector with expr: float in [1.0] 950 searchResult2, errSearch2 := mc.Search( 951 ctx, collName, 952 []string{common.DefaultPartition}, 953 fmt.Sprintf("%s in [1.0]", common.DefaultFloatFieldName), 954 []string{common.DefaultFloatFieldName}, 955 common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector), 956 common.DefaultFloatVecFieldName, 957 entity.L2, 958 2, 959 sp, 960 ) 961 common.CheckErr(t, errSearch2, true) 962 // check search ids equal to 1 963 common.CheckSearchResult(t, searchResult2, 1, 1) 964 require.Equal(t, searchResult2[0].IDs.(*entity.ColumnInt64).Data()[0], int64(1)) 965 } 966 967 // test search with invalid expression 968 func TestSearchInvalidExpr(t *testing.T) { 969 t.Parallel() 970 971 ctx := createContext(t, time.Second*common.DefaultTimeout) 972 // connect 973 mc := createMilvusClient(ctx, t) 974 975 // create collection 976 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 977 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 978 collName := createCollection(ctx, t, mc, cp) 979 980 // insert 981 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 982 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true} 983 _, _ = insertData(ctx, t, mc, dp) 984 985 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 986 _ = mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 987 988 // Load collection 989 errLoad := mc.LoadCollection(ctx, collName, false) 990 common.CheckErr(t, errLoad, true) 991 992 // search with invalid expr 993 sp, _ := entity.NewIndexHNSWSearchParam(74) 994 for _, exprStruct := range common.InvalidExpressions { 995 _, errSearchEmpty := mc.Search( 996 ctx, collName, 997 []string{}, 998 exprStruct.Expr, 999 []string{common.DefaultIntFieldName}, 1000 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1001 common.DefaultFloatVecFieldName, 1002 entity.L2, 1003 common.DefaultTopK, 1004 sp, 1005 ) 1006 common.CheckErr(t, errSearchEmpty, exprStruct.ErrNil, exprStruct.ErrMsg) 1007 } 1008 } 1009 1010 func TestSearchJsonFieldExpr(t *testing.T) { 1011 t.Parallel() 1012 1013 ctx := createContext(t, time.Second*common.DefaultTimeout) 1014 // connect 1015 mc := createMilvusClient(ctx, t) 1016 1017 for _, dynamicField := range []bool{false} { 1018 // create collection 1019 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: dynamicField, 1020 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1021 collName := createCollection(ctx, t, mc, cp) 1022 1023 // insert 1024 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1025 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: dynamicField} 1026 _, _ = insertData(ctx, t, mc, dp) 1027 mc.Flush(ctx, collName, false) 1028 1029 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1030 _ = mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 1031 1032 // Load collection 1033 errLoad := mc.LoadCollection(ctx, collName, false) 1034 common.CheckErr(t, errLoad, true) 1035 1036 exprs := []string{ 1037 "", 1038 fmt.Sprintf("exists %s['number'] ", common.DefaultJSONFieldName), // exists 1039 "json[\"number\"] > 1 and json[\"number\"] < 1000", // > and 1040 fmt.Sprintf("%s[\"number\"] > 10", common.DefaultJSONFieldName), // number > 1041 fmt.Sprintf("%s != 10 ", common.DefaultJSONFieldName), // json != 10 1042 fmt.Sprintf("%s[\"number\"] < 2000", common.DefaultJSONFieldName), // number < 1043 fmt.Sprintf("%s[\"bool\"] != true", common.DefaultJSONFieldName), // bool != 1044 fmt.Sprintf("%s[\"bool\"] == False", common.DefaultJSONFieldName), // bool == 1045 fmt.Sprintf("%s[\"bool\"] in [true]", common.DefaultJSONFieldName), // bool in 1046 fmt.Sprintf("%s[\"string\"] >= '1' ", common.DefaultJSONFieldName), // string >= 1047 fmt.Sprintf("%s['list'][0] > 200", common.DefaultJSONFieldName), // list filter 1048 fmt.Sprintf("%s['list'] != [2, 3]", common.DefaultJSONFieldName), // json[list] != 1049 fmt.Sprintf("%s > 2000", common.DefaultJSONFieldName), // json > 2000 1050 fmt.Sprintf("%s like '2%%' ", common.DefaultJSONFieldName), // json like '2%' 1051 fmt.Sprintf("%s[0] > 2000 ", common.DefaultJSONFieldName), // json[0] > 2000 1052 fmt.Sprintf("%s > 2000.5 ", common.DefaultJSONFieldName), // json > 2000.5 1053 } 1054 1055 // search with jsonField expr key datatype and json data type mismatch 1056 sp, _ := entity.NewIndexHNSWSearchParam(74) 1057 for _, expr := range exprs { 1058 log.Printf("search expr: %s", expr) 1059 searchRes, errSearchEmpty := mc.Search( 1060 ctx, collName, 1061 []string{}, 1062 expr, 1063 []string{common.DefaultIntFieldName, common.DefaultJSONFieldName}, 1064 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1065 common.DefaultFloatVecFieldName, 1066 entity.L2, 1067 common.DefaultTopK, 1068 sp, 1069 ) 1070 common.CheckErr(t, errSearchEmpty, true) 1071 common.CheckOutputFields(t, searchRes[0].Fields, []string{common.DefaultIntFieldName, common.DefaultJSONFieldName}) 1072 common.CheckSearchResult(t, searchRes, common.DefaultNq, common.DefaultTopK) 1073 } 1074 } 1075 } 1076 1077 // search dynamic field with expr 1078 func TestSearchDynamicFieldExpr(t *testing.T) { 1079 t.Parallel() 1080 1081 ctx := createContext(t, time.Second*common.DefaultTimeout) 1082 // connect 1083 mc := createMilvusClient(ctx, t) 1084 1085 for _, withRows := range []bool{true, false} { 1086 // create collection 1087 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 1088 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1089 collName := createCollection(ctx, t, mc, cp) 1090 1091 // insert 1092 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1093 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: withRows} 1094 _, _ = insertData(ctx, t, mc, dp) 1095 mc.Flush(ctx, collName, false) 1096 1097 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1098 _ = mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 1099 1100 // Load collection 1101 errLoad := mc.LoadCollection(ctx, collName, false) 1102 common.CheckErr(t, errLoad, true) 1103 1104 exprs := []string{ 1105 "", 1106 "exists dynamicNumber", // exist without dynamic fieldName 1107 fmt.Sprintf("exists %s[\"dynamicNumber\"]", common.DefaultDynamicFieldName), // exist with fieldName 1108 fmt.Sprintf("%s[\"dynamicNumber\"] > 10", common.DefaultDynamicFieldName), // int expr with fieldName 1109 fmt.Sprintf("%s[\"dynamicBool\"] == true", common.DefaultDynamicFieldName), // bool with fieldName 1110 "dynamicBool == False", // bool without fieldName 1111 fmt.Sprintf("%s['dynamicString'] == '1'", common.DefaultDynamicFieldName), // string with fieldName 1112 "dynamicString != \"2\" ", // string without fieldName 1113 } 1114 1115 // search with jsonField expr key datatype and json data type mismatch 1116 sp, _ := entity.NewIndexHNSWSearchParam(74) 1117 for _, expr := range exprs { 1118 log.Print(expr) 1119 searchRes, errSearchEmpty := mc.Search( 1120 ctx, collName, 1121 []string{}, 1122 expr, 1123 []string{common.DefaultIntFieldName, "dynamicNumber", "number"}, 1124 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1125 common.DefaultFloatVecFieldName, 1126 entity.L2, 1127 common.DefaultTopK, 1128 sp, 1129 ) 1130 common.CheckErr(t, errSearchEmpty, true) 1131 common.CheckOutputFields(t, searchRes[0].Fields, []string{common.DefaultIntFieldName, "dynamicNumber", "number"}) 1132 if expr == "$meta['dynamicString'] == '1'" { 1133 common.CheckSearchResult(t, searchRes, common.DefaultNq, 1) 1134 } else { 1135 common.CheckSearchResult(t, searchRes, common.DefaultNq, common.DefaultTopK) 1136 } 1137 } 1138 1139 // search with expr filter number and, &&, or, || 1140 exprs2 := []string{ 1141 "dynamicNumber > 1 and dynamicNumber <= 999", // int expr without fieldName 1142 fmt.Sprintf("%s['dynamicNumber'] > 1 && %s['dynamicNumber'] < 1000", common.DefaultDynamicFieldName, common.DefaultDynamicFieldName), 1143 "dynamicNumber < 888 || dynamicNumber < 1000", 1144 fmt.Sprintf("%s['dynamicNumber'] < 888 or %s['dynamicNumber'] < 1000", common.DefaultDynamicFieldName, common.DefaultDynamicFieldName), 1145 fmt.Sprintf("%s[\"dynamicNumber\"] < 1000", common.DefaultDynamicFieldName), // int expr with fieldName 1146 } 1147 1148 // search 1149 for _, expr := range exprs2 { 1150 log.Print(expr) 1151 searchRes, errSearchEmpty := mc.Search( 1152 ctx, collName, 1153 []string{}, 1154 expr, 1155 []string{common.DefaultIntFieldName, common.DefaultJSONFieldName, common.DefaultDynamicFieldName, "dynamicNumber", "number"}, 1156 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1157 common.DefaultFloatVecFieldName, 1158 entity.L2, 1159 common.DefaultTopK, 1160 sp, 1161 ) 1162 common.CheckErr(t, errSearchEmpty, true) 1163 common.CheckOutputFields(t, searchRes[0].Fields, []string{common.DefaultIntFieldName, common.DefaultJSONFieldName, common.DefaultDynamicFieldName, "dynamicNumber", "number"}) 1164 for _, res := range searchRes { 1165 for _, id := range res.IDs.(*entity.ColumnInt64).Data() { 1166 require.Less(t, id, int64(1000)) 1167 } 1168 } 1169 } 1170 } 1171 } 1172 1173 func TestSearchArrayFieldExpr(t *testing.T) { 1174 t.Parallel() 1175 1176 ctx := createContext(t, time.Second*common.DefaultTimeout) 1177 // connect 1178 mc := createMilvusClient(ctx, t) 1179 var capacity int64 = common.TestCapacity 1180 1181 for _, withRows := range []bool{true, false} { 1182 // create collection 1183 cp := CollectionParams{CollectionFieldsType: Int64FloatVecArray, AutoID: false, EnableDynamicField: true, 1184 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxCapacity: capacity} 1185 collName := createCollection(ctx, t, mc, cp, client.WithConsistencyLevel(entity.ClStrong)) 1186 1187 // prepare and insert data 1188 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecArray, 1189 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: withRows} 1190 _, _ = insertData(ctx, t, mc, dp, common.WithArrayCapacity(capacity)) 1191 mc.Flush(ctx, collName, false) 1192 1193 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1194 _ = mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) 1195 1196 // Load collection 1197 errLoad := mc.LoadCollection(ctx, collName, false) 1198 common.CheckErr(t, errLoad, true) 1199 1200 exprs := []string{ 1201 fmt.Sprintf("%s[0] == false", common.DefaultBoolArrayField), // array[0] == 1202 fmt.Sprintf("%s[0] > 0", common.DefaultInt64ArrayField), // array[0] > 1203 fmt.Sprintf("json_contains (%s, %d)", common.DefaultInt16ArrayField, capacity), // json_contains 1204 fmt.Sprintf("array_contains (%s, %d)", common.DefaultInt16ArrayField, capacity), // array_contains 1205 fmt.Sprintf("json_contains_all (%s, [90, 91])", common.DefaultInt64ArrayField), // json_contains_all 1206 fmt.Sprintf("array_contains_all (%s, [90, 91])", common.DefaultInt64ArrayField), // array_contains_all 1207 fmt.Sprintf("array_contains_any (%s, [0, 100, 10000])", common.DefaultFloatArrayField), // array_contains_any 1208 fmt.Sprintf("json_contains_any (%s, [0, 100, 10])", common.DefaultFloatArrayField), // json_contains_any 1209 fmt.Sprintf("array_length(%s) == %d", common.DefaultDoubleArrayField, capacity), // array_length 1210 } 1211 1212 // search with jsonField expr key datatype and json data type mismatch 1213 sp, _ := entity.NewIndexHNSWSearchParam(74) 1214 for _, expr := range exprs { 1215 log.Printf("search expr: %s", expr) 1216 searchRes, errSearchEmpty := mc.Search( 1217 ctx, collName, []string{}, 1218 expr, common.AllArrayFieldsName, 1219 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1220 common.DefaultFloatVecFieldName, entity.L2, 1221 common.DefaultTopK, sp, 1222 ) 1223 common.CheckErr(t, errSearchEmpty, true) 1224 common.CheckOutputFields(t, searchRes[0].Fields, common.AllArrayFieldsName) 1225 common.CheckSearchResult(t, searchRes, common.DefaultNq, common.DefaultTopK) 1226 } 1227 1228 // search hits empty 1229 searchRes, errSearchEmpty := mc.Search( 1230 ctx, collName, []string{}, 1231 fmt.Sprintf("array_contains (%s, 1000000)", common.DefaultInt32ArrayField), 1232 common.AllArrayFieldsName, 1233 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1234 common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, 1235 sp, 1236 ) 1237 common.CheckErr(t, errSearchEmpty, true) 1238 require.Len(t, searchRes, common.DefaultNq) 1239 for _, resultSet := range searchRes { 1240 assert.EqualValues(t, 0, resultSet.ResultCount) 1241 } 1242 } 1243 } 1244 1245 // search with index scann search param ef < topK -> error 1246 func TestSearchInvalidScannReorderK(t *testing.T) { 1247 ctx := createContext(t, time.Second*common.DefaultTimeout) 1248 // connect 1249 mc := createMilvusClient(ctx, t) 1250 1251 // create collection 1252 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 1253 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1254 collName := createCollection(ctx, t, mc, cp) 1255 1256 // insert 1257 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1258 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 1259 _, _ = insertData(ctx, t, mc, dp) 1260 1261 // flush 1262 mc.Flush(ctx, collName, false) 1263 1264 // create scann index 1265 indexScann, _ := entity.NewIndexSCANN(entity.L2, 16, false) 1266 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, indexScann, false) 1267 common.CheckErr(t, err, true) 1268 1269 // describe index 1270 indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName) 1271 log.Println(indexes) 1272 expIndex := entity.NewGenericIndex(common.DefaultFloatVecFieldName, entity.SCANN, indexScann.Params()) 1273 common.CheckIndexResult(t, indexes, expIndex) 1274 1275 // load collection 1276 errLoad := mc.LoadCollection(ctx, collName, false) 1277 common.CheckErr(t, errLoad, true) 1278 1279 // search with invalid reorder_k < topk 1280 queryVec := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector) 1281 spInvalid, _ := entity.NewIndexSCANNSearchParam(8, common.DefaultTopK-1) 1282 _, errInvalid := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName}, queryVec, 1283 common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, spInvalid) 1284 common.CheckErr(t, errInvalid, false, 1285 fmt.Sprintf("reorder_k(%d) should be larger than k(%d)", common.DefaultTopK-1, common.DefaultTopK)) 1286 1287 // valid scann index search reorder_k 1288 sp, _ := entity.NewIndexSCANNSearchParam(8, 20) 1289 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName}, queryVec, 1290 common.DefaultFloatVecFieldName, entity.L2, common.DefaultTopK, sp) 1291 common.CheckErr(t, errSearch, true) 1292 common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK) 1293 } 1294 1295 // test search with scann index params: with_raw_data and metrics_type [L2, IP, COSINE] 1296 func TestSearchScannAllMetricsWithRawData(t *testing.T) { 1297 t.Parallel() 1298 for _, withRawData := range []bool{true, false} { 1299 for _, metricType := range []entity.MetricType{entity.L2, entity.IP, entity.COSINE} { 1300 ctx := createContext(t, time.Second*common.DefaultTimeout) 1301 // connect 1302 mc := createMilvusClient(ctx, t) 1303 1304 // create collection 1305 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 1306 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1307 collName := createCollection(ctx, t, mc, cp) 1308 1309 // insert 1310 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1311 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 1312 _, _ = insertData(ctx, t, mc, dp) 1313 mc.Flush(ctx, collName, false) 1314 1315 // create scann index 1316 indexScann, _ := entity.NewIndexSCANN(metricType, 16, withRawData) 1317 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, indexScann, false) 1318 common.CheckErr(t, err, true) 1319 1320 // describe index 1321 indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName) 1322 expIndex := entity.NewGenericIndex(common.DefaultFloatVecFieldName, entity.SCANN, indexScann.Params()) 1323 common.CheckIndexResult(t, indexes, expIndex) 1324 1325 // load collection 1326 errLoad := mc.LoadCollection(ctx, collName, false) 1327 common.CheckErr(t, errLoad, true) 1328 1329 // search and output all fields 1330 sp, _ := entity.NewIndexSCANNSearchParam(8, 20) 1331 resSearch, errSearch := mc.Search( 1332 ctx, collName, 1333 []string{}, 1334 "", 1335 []string{"*"}, 1336 common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector), 1337 common.DefaultFloatVecFieldName, 1338 metricType, 1339 common.DefaultTopK, 1340 sp, 1341 ) 1342 common.CheckErr(t, errSearch, true) 1343 common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, 1344 common.DefaultJSONFieldName, common.DefaultFloatVecFieldName, common.DefaultDynamicFieldName}) 1345 common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK) 1346 } 1347 } 1348 } 1349 1350 // test range search with scann index 1351 func TestRangeSearchScannL2(t *testing.T) { 1352 ctx := createContext(t, time.Second*common.DefaultTimeout) 1353 // connect 1354 mc := createMilvusClient(ctx, t) 1355 1356 // create collection 1357 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 1358 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1359 collName := createCollection(ctx, t, mc, cp) 1360 1361 // insert 1362 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1363 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 1364 _, _ = insertData(ctx, t, mc, dp) 1365 1366 // create scann index 1367 indexScann, _ := entity.NewIndexSCANN(entity.L2, 16, false) 1368 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, indexScann, false) 1369 common.CheckErr(t, err, true) 1370 1371 // describe index 1372 indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName) 1373 expIndex := entity.NewGenericIndex(common.DefaultFloatVecFieldName, entity.SCANN, indexScann.Params()) 1374 common.CheckIndexResult(t, indexes, expIndex) 1375 1376 // load collection 1377 errLoad := mc.LoadCollection(ctx, collName, false) 1378 common.CheckErr(t, errLoad, true) 1379 1380 // search output all fields 1381 queryVec := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector) 1382 sp, _ := entity.NewIndexSCANNSearchParam(8, 20) 1383 sp.AddRadius(20) 1384 sp.AddRangeFilter(15) 1385 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultFloatVecFieldName, 1386 entity.L2, common.DefaultTopK, sp) 1387 1388 // verify error nil, output all fields, range score 1389 common.CheckErr(t, errSearch, true) 1390 common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK) 1391 common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, 1392 common.DefaultJSONFieldName, common.DefaultFloatVecFieldName, common.DefaultDynamicFieldName}) 1393 for _, s := range resSearch[0].Scores { 1394 require.GreaterOrEqual(t, s, float32(15.0)) 1395 require.Less(t, s, float32(20.0)) 1396 } 1397 1398 // invalid range search: radius < range filter 1399 sp.AddRadius(15) 1400 sp.AddRangeFilter(20) 1401 _, errRange := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultFloatVecFieldName, 1402 entity.L2, common.DefaultTopK, sp) 1403 common.CheckErr(t, errRange, false, "must be less than radius") 1404 } 1405 1406 // test range search with scann index and IP COSINE metric type 1407 func TestRangeSearchScannIPCosine(t *testing.T) { 1408 t.Skip("https://github.com/milvus-io/milvus/issues/32608") 1409 t.Parallel() 1410 for _, metricType := range []entity.MetricType{entity.IP, entity.COSINE} { 1411 ctx := createContext(t, time.Second*common.DefaultTimeout) 1412 // connect 1413 mc := createMilvusClient(ctx, t) 1414 1415 // create collection 1416 cp := CollectionParams{CollectionFieldsType: Int64FloatVecJSON, AutoID: false, EnableDynamicField: true, 1417 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1418 collName := createCollection(ctx, t, mc, cp) 1419 1420 // insert 1421 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVecJSON, 1422 start: 0, nb: common.DefaultNb * 4, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 1423 _, _ = insertData(ctx, t, mc, dp) 1424 mc.Flush(ctx, collName, false) 1425 1426 // create scann index 1427 indexScann, _ := entity.NewIndexSCANN(metricType, 16, false) 1428 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, indexScann, false) 1429 common.CheckErr(t, err, true) 1430 1431 // describe index 1432 indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName) 1433 expIndex := entity.NewGenericIndex(common.DefaultFloatVecFieldName, entity.SCANN, indexScann.Params()) 1434 common.CheckIndexResult(t, indexes, expIndex) 1435 1436 // load collection 1437 errLoad := mc.LoadCollection(ctx, collName, false) 1438 common.CheckErr(t, errLoad, true) 1439 1440 // range search filter distance and output all fields 1441 queryVec := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector) 1442 sp, _ := entity.NewIndexSCANNSearchParam(8, 20) 1443 1444 // search without range 1445 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultFloatVecFieldName, 1446 metricType, common.DefaultTopK, sp) 1447 common.CheckErr(t, errSearch, true) 1448 for _, s := range resSearch[0].Scores { 1449 log.Println(s) 1450 } 1451 1452 // range search 1453 var radius float64 1454 var rangeFilter float64 1455 if metricType == entity.COSINE { 1456 radius = 10 1457 rangeFilter = 50 1458 } 1459 if metricType == entity.IP { 1460 radius = 0.2 1461 rangeFilter = 0.8 1462 } 1463 sp.AddRadius(radius) 1464 sp.AddRangeFilter(rangeFilter) 1465 resRange, errRange := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultFloatVecFieldName, 1466 metricType, common.DefaultTopK, sp) 1467 1468 // verify error nil, output all fields, range score 1469 common.CheckErr(t, errRange, true) 1470 common.CheckSearchResult(t, resRange, 1, common.DefaultTopK) 1471 common.CheckOutputFields(t, resRange[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, 1472 common.DefaultJSONFieldName, common.DefaultFloatVecFieldName, common.DefaultDynamicFieldName}) 1473 for _, s := range resSearch[0].Scores { 1474 log.Println(s) 1475 require.GreaterOrEqual(t, s, float32(radius)) 1476 require.Less(t, s, float32(rangeFilter)) 1477 } 1478 1479 // invalid range search: radius > range filter 1480 sp.AddRadius(20) 1481 sp.AddRangeFilter(10) 1482 _, errRange = mc.Search(ctx, collName, []string{}, "", []string{""}, queryVec, common.DefaultFloatVecFieldName, 1483 metricType, common.DefaultTopK, sp) 1484 common.CheckErr(t, errRange, false, "must be greater than radius") 1485 } 1486 } 1487 1488 // test range search with scann index and entity.HAMMING, entity.JACCARD metric type 1489 func TestRangeSearchScannBinary(t *testing.T) { 1490 t.Parallel() 1491 for _, metricType := range common.SupportBinIvfFlatMetricType { 1492 ctx := createContext(t, time.Second*common.DefaultTimeout) 1493 // connect 1494 mc := createMilvusClient(ctx, t) 1495 1496 // create collection 1497 cp := CollectionParams{CollectionFieldsType: Int64BinaryVec, AutoID: false, EnableDynamicField: true, 1498 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1499 collName := createCollection(ctx, t, mc, cp) 1500 1501 // insert 1502 dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64BinaryVec, 1503 start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} 1504 _, _ = insertData(ctx, t, mc, dp) 1505 mc.Flush(ctx, collName, false) 1506 1507 // create scann index 1508 indexBin, _ := entity.NewIndexBinIvfFlat(metricType, 16) 1509 err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, indexBin, false) 1510 common.CheckErr(t, err, true) 1511 1512 // describe index 1513 indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultBinaryVecFieldName) 1514 expIndex := entity.NewGenericIndex(common.DefaultBinaryVecFieldName, entity.BinIvfFlat, indexBin.Params()) 1515 common.CheckIndexResult(t, indexes, expIndex) 1516 1517 // load collection 1518 errLoad := mc.LoadCollection(ctx, collName, false) 1519 common.CheckErr(t, errLoad, true) 1520 1521 // range search filter distance and output all fields 1522 queryVec := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeBinaryVector) 1523 sp, _ := entity.NewIndexBinIvfFlatSearchParam(8) 1524 sp.AddRadius(100) 1525 sp.AddRangeFilter(0) 1526 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultBinaryVecFieldName, 1527 metricType, common.DefaultTopK, sp) 1528 1529 // verify error nil, output all fields, range score 1530 common.CheckErr(t, errSearch, true) 1531 common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK) 1532 common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, 1533 common.DefaultBinaryVecFieldName, common.DefaultDynamicFieldName}) 1534 for _, s := range resSearch[0].Scores { 1535 require.GreaterOrEqual(t, s, float32(0)) 1536 require.Less(t, s, float32(100)) 1537 } 1538 1539 // invalid range search: radius > range filter 1540 sp.AddRadius(0) 1541 sp.AddRangeFilter(100) 1542 _, errRange := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultBinaryVecFieldName, 1543 metricType, common.DefaultTopK, sp) 1544 common.CheckErr(t, errRange, false, "range_filter(100) must be less than radius(0)") 1545 } 1546 } 1547 1548 func TestVectorOutputField(t *testing.T) { 1549 ctx := createContext(t, time.Second*common.DefaultTimeout) 1550 // connect 1551 mc := createMilvusClient(ctx, t) 1552 1553 // create collection with data 1554 collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, true) 1555 1556 // load collection 1557 errLoad := mc.LoadCollection(ctx, collName, false) 1558 common.CheckErr(t, errLoad, true) 1559 1560 // search vector 1561 for i := 0; i < 20; i++ { 1562 sp, _ := entity.NewIndexHNSWSearchParam(74) 1563 searchResult, errSearch := mc.Search( 1564 ctx, collName, 1565 []string{common.DefaultPartition}, 1566 "", 1567 []string{common.DefaultFloatVecFieldName}, 1568 //[]entity.Vector{entity.FloatVector([]float32{0.1, 0.2})}, 1569 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 1570 common.DefaultFloatVecFieldName, 1571 entity.L2, 1572 common.DefaultTopK, 1573 sp, 1574 ) 1575 common.CheckErr(t, errSearch, true) 1576 common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultFloatVecFieldName}) 1577 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 1578 log.Printf("search %d done\n", i) 1579 } 1580 } 1581 1582 // test search with fp16/ bf16 /binary vector 1583 func TestSearchMultiVectors(t *testing.T) { 1584 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1585 // connect 1586 mc := createMilvusClient(ctx, t) 1587 1588 // create -> insert [0, 3000) -> flush -> index -> load 1589 cp := CollectionParams{CollectionFieldsType: AllVectors, AutoID: false, EnableDynamicField: true, 1590 ShardsNum: common.DefaultShards, Dim: common.DefaultDim} 1591 1592 dp := DataParams{DoInsert: true, CollectionFieldsType: AllVectors, start: 0, nb: common.DefaultNb * 2, 1593 dim: common.DefaultDim, EnableDynamicField: true} 1594 1595 // index params 1596 ips := make([]IndexParams, 4) 1597 var idx entity.Index 1598 for _, fieldName := range common.AllVectorsFieldsName { 1599 if fieldName == common.DefaultBinaryVecFieldName { 1600 idx, _ = entity.NewIndexBinFlat(entity.JACCARD, 64) 1601 } else { 1602 idx, _ = entity.NewIndexFlat(entity.L2) 1603 } 1604 ips = append(ips, IndexParams{BuildIndex: true, Index: idx, FieldName: fieldName, async: false}) 1605 } 1606 1607 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1608 1609 // search with all kinds of vectors 1610 type mFieldNameType struct { 1611 fieldName string 1612 fieldType entity.FieldType 1613 metricType entity.MetricType 1614 } 1615 fnts := []mFieldNameType{ 1616 {fieldName: common.DefaultFloatVecFieldName, fieldType: entity.FieldTypeFloatVector, metricType: entity.L2}, 1617 {fieldName: common.DefaultBinaryVecFieldName, fieldType: entity.FieldTypeBinaryVector, metricType: entity.JACCARD}, 1618 {fieldName: common.DefaultFloat16VecFieldName, fieldType: entity.FieldTypeFloat16Vector, metricType: entity.L2}, 1619 {fieldName: common.DefaultBFloat16VecFieldName, fieldType: entity.FieldTypeBFloat16Vector, metricType: entity.L2}, 1620 } 1621 1622 //sp, _ := entity.NewIndexHNSWSearchParam(20) 1623 sp, _ := entity.NewIndexFlatSearchParam() 1624 for _, fnt := range fnts { 1625 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, fnt.fieldType) 1626 1627 // search 1628 resSearch, errSearch := mc.Search(ctx, collName, []string{}, fmt.Sprintf("%s > 10", common.DefaultIntFieldName), 1629 []string{"*"}, queryVec, fnt.fieldName, fnt.metricType, common.DefaultTopK*2, sp) 1630 common.CheckErr(t, errSearch, true) 1631 common.CheckSearchResult(t, resSearch, common.DefaultNq, common.DefaultTopK*2) 1632 common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatVecFieldName, 1633 common.DefaultBinaryVecFieldName, common.DefaultFloat16VecFieldName, common.DefaultBFloat16VecFieldName, common.DefaultDynamicFieldName}) 1634 1635 //pagination search 1636 resPage, errPage := mc.Search(ctx, collName, []string{}, fmt.Sprintf("%s > 10", common.DefaultIntFieldName), 1637 []string{"*"}, queryVec, fnt.fieldName, fnt.metricType, common.DefaultTopK, sp, client.WithOffset(10)) 1638 common.CheckErr(t, errPage, true) 1639 common.CheckSearchResult(t, resPage, common.DefaultNq, common.DefaultTopK) 1640 for i := 0; i < common.DefaultNq; i++ { 1641 require.Equal(t, resSearch[i].IDs.(*entity.ColumnInt64).Data()[10:], resPage[i].IDs.(*entity.ColumnInt64).Data()) 1642 } 1643 common.CheckOutputFields(t, resPage[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatVecFieldName, 1644 common.DefaultBinaryVecFieldName, common.DefaultFloat16VecFieldName, common.DefaultBFloat16VecFieldName, common.DefaultDynamicFieldName}) 1645 1646 // range search 1647 sp.AddRadius(50.2) 1648 sp.AddRangeFilter(0) 1649 resRange, errRange := mc.Search(ctx, collName, []string{}, fmt.Sprintf("%s > 10", common.DefaultIntFieldName), 1650 []string{"*"}, queryVec, fnt.fieldName, fnt.metricType, common.DefaultTopK, sp, client.WithOffset(10)) 1651 common.CheckErr(t, errRange, true) 1652 common.CheckSearchResult(t, resRange, common.DefaultNq, common.DefaultTopK) 1653 common.CheckOutputFields(t, resRange[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatVecFieldName, 1654 common.DefaultBinaryVecFieldName, common.DefaultFloat16VecFieldName, common.DefaultBFloat16VecFieldName, common.DefaultDynamicFieldName}) 1655 for _, res := range resRange { 1656 for _, score := range res.Scores { 1657 require.GreaterOrEqual(t, score, float32(0)) 1658 require.LessOrEqual(t, score, float32(50.2)) 1659 } 1660 } 1661 // TODO iterator search 1662 } 1663 } 1664 1665 func TestSearchSparseVector(t *testing.T) { 1666 t.Parallel() 1667 idxInverted := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_INVERTED_INDEX", map[string]string{"drop_ratio_build": "0.2", "metric_type": "IP"}) 1668 idxWand := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_WAND", map[string]string{"drop_ratio_build": "0.3", "metric_type": "IP"}) 1669 for _, idx := range []entity.Index{idxInverted, idxWand} { 1670 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1671 // connect 1672 mc := createMilvusClient(ctx, t) 1673 1674 // create -> insert [0, 3000) -> flush -> index -> load 1675 cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true, 1676 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 1677 1678 dp := DataParams{DoInsert: true, CollectionFieldsType: Int64VarcharSparseVec, start: 0, nb: common.DefaultNb * 4, 1679 dim: common.DefaultDim, EnableDynamicField: true} 1680 1681 // index params 1682 idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1683 ips := []IndexParams{ 1684 {BuildIndex: true, Index: idx, FieldName: common.DefaultSparseVecFieldName, async: false}, 1685 {BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false}, 1686 } 1687 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1688 1689 // search 1690 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeSparseVector) 1691 sp, _ := entity.NewIndexSparseInvertedSearchParam(0.2) 1692 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1693 entity.IP, common.DefaultTopK, sp) 1694 common.CheckErr(t, errSearch, true) 1695 require.Len(t, resSearch, common.DefaultNq) 1696 outputFields := []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName, common.DefaultFloatVecFieldName, 1697 common.DefaultSparseVecFieldName, common.DefaultDynamicFieldName} 1698 for _, res := range resSearch { 1699 require.LessOrEqual(t, res.ResultCount, common.DefaultTopK) 1700 if res.ResultCount == common.DefaultTopK { 1701 common.CheckOutputFields(t, resSearch[0].Fields, outputFields) 1702 } 1703 } 1704 } 1705 } 1706 1707 // test search with invalid sparse vector 1708 func TestSearchInvalidSparseVector(t *testing.T) { 1709 t.Skip("https://github.com/milvus-io/milvus/issues/32368") 1710 t.Parallel() 1711 idxInverted := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_INVERTED_INDEX", map[string]string{"drop_ratio_build": "0.2", "metric_type": "IP"}) 1712 idxWand := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_WAND", map[string]string{"drop_ratio_build": "0.3", "metric_type": "IP"}) 1713 for _, idx := range []entity.Index{idxInverted, idxWand} { 1714 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1715 // connect 1716 mc := createMilvusClient(ctx, t) 1717 1718 // create -> insert [0, 3000) -> flush -> index -> load 1719 cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true, 1720 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 1721 1722 dp := DataParams{DoInsert: true, CollectionFieldsType: Int64VarcharSparseVec, start: 0, nb: common.DefaultNb, 1723 dim: common.DefaultDim, EnableDynamicField: true} 1724 1725 // index params 1726 idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1727 ips := []IndexParams{ 1728 {BuildIndex: true, Index: idx, FieldName: common.DefaultSparseVecFieldName, async: false}, 1729 {BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false}, 1730 } 1731 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1732 sp, _ := entity.NewIndexSparseInvertedSearchParam(0) 1733 1734 _, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, []entity.Vector{}, common.DefaultSparseVecFieldName, 1735 entity.IP, common.DefaultTopK, sp) 1736 common.CheckErr(t, errSearch, false, "nq (number of search vector per search request) should be in range [1, 16384]") 1737 1738 vector1, err := entity.NewSliceSparseEmbedding([]uint32{}, []float32{}) 1739 common.CheckErr(t, err, true) 1740 searchRes, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, []entity.Vector{vector1}, common.DefaultSparseVecFieldName, 1741 entity.IP, common.DefaultTopK, sp) 1742 common.CheckErr(t, errSearch, true) 1743 common.CheckSearchResult(t, searchRes, 1, 0) 1744 1745 positions := make([]uint32, 100) 1746 values := make([]float32, 100) 1747 for i := 0; i < 100; i++ { 1748 positions[i] = uint32(1) 1749 values[i] = rand.Float32() 1750 } 1751 vector, _ := entity.NewSliceSparseEmbedding(positions, values) 1752 _, errSearch1 := mc.Search(ctx, collName, []string{}, "", []string{"*"}, []entity.Vector{vector}, common.DefaultSparseVecFieldName, 1753 entity.IP, common.DefaultTopK, sp) 1754 common.CheckErr(t, errSearch1, false, "unsorted or same indices in sparse float vector") 1755 } 1756 } 1757 1758 func TestSearchEmptySparseCollection(t *testing.T) { 1759 t.Parallel() 1760 idxInverted := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_INVERTED_INDEX", map[string]string{"drop_ratio_build": "0.2", "metric_type": "IP"}) 1761 for _, idx := range []entity.Index{idxInverted} { 1762 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1763 // connect 1764 mc := createMilvusClient(ctx, t) 1765 1766 // create -> insert [0, 3000) -> flush -> index -> load 1767 cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true, 1768 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 1769 1770 dp := DataParams{DoInsert: false} 1771 1772 // index params 1773 idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1774 ips := []IndexParams{ 1775 {BuildIndex: true, Index: idx, FieldName: common.DefaultSparseVecFieldName, async: false}, 1776 {BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false}, 1777 } 1778 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1779 1780 // search 1781 sp, _ := entity.NewIndexSparseInvertedSearchParam(0) 1782 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeSparseVector) 1783 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1784 entity.IP, common.DefaultTopK, sp) 1785 common.CheckErr(t, errSearch, true) 1786 common.CheckSearchResult(t, resSearch, common.DefaultNq, 0) 1787 } 1788 } 1789 1790 func TestSearchSparseVectorPagination(t *testing.T) { 1791 t.Parallel() 1792 idxInverted, _ := entity.NewIndexSparseInverted(entity.IP, 0.2) 1793 idxWand, _ := entity.NewIndexSparseWAND(entity.IP, 0.2) 1794 for _, idx := range []entity.Index{idxInverted, idxWand} { 1795 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1796 // connect 1797 mc := createMilvusClient(ctx, t) 1798 1799 // create -> insert [0, 3000) -> flush -> index -> load 1800 cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true, 1801 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 1802 1803 dp := DataParams{DoInsert: true, CollectionFieldsType: Int64VarcharSparseVec, start: 0, nb: common.DefaultNb * 4, 1804 dim: common.DefaultDim, EnableDynamicField: true} 1805 1806 // index params 1807 idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1808 ips := []IndexParams{ 1809 {BuildIndex: true, Index: idx, FieldName: common.DefaultSparseVecFieldName, async: false}, 1810 {BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false}, 1811 } 1812 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1813 1814 // search 1815 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeSparseVector) 1816 sp, _ := entity.NewIndexSparseInvertedSearchParam(0.2) 1817 resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1818 entity.IP, common.DefaultTopK, sp) 1819 common.CheckErr(t, errSearch, true) 1820 require.Len(t, resSearch, common.DefaultNq) 1821 1822 pageSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1823 entity.IP, 5, sp, client.WithOffset(5)) 1824 common.CheckErr(t, errSearch, true) 1825 require.Len(t, pageSearch, common.DefaultNq) 1826 for i := 0; i < len(resSearch); i++ { 1827 if resSearch[i].ResultCount == common.DefaultTopK && pageSearch[i].ResultCount == 5 { 1828 require.Equal(t, resSearch[i].IDs.(*entity.ColumnInt64).Data()[5:], pageSearch[i].IDs.(*entity.ColumnInt64).Data()) 1829 } 1830 } 1831 } 1832 } 1833 1834 // test sparse vector unsupported search: TODO iterator search 1835 func TestSearchSparseVectorNotSupported(t *testing.T) { 1836 t.Skip("Go-sdk support iterator search in progress") 1837 } 1838 1839 func TestRangeSearchSparseVector(t *testing.T) { 1840 ctx := createContext(t, time.Second*common.DefaultTimeout*2) 1841 // connect 1842 mc := createMilvusClient(ctx, t) 1843 1844 // create -> insert [0, 3000) -> flush -> index -> load 1845 cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true, 1846 ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen} 1847 1848 dp := DataParams{DoInsert: true, CollectionFieldsType: Int64VarcharSparseVec, start: 0, nb: common.DefaultNb * 4, 1849 dim: common.DefaultDim, EnableDynamicField: true} 1850 1851 // index params 1852 idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 1853 idxWand := entity.NewGenericIndex(common.DefaultSparseVecFieldName, "SPARSE_WAND", map[string]string{"drop_ratio_build": "0.1", "metric_type": "IP"}) 1854 ips := []IndexParams{ 1855 {BuildIndex: true, Index: idxWand, FieldName: common.DefaultSparseVecFieldName, async: false}, 1856 {BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false}, 1857 } 1858 collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong))) 1859 1860 // range search 1861 queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeSparseVector) 1862 sp, _ := entity.NewIndexSparseInvertedSearchParam(0.3) 1863 1864 // without range 1865 resRange, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1866 entity.IP, common.DefaultTopK, sp) 1867 common.CheckErr(t, errSearch, true) 1868 require.Len(t, resRange, common.DefaultNq) 1869 for _, res := range resRange { 1870 log.Println(res.Scores) 1871 } 1872 1873 sp.AddRadius(0) 1874 sp.AddRangeFilter(0.8) 1875 resRange, errSearch = mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, common.DefaultSparseVecFieldName, 1876 entity.IP, common.DefaultTopK, sp) 1877 common.CheckErr(t, errSearch, true) 1878 require.Len(t, resRange, common.DefaultNq) 1879 for _, res := range resRange { 1880 for _, s := range res.Scores { 1881 require.GreaterOrEqual(t, s, float32(0)) 1882 require.Less(t, s, float32(0.8)) 1883 } 1884 } 1885 } 1886 1887 // TODO offset and limit 1888 // TODO consistency level 1889 // TODO WithGuaranteeTimestamp 1890 // TODO ignore growing