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  }