github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/examples/dynamic_schema/dynamic_schema.go (about) 1 package main 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "log" 8 "math/rand" 9 "time" 10 11 "github.com/milvus-io/milvus-sdk-go/v2/client" 12 "github.com/milvus-io/milvus-sdk-go/v2/entity" 13 ) 14 15 const ( 16 milvusAddr = `127.0.0.1:19530` 17 nEntities, dim = 3000, 128 18 collectionName = "dynamic_example" 19 20 msgFmt = "\n==== %s ====\n" 21 idCol, typeCol, randomCol, sourceCol, embeddingCol = "ID", "type", "random", "source", "embeddings" 22 topK = 4 23 ) 24 25 func main() { 26 flag.Parse() 27 ctx := context.Background() 28 29 fmt.Printf(msgFmt, "start connecting to Milvus") 30 c, err := client.NewGrpcClient(ctx, milvusAddr) 31 if err != nil { 32 log.Fatalf("failed to connect to milvus, err: %v", err) 33 } 34 defer c.Close() 35 36 version, err := c.GetVersion(ctx) 37 if err != nil { 38 log.Fatal("failed to get version of Milvus server", err.Error()) 39 } 40 fmt.Println("Milvus Version:", version) 41 42 // delete collection if exists 43 has, err := c.HasCollection(ctx, collectionName) 44 if err != nil { 45 log.Fatalf("failed to check collection exists, err: %v", err) 46 } 47 if has { 48 c.DropCollection(ctx, collectionName) 49 } 50 51 // create collection 52 fmt.Printf(msgFmt, "create collection `dynamic_example") 53 schema := entity.NewSchema(). 54 WithName(collectionName). 55 WithDescription("dynamic schema example collection"). 56 WithAutoID(false). 57 WithDynamicFieldEnabled(true). 58 WithField(entity.NewField().WithName(idCol).WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)). 59 WithField(entity.NewField().WithName(embeddingCol).WithDataType(entity.FieldTypeFloatVector).WithDim(dim)) 60 61 if err := c.CreateCollection(ctx, schema, entity.DefaultShardNumber); err != nil { // use default shard number 62 log.Fatalf("create collection failed, err: %v", err) 63 } 64 65 // describe collection 66 fmt.Printf(msgFmt, "describe collection `dynamic_example`") 67 coll, err := c.DescribeCollection(ctx, collectionName) 68 if err != nil { 69 log.Fatal("failed to describe collection:", err.Error()) 70 } 71 72 fmt.Printf("Collection %s\tDescription: %s\tDynamicEnabled: %t\n", coll.Schema.CollectionName, coll.Schema.CollectionName, coll.Schema.EnableDynamicField) 73 for _, field := range coll.Schema.Fields { 74 fmt.Printf("Field: %s\tDataType: %s\tIsDynamic: %t\n", field.Name, field.DataType.String(), field.IsDynamic) 75 } 76 77 // insert data 78 fmt.Printf(msgFmt, "start inserting with extra columns") 79 idList, randomList := make([]int64, 0, nEntities), make([]float64, 0, nEntities) 80 typeList := make([]int32, 0, nEntities) 81 embeddingList := make([][]float32, 0, nEntities) 82 83 rand.Seed(time.Now().UnixNano()) 84 // generate data 85 for i := 0; i < nEntities; i++ { 86 idList = append(idList, int64(i)) 87 typeList = append(typeList, int32(i%3)) 88 } 89 for i := 0; i < nEntities; i++ { 90 randomList = append(randomList, rand.Float64()) 91 } 92 for i := 0; i < nEntities; i++ { 93 vec := make([]float32, 0, dim) 94 for j := 0; j < dim; j++ { 95 vec = append(vec, rand.Float32()) 96 } 97 embeddingList = append(embeddingList, vec) 98 } 99 100 idColData := entity.NewColumnInt64(idCol, idList) 101 randomColData := entity.NewColumnDouble(randomCol, randomList) 102 typeColData := entity.NewColumnInt32(typeCol, typeList) 103 embeddingColData := entity.NewColumnFloatVector(embeddingCol, dim, embeddingList) 104 if _, err := c.Insert(ctx, collectionName, "", idColData, randomColData, typeColData, embeddingColData); err != nil { 105 log.Fatalf("failed to insert random data into `dynamic_example, err: %v", err) 106 } 107 108 if err := c.Flush(ctx, collectionName, false); err != nil { 109 log.Fatalf("failed to flush data, err: %v", err) 110 } 111 fmt.Printf(msgFmt, "start inserting with rows") 112 113 // insert by struct 114 type DynamicRow struct { 115 entity.RowBase 116 ID int64 `milvus:"name:ID;primary_key"` 117 Vector []float32 `milvus:"name:embeddings;dim:128"` 118 Source int32 `milvus:"name:source"` 119 Value float64 `milvus:"name:random"` 120 } 121 122 rows := make([]entity.Row, 0, nEntities) 123 for i := 0; i < nEntities; i++ { 124 vec := make([]float32, 0, dim) 125 for j := 0; j < dim; j++ { 126 vec = append(vec, rand.Float32()) 127 } 128 129 rows = append(rows, &DynamicRow{ 130 ID: int64(nEntities + i), 131 Vector: vec, 132 Source: 1, 133 Value: rand.Float64(), 134 }) 135 } 136 137 _, err = c.InsertByRows(ctx, collectionName, "", rows) 138 if err != nil { 139 log.Fatal("failed to insert by rows: ", err.Error()) 140 } 141 142 // insert by map[string]interface{} 143 fmt.Printf(msgFmt, "start to inserting by MapRow") 144 m := make(map[string]interface{}) 145 m["ID"] = int64(nEntities) 146 vec := make([]float32, 0, dim) 147 for j := 0; j < dim; j++ { 148 vec = append(vec, rand.Float32()) 149 } 150 m["embeddings"] = vec 151 m["source"] = int32(1) 152 m["random"] = rand.Float64() 153 154 _, err = c.InsertByRows(ctx, collectionName, "", []entity.Row{entity.MapRow(m)}) 155 if err != nil { 156 log.Fatal("failed to insert by rows: ", err.Error()) 157 } 158 159 if err := c.Flush(ctx, collectionName, false); err != nil { 160 log.Fatalf("failed to flush data, err: %v", err) 161 } 162 163 // build index 164 fmt.Printf(msgFmt, "start creating index IVF_FLAT") 165 idx, err := entity.NewIndexIvfFlat(entity.L2, 128) 166 if err != nil { 167 log.Fatalf("failed to create ivf flat index, err: %v", err) 168 } 169 if err := c.CreateIndex(ctx, collectionName, embeddingCol, idx, false); err != nil { 170 log.Fatalf("failed to create index, err: %v", err) 171 } 172 173 fmt.Printf(msgFmt, "start loading collection") 174 start := time.Now() 175 err = c.LoadCollection(ctx, collectionName, false) 176 if err != nil { 177 log.Fatalf("failed to load collection, err: %v", err) 178 } 179 180 fmt.Printf("load collection done, time elasped: %v\n", time.Since(start)) 181 fmt.Printf(msgFmt, "start searching based on vector similarity") 182 183 vec2search := []entity.Vector{ 184 entity.FloatVector(embeddingList[len(embeddingList)-2]), 185 entity.FloatVector(embeddingList[len(embeddingList)-1]), 186 } 187 begin := time.Now() 188 sp, _ := entity.NewIndexIvfFlatSearchParam(16) 189 sRet, err := c.Search(ctx, collectionName, nil, "", []string{randomCol, typeCol}, vec2search, 190 embeddingCol, entity.L2, topK, sp) 191 end := time.Now() 192 if err != nil { 193 log.Fatalf("failed to search collection, err: %v", err) 194 } 195 196 fmt.Println("results:") 197 for _, res := range sRet { 198 printResult(&res, map[string]string{randomCol: "double", typeCol: "int"}) 199 } 200 fmt.Printf("\tsearch latency: %dms\n", end.Sub(begin)/time.Millisecond) 201 202 // hybrid search 203 fmt.Printf(msgFmt, "start hybrid searching with `random > 0.9`") 204 begin = time.Now() 205 sRet2, err := c.Search(ctx, collectionName, nil, "random > 0.9", 206 []string{randomCol, typeCol}, vec2search, embeddingCol, entity.L2, topK, sp) 207 end = time.Now() 208 if err != nil { 209 log.Fatalf("failed to search collection, err: %v", err) 210 } 211 fmt.Println("results:") 212 for _, res := range sRet2 { 213 printResult(&res, map[string]string{randomCol: "double", typeCol: "int"}) 214 } 215 fmt.Printf("\tsearch latency: %dms\n", end.Sub(begin)/time.Millisecond) 216 217 // query 218 expr := "ID in [0, 1, 2]" 219 fmt.Printf(msgFmt, fmt.Sprintf("query with expr `%s`", expr)) 220 sRet3, err := c.Query(ctx, collectionName, nil, expr, []string{randomCol, typeCol}) 221 if err != nil { 222 log.Fatalf("failed to query result, err: %v", err) 223 } 224 printResultSet(sRet3, map[string]string{idCol: "int", randomCol: "double", typeCol: "int"}) 225 226 // $meta["source"] 227 expr = "source in [1] and random > 0.1" 228 fmt.Printf(msgFmt, fmt.Sprintf("query with expr `%s`", expr)) 229 sRet3, err = c.Query(ctx, collectionName, nil, expr, []string{randomCol, typeCol, sourceCol}, client.WithLimit(3)) 230 if err != nil { 231 log.Fatalf("failed to query result, err: %v", err) 232 } 233 printResultSet(sRet3, map[string]string{idCol: "int", randomCol: "double", typeCol: "int", sourceCol: "int"}) 234 235 // drop collection 236 fmt.Printf(msgFmt, "drop collection `dynamic_example`") 237 if err := c.DropCollection(ctx, collectionName); err != nil { 238 log.Fatalf("failed to drop collection, err: %v", err) 239 } 240 } 241 242 func printResultSet(sRets client.ResultSet, outputInfo map[string]string) { 243 for name, typ := range outputInfo { 244 column := sRets.GetColumn(name) 245 if column == nil { 246 fmt.Printf("column %s not found in result set\n", name) 247 continue 248 } 249 250 fmt.Printf("Result Column %s, count: %d\n", name, column.Len()) 251 switch typ { 252 case "int": 253 var data []int64 254 for i := 0; i < column.Len(); i++ { 255 line, err := column.GetAsInt64(i) 256 if err != nil { 257 fmt.Printf("failed to get column %s at index %d, err: %s\n", name, i, err.Error()) 258 } 259 data = append(data, line) 260 } 261 fmt.Println("Data:", data) 262 case "string": 263 var data []string 264 for i := 0; i < column.Len(); i++ { 265 line, err := column.GetAsString(i) 266 if err != nil { 267 fmt.Printf("failed to get column %s at index %d, err: %s\n", name, i, err.Error()) 268 } 269 data = append(data, line) 270 } 271 fmt.Println("Data:", data) 272 case "double": 273 var data []float64 274 for i := 0; i < column.Len(); i++ { 275 line, err := column.GetAsDouble(i) 276 if err != nil { 277 fmt.Printf("failed to get column %s at index %d, err: %s\n", name, i, err.Error()) 278 } 279 data = append(data, line) 280 } 281 fmt.Println("Data:", data) 282 } 283 } 284 } 285 286 func printResult(sRet *client.SearchResult, outputInfo map[string]string) { 287 printResultSet(sRet.Fields, outputInfo) 288 }