github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/test/testcases/partition_key_test.go (about) 1 //go:build L0 2 3 package testcases 4 5 import ( 6 "fmt" 7 "math/rand" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/milvus-io/milvus-sdk-go/v2/client" 15 "github.com/milvus-io/milvus-sdk-go/v2/entity" 16 17 "github.com/milvus-io/milvus-sdk-go/v2/test/common" 18 ) 19 20 // test enable partition key with int64 field 21 func TestPartitionKeyDefaultInt64(t *testing.T) { 22 ctx := createContext(t, time.Second*common.DefaultTimeout) 23 mc := createMilvusClient(ctx, t) 24 25 // fields 26 partitionKeyFieldName := "partitionKeyField" 27 partitionKeyField := common.GenField(partitionKeyFieldName, entity.FieldTypeInt64, 28 common.WithIsPartitionKey(true), common.WithMaxLength(common.MaxLength)) 29 30 // schema 31 schema := common.GenSchema(common.GenRandomString(6), false, common.GenDefaultFields(false)) 32 schema.WithField(partitionKeyField) 33 34 // create collection and check partition key 35 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(10)) 36 common.CheckErr(t, err, true) 37 38 // insert data 39 partitionKeyColumn := common.GenColumnData(0, common.DefaultNb, entity.FieldTypeInt64, partitionKeyFieldName) 40 pkColumn, floatColumn, vecColumn := common.GenDefaultColumnData(0, common.DefaultNb, common.DefaultDim) 41 ids, errInsert := mc.Insert(ctx, schema.CollectionName, "", pkColumn, floatColumn, vecColumn, partitionKeyColumn) 42 common.CheckErr(t, errInsert, true) 43 require.Equalf(t, common.DefaultNb, ids.Len(), fmt.Sprintf("Expected insert result equal to %d, actual %d", common.DefaultNb, ids.Len())) 44 45 // flush and create index and load collection 46 mc.Flush(ctx, schema.CollectionName, true) 47 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 48 mc.CreateIndex(ctx, schema.CollectionName, common.DefaultFloatVecFieldName, idx, false) 49 mc.LoadCollection(ctx, schema.CollectionName, false) 50 51 // query filter partition key field and other field 52 queryIds := []entity.Column{ 53 common.GenColumnData(0, 10, entity.FieldTypeInt64, partitionKeyFieldName), 54 common.GenColumnData(0, 10, entity.FieldTypeInt64, common.DefaultIntFieldName), 55 } 56 for _, queryID := range queryIds { 57 queryResult, errQuery := mc.QueryByPks(ctx, schema.CollectionName, []string{}, 58 queryID, 59 []string{common.DefaultIntFieldName}, 60 ) 61 common.CheckErr(t, errQuery, true) 62 common.CheckQueryResult(t, queryResult, []entity.Column{common.GenColumnData(0, 10, entity.FieldTypeInt64, common.DefaultIntFieldName)}) 63 } 64 65 // search vector with expr: in, ==, >, non-partition-key field 66 sp, _ := entity.NewIndexHNSWSearchParam(64) 67 exprs := []string{ 68 fmt.Sprintf("%s < 1000", partitionKeyFieldName), 69 fmt.Sprintf("%s == 1000", partitionKeyFieldName), 70 fmt.Sprintf("%s in [99, 199, 299, 399, 499, 599, 699, 799, 899, 999, 300, 789, 525, 22]", partitionKeyFieldName), 71 fmt.Sprintf("%s < 1000.0 && %s > 5", common.DefaultFloatFieldName, partitionKeyFieldName), 72 } 73 for _, expr := range exprs { 74 // expr filter 75 searchResult, errSearch := mc.Search( 76 ctx, schema.CollectionName, 77 []string{}, 78 expr, 79 []string{common.DefaultIntFieldName}, 80 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 81 common.DefaultFloatVecFieldName, 82 entity.L2, 83 common.DefaultTopK, 84 sp, 85 ) 86 common.CheckErr(t, errSearch, true) 87 if strings.Contains(expr, "==") { 88 common.CheckSearchResult(t, searchResult, common.DefaultNq, 1) 89 } else { 90 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 91 } 92 for _, res := range searchResult { 93 for _, id := range res.IDs.(*entity.ColumnInt64).Data() { 94 require.LessOrEqualf(t, id, int64(1000), "The id search returned is expected to <= 1000") 95 } 96 } 97 } 98 } 99 100 // test enable partition key with varchar field 101 func TestPartitionKeyDefaultVarchar(t *testing.T) { 102 ctx := createContext(t, time.Second*common.DefaultTimeout) 103 mc := createMilvusClient(ctx, t) 104 105 // fields 106 partitionKeyFieldName := "partitionKeyField" 107 partitionKeyField := common.GenField(partitionKeyFieldName, entity.FieldTypeVarChar, 108 common.WithIsPartitionKey(true), common.WithMaxLength(common.MaxLength)) 109 110 // schema 111 schema := common.GenSchema(common.GenRandomString(6), false, common.GenDefaultFields(false)) 112 schema.WithField(partitionKeyField) 113 114 // create collection and check partition key 115 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(10)) 116 common.CheckErr(t, err, true) 117 118 // insert data 119 partitionKeyColumn := common.GenColumnData(0, common.DefaultNb, entity.FieldTypeVarChar, partitionKeyFieldName) 120 pkColumn, floatColumn, vecColumn := common.GenDefaultColumnData(0, common.DefaultNb, common.DefaultDim) 121 ids, errInsert := mc.Insert(ctx, schema.CollectionName, "", pkColumn, floatColumn, vecColumn, partitionKeyColumn) 122 common.CheckErr(t, errInsert, true) 123 require.Equalf(t, common.DefaultNb, ids.Len(), fmt.Sprintf("Expected insert result equal to %d, actual %d", common.DefaultNb, ids.Len())) 124 125 // flush and create index and load collection 126 mc.Flush(ctx, schema.CollectionName, true) 127 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 128 mc.CreateIndex(ctx, schema.CollectionName, common.DefaultFloatVecFieldName, idx, false) 129 mc.LoadCollection(ctx, schema.CollectionName, false) 130 131 // query filter partition key field and other field 132 queryIds := []entity.Column{ 133 common.GenColumnData(0, 10, entity.FieldTypeVarChar, partitionKeyFieldName), 134 common.GenColumnData(0, 10, entity.FieldTypeInt64, common.DefaultIntFieldName), 135 } 136 for _, queryID := range queryIds { 137 queryResult, errQuery := mc.QueryByPks(ctx, schema.CollectionName, []string{}, 138 queryID, 139 []string{common.DefaultIntFieldName}, 140 ) 141 common.CheckErr(t, errQuery, true) 142 common.CheckQueryResult(t, queryResult, []entity.Column{common.GenColumnData(0, 10, entity.FieldTypeInt64, common.DefaultIntFieldName)}) 143 } 144 145 // search vector with expr: in, ==, >, non-partition-key field 146 sp, _ := entity.NewIndexHNSWSearchParam(64) 147 exprs := []string{ 148 fmt.Sprintf("%s < '9'", partitionKeyFieldName), 149 fmt.Sprintf("%s == '1000'", partitionKeyFieldName), 150 fmt.Sprintf("%s in ['99', '199', '299', '399', '499', '599', '699', '799', '899', '999', '300', '789', '525', '22']", partitionKeyFieldName), 151 fmt.Sprintf("%s < 1000.0 && %s > '5'", common.DefaultFloatFieldName, partitionKeyFieldName), 152 } 153 for _, expr := range exprs { 154 // expr filter 155 searchResult, errSearch := mc.Search( 156 ctx, schema.CollectionName, 157 []string{}, 158 expr, 159 []string{common.DefaultIntFieldName}, 160 common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector), 161 common.DefaultFloatVecFieldName, 162 entity.L2, 163 common.DefaultTopK, 164 sp, 165 ) 166 common.CheckErr(t, errSearch, true) 167 if strings.Contains(expr, "==") { 168 common.CheckSearchResult(t, searchResult, common.DefaultNq, 1) 169 } else { 170 common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) 171 } 172 } 173 } 174 175 func TestPartitionKeyInvalidNumPartition(t *testing.T) { 176 ctx := createContext(t, time.Second*common.DefaultTimeout) 177 mc := createMilvusClient(ctx, t) 178 179 // prepare field and schema 180 partitionKeyFieldName := "partitionKeyField" 181 partitionKeyField := common.GenField(partitionKeyFieldName, entity.FieldTypeInt64, common.WithIsPartitionKey(true)) 182 183 // schema 184 collName := common.GenRandomString(6) 185 schema := common.GenSchema(collName, false, common.GenDefaultFields(false)) 186 schema.WithField(partitionKeyField) 187 188 invalidNumPartitionStruct := []struct { 189 numPartitions int64 190 errMsg string 191 }{ 192 {common.MaxPartitionNum + 1, "exceeds max configuration (4096)"}, 193 {-1, "the specified partitions should be greater than 0 if partition key is used"}, 194 } 195 for _, npStruct := range invalidNumPartitionStruct { 196 197 // create collection and check partition key 198 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(npStruct.numPartitions)) 199 common.CheckErr(t, err, false, npStruct.errMsg) 200 } 201 202 // PartitionNum is 0, actually default 64 partitions 203 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(0)) 204 common.CheckErr(t, err, true) 205 partitions, _ := mc.ShowPartitions(ctx, collName) 206 require.Equal(t, len(partitions), common.DefaultPartitionNum) 207 } 208 209 func TestPartitionKeyNumPartition(t *testing.T) { 210 // test set num partition range [1, 4096] 211 // set num partition 212 t.Parallel() 213 214 numPartitionsValues := []int64{ 215 1, 216 128, 217 64, 218 4096, 219 } 220 for _, numPartitionsValue := range numPartitionsValues { 221 ctx := createContext(t, time.Second*common.DefaultTimeout) 222 mc := createMilvusClient(ctx, t) 223 224 // prepare field and schema 225 partitionKeyFieldName := "partitionKeyField" 226 partitionKeyField := common.GenField(partitionKeyFieldName, entity.FieldTypeInt64, common.WithIsPartitionKey(true)) 227 228 // schema 229 collName := common.GenRandomString(6) 230 schema := common.GenSchema(collName, false, common.GenDefaultFields(false)) 231 schema.WithField(partitionKeyField) 232 233 // create collection and check partition key 234 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(numPartitionsValue)) 235 common.CheckErr(t, err, true) 236 237 // insert and query search 238 collections, _ := mc.ListCollections(ctx) 239 common.CheckContainsCollection(t, collections, collName) 240 } 241 242 } 243 244 // test partition key on invalid field 245 func TestPartitionKeyNotSupportFieldType(t *testing.T) { 246 t.Parallel() 247 // current only support int64 and varchar field 248 ctx := createContext(t, time.Second*common.DefaultTimeout) 249 mc := createMilvusClient(ctx, t) 250 251 notSupportPartitionKeyFieldType := []entity.FieldType{ 252 entity.FieldTypeBool, 253 entity.FieldTypeInt8, 254 entity.FieldTypeInt16, 255 entity.FieldTypeInt32, 256 entity.FieldTypeFloat, 257 entity.FieldTypeDouble, 258 entity.FieldTypeJSON, 259 entity.FieldTypeBinaryVector, 260 entity.FieldTypeFloatVector, 261 } 262 263 for _, pkf := range notSupportPartitionKeyFieldType { 264 // prepare field and schema 265 partitionKeyFieldName := "partitionKeyField" 266 partitionKeyField := common.GenField(partitionKeyFieldName, pkf, common.WithIsPartitionKey(true)) 267 268 // schema 269 collName := common.GenRandomString(6) 270 schema := common.GenSchema(collName, false, common.GenDefaultFields(false)) 271 schema.WithField(partitionKeyField) 272 273 // create collection and check partition key 274 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(10)) 275 common.CheckErr(t, err, false, "the data type of partition key should be Int64 or VarChar") 276 } 277 } 278 279 // test multi partition key fields -> error 280 func TestPartitionKeyMultiFields(t *testing.T) { 281 ctx := createContext(t, time.Second*common.DefaultTimeout) 282 mc := createMilvusClient(ctx, t) 283 284 // multi partition key field 285 partitionKeyField1 := common.GenField("intPartitionKeyField", entity.FieldTypeInt64, common.WithIsPartitionKey(true)) 286 partitionKeyField2 := common.GenField("varcharPartitionKeyField", entity.FieldTypeInt64, common.WithIsPartitionKey(true)) 287 288 // schema 289 collName := common.GenRandomString(6) 290 schema := common.GenSchema(collName, false, common.GenDefaultFields(false)) 291 schema.WithField(partitionKeyField1).WithField(partitionKeyField2) 292 293 // create collection and check partition key 294 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(10)) 295 common.CheckErr(t, err, false, "there are more than one partition key") 296 } 297 298 func TestPartitionNumWhenDisablePartitionKey(t *testing.T) { 299 ctx := createContext(t, time.Second*common.DefaultTimeout) 300 mc := createMilvusClient(ctx, t) 301 302 // schema 303 collName := common.GenRandomString(6) 304 schema := common.GenSchema(collName, false, common.GenDefaultFields(false)) 305 306 // create collection and check partition key 307 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(10)) 308 common.CheckErr(t, err, false, "num_partitions should only be specified with partition key field enabled") 309 } 310 311 // test operate partition related after enable partition key -> error expect has partition 312 func TestPartitionKeyPartitionOperation(t *testing.T) { 313 ctx := createContext(t, time.Second*common.DefaultTimeout) 314 mc := createMilvusClient(ctx, t) 315 316 // multi partition key field 317 partitionKeyField := common.GenField("partitionKeyField", entity.FieldTypeInt64, common.WithIsPartitionKey(true)) 318 319 // schema 320 collName := common.GenRandomString(6) 321 schema := common.GenSchema(collName, true, common.GenDefaultFields(true)) 322 schema.WithField(partitionKeyField) 323 324 // create collection and check partition key 325 partitionNum := 10 326 err := mc.CreateCollection(ctx, schema, common.DefaultShards, client.WithPartitionNum(int64(partitionNum))) 327 common.CheckErr(t, err, true) 328 329 // list partitions -> success 330 partitions, err := mc.ShowPartitions(ctx, collName) 331 common.CheckErr(t, err, true) 332 require.Lenf(t, partitions, partitionNum, fmt.Sprintf("Expected collection has %d partitions, actually %d.", partitionNum, len(partitions))) 333 334 // has partition -> success 335 has, err := mc.HasPartition(ctx, collName, partitions[0].Name) 336 require.True(t, has) 337 common.CheckErr(t, err, true) 338 339 // create partition -> error 340 err = mc.CreatePartition(ctx, collName, common.GenRandomString(4)) 341 common.CheckErr(t, err, false, "disable create partition if partition key mode is used") 342 343 // drop partition -> error 344 err = mc.DropPartition(ctx, collName, partitions[2].Name) 345 common.CheckErr(t, err, false, "disable drop partition if partition key mode is used") 346 347 // load partition -> error 348 err = mc.LoadPartitions(ctx, collName, []string{partitions[0].Name}, true) 349 common.CheckErr(t, err, false, "disable load partitions if partition key mode is used") 350 351 // release partition -> error 352 err = mc.ReleasePartitions(ctx, collName, []string{partitions[0].Name}) 353 common.CheckErr(t, err, false, "disable release partitions if partition key mode is used") 354 355 // insert into partition -> error 356 partitionKeyColumn := common.GenColumnData(0, common.DefaultNb, entity.FieldTypeInt64, partitionKeyField.Name) 357 _, floatColumn, vecColumn := common.GenDefaultColumnData(0, common.DefaultNb, common.DefaultDim) 358 _, err = mc.Insert(ctx, schema.CollectionName, partitions[0].Name, floatColumn, vecColumn, partitionKeyColumn) 359 common.CheckErr(t, err, false, "not support manually specifying the partition names if partition key mode is used") 360 361 // InsertRows into partition -> error 362 vector := make([]float32, 0, common.DefaultDim) 363 for j := 0; j < int(common.DefaultDim); j++ { 364 vector = append(vector, rand.Float32()) 365 } 366 row := struct { 367 Int64 int64 `json:"int64" milvus:"name:int64"` 368 Float float32 `json:"float" milvus:"name:float"` 369 FloatVec []float32 `json:"floatVec" milvus:"name:floatVec"` 370 PartitionKeyField int64 `json:"partitionKeyField" milvus:"name:partitionKeyField"` 371 }{int64(1), float32(1), vector, int64(2)} 372 _, err = mc.InsertRows(ctx, collName, partitions[0].Name, []interface{}{row}) 373 common.CheckErr(t, err, false, "not support manually specifying the partition names if partition key mode is used") 374 375 // delete from partition -> error 376 err = mc.DeleteByPks(ctx, collName, partitions[2].Name, entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0, 1})) 377 common.CheckErr(t, err, false, "not support manually specifying the partition names if partition key mode is used") 378 379 // bulk insert -> error 380 _, err = mc.BulkInsert(ctx, collName, partitions[0].Name, []string{""}) 381 common.CheckErr(t, err, false, "not allow to set partition name for collection with partition key: importing data failed") 382 383 // query partitions -> error 384 _, err = mc.QueryByPks( 385 ctx, collName, 386 []string{partitions[0].Name}, 387 entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0}), []string{}) 388 common.CheckErr(t, err, false, "not support manually specifying the partition names if partition key mode is used") 389 390 // search 391 sp, _ := entity.NewIndexHNSWSearchParam(74) 392 _, err = mc.Search( 393 ctx, collName, []string{partitions[0].Name}, "", []string{}, 394 common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector), common.DefaultFloatVecFieldName, 395 entity.L2, 1, sp) 396 common.CheckErr(t, err, false, "not support manually specifying the partition names if partition key mode is used") 397 }