github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/examples/index/index.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/csv" 6 "fmt" 7 "log" 8 "os" 9 "strconv" 10 "strings" 11 "time" 12 13 "github.com/milvus-io/milvus-sdk-go/v2/client" 14 "github.com/milvus-io/milvus-sdk-go/v2/entity" 15 ) 16 17 func main() { 18 // Milvus instance proxy address, may verify in your env/settings 19 milvusAddr := `localhost:19530` 20 21 // setup context 22 ctx, cancel := context.WithCancel(context.Background()) 23 defer cancel() 24 25 c, err := client.NewClient(ctx, client.Config{ 26 Address: milvusAddr, 27 }) 28 if err != nil { 29 // handling error and exit, to make example simple here 30 log.Fatal("failed to connect to milvus:", err.Error()) 31 } 32 // in a main func, remember to close the client 33 defer c.Close() 34 35 // here is the collection name we use in this example 36 collectionName := `gosdk_index_example` 37 38 has, err := c.HasCollection(ctx, collectionName) 39 if err != nil { 40 log.Fatal("failed to check whether collection exists:", err.Error()) 41 } 42 if has { 43 // collection with same name exist, clean up mess 44 _ = c.DropCollection(ctx, collectionName) 45 } 46 47 // define collection schema, see film.csv 48 schema := entity.NewSchema().WithName(collectionName).WithDescription("this is the example collection for indexing"). 49 WithField(entity.NewField().WithName("ID").WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)). 50 WithField(entity.NewField().WithName("Year").WithDataType(entity.FieldTypeInt32)). 51 WithField(entity.NewField().WithName("Vector").WithDataType(entity.FieldTypeFloatVector).WithDim(8)) 52 53 err = c.CreateCollection(ctx, schema, entity.DefaultShardNumber) 54 if err != nil { 55 log.Fatal("failed to create collection:", err.Error()) 56 } 57 58 films, err := loadFilmCSV() 59 if err != nil { 60 log.Fatal("failed to load film data csv:", err.Error()) 61 } 62 63 // row-base covert to column-base 64 ids := make([]int64, 0, len(films)) 65 years := make([]int32, 0, len(films)) 66 vectors := make([][]float32, 0, len(films)) 67 // string field is not supported yet 68 idTitle := make(map[int64]string) 69 for idx, film := range films { 70 ids = append(ids, film.ID) 71 idTitle[film.ID] = film.Title 72 years = append(years, film.Year) 73 vectors = append(vectors, films[idx].Vector[:]) // prevent same vector 74 } 75 idColumn := entity.NewColumnInt64("ID", ids) 76 yearColumn := entity.NewColumnInt32("Year", years) 77 vectorColumn := entity.NewColumnFloatVector("Vector", 8, vectors) 78 79 // insert into default partition 80 _, err = c.Insert(ctx, collectionName, "", idColumn, yearColumn, vectorColumn) 81 if err != nil { 82 log.Fatal("failed to insert film data:", err.Error()) 83 } 84 log.Println("insert completed") 85 ctx, cancel = context.WithTimeout(context.Background(), time.Second*120) 86 defer cancel() 87 err = c.Flush(ctx, collectionName, false) 88 if err != nil { 89 log.Fatal("failed to flush collection:", err.Error()) 90 } 91 log.Println("flush completed") 92 // Now add index 93 idx, err := entity.NewIndexIvfFlat(entity.L2, 2) 94 if err != nil { 95 log.Fatal("fail to create ivf flat index:", err.Error()) 96 } 97 err = c.CreateIndex(ctx, collectionName, "Vector", idx, false) 98 if err != nil { 99 log.Fatal("fail to create index:", err.Error()) 100 } 101 102 sidx := entity.NewScalarIndex() 103 if err := c.CreateIndex(ctx, collectionName, "Year", sidx, false); err != nil { 104 log.Fatal("failed to create scalar index", err.Error()) 105 } 106 107 // load collection with async=false 108 err = c.LoadCollection(ctx, collectionName, false) 109 if err != nil { 110 log.Fatal("failed to load collection:", err.Error()) 111 } 112 log.Println("load collection completed") 113 114 searchFilm := films[0] // use first fim to search 115 vector := entity.FloatVector(searchFilm.Vector[:]) 116 sp, _ := entity.NewIndexFlatSearchParam() 117 start := time.Now() 118 sr, err := c.Search(ctx, collectionName, []string{}, "Year > 1990", []string{"ID"}, []entity.Vector{vector}, "Vector", 119 entity.L2, 10, sp) 120 if err != nil { 121 log.Fatal("fail to search collection:", err.Error()) 122 } 123 log.Println("search without index time elapsed:", time.Since(start)) 124 for _, result := range sr { 125 var idColumn *entity.ColumnInt64 126 for _, field := range result.Fields { 127 if field.Name() == "ID" { 128 c, ok := field.(*entity.ColumnInt64) 129 if ok { 130 idColumn = c 131 } 132 } 133 } 134 if idColumn == nil { 135 log.Fatal("result field not math") 136 } 137 for i := 0; i < result.ResultCount; i++ { 138 id, err := idColumn.ValueByIdx(i) 139 if err != nil { 140 log.Fatal(err.Error()) 141 } 142 title := idTitle[id] 143 fmt.Printf("file id: %d title: %s scores: %f\n", id, title, result.Scores[i]) 144 } 145 } 146 147 // clean up 148 _ = c.DropCollection(ctx, collectionName) 149 } 150 151 type film struct { 152 ID int64 153 Title string 154 Year int32 155 Vector [8]float32 // fix length array 156 } 157 158 func loadFilmCSV() ([]film, error) { 159 f, err := os.Open("../films.csv") // assume you are in examples/insert folder, if not, please change the path 160 if err != nil { 161 return []film{}, err 162 } 163 r := csv.NewReader(f) 164 raw, err := r.ReadAll() 165 if err != nil { 166 return []film{}, err 167 } 168 films := make([]film, 0, len(raw)) 169 for _, line := range raw { 170 if len(line) < 4 { // insuffcient column 171 continue 172 } 173 fi := film{} 174 // ID 175 v, err := strconv.ParseInt(line[0], 10, 64) 176 if err != nil { 177 continue 178 } 179 fi.ID = v 180 // Title 181 fi.Title = line[1] 182 // Year 183 v, err = strconv.ParseInt(line[2], 10, 64) 184 if err != nil { 185 continue 186 } 187 fi.Year = int32(v) 188 // Vector 189 vectorStr := strings.ReplaceAll(line[3], "[", "") 190 vectorStr = strings.ReplaceAll(vectorStr, "]", "") 191 parts := strings.Split(vectorStr, ",") 192 if len(parts) != 8 { // dim must be 8 193 continue 194 } 195 for idx, part := range parts { 196 part = strings.TrimSpace(part) 197 v, err := strconv.ParseFloat(part, 32) 198 if err != nil { 199 continue 200 } 201 fi.Vector[idx] = float32(v) 202 } 203 films = append(films, fi) 204 } 205 return films, nil 206 }