github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/examples/calcdistance/calc_distance.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"encoding/csv"
     6  	"log"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/milvus-io/milvus-sdk-go/v2/client"
    13  	"github.com/milvus-io/milvus-sdk-go/v2/entity"
    14  )
    15  
    16  func main() {
    17  	// Milvus instance proxy address, may verify in your env/settings
    18  	milvusAddr := `localhost:19530`
    19  
    20  	// setup context for client creation, use 2 seconds here
    21  	ctx := context.Background()
    22  	ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    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_insert_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.Schema{
    49  		CollectionName: collectionName,
    50  		Description:    "this is the example collection for inser and search",
    51  		AutoID:         false,
    52  		Fields: []*entity.Field{
    53  			{
    54  				Name:       "ID",
    55  				DataType:   entity.FieldTypeInt64, // int64 only for now
    56  				PrimaryKey: true,
    57  				AutoID:     false,
    58  			},
    59  			{
    60  				Name:       "Year",
    61  				DataType:   entity.FieldTypeInt32,
    62  				PrimaryKey: false,
    63  				AutoID:     false,
    64  			},
    65  			{
    66  				Name:     "Vector",
    67  				DataType: entity.FieldTypeFloatVector,
    68  				TypeParams: map[string]string{
    69  					entity.TypeParamDim: "8",
    70  				},
    71  			},
    72  		},
    73  	}
    74  
    75  	err = c.CreateCollection(ctx, schema, entity.DefaultShardNumber)
    76  	if err != nil {
    77  		log.Fatal("failed to create collection:", err.Error())
    78  	}
    79  
    80  	films, err := loadFilmCSV()
    81  	if err != nil {
    82  		log.Fatal("failed to load film data csv:", err.Error())
    83  	}
    84  
    85  	// row-base covert to column-base
    86  	ids := make([]int64, 0, len(films))
    87  	years := make([]int32, 0, len(films))
    88  	vectors := make([][]float32, 0, len(films))
    89  	// string field is not supported yet
    90  	idTitle := make(map[int64]string)
    91  	for idx, film := range films {
    92  		ids = append(ids, film.ID)
    93  		idTitle[film.ID] = film.Title
    94  		years = append(years, film.Year)
    95  		vectors = append(vectors, films[idx].Vector[:]) // prevent same vector
    96  	}
    97  	idColumn := entity.NewColumnInt64("ID", ids)
    98  	yearColumn := entity.NewColumnInt32("Year", years)
    99  	vectorColumn := entity.NewColumnFloatVector("Vector", 8, vectors)
   100  
   101  	// insert into default partition
   102  	rids, err := c.Insert(ctx, collectionName, "", idColumn, yearColumn, vectorColumn)
   103  	if err != nil {
   104  		log.Fatal("failed to insert film data:", err.Error())
   105  	}
   106  	log.Println("insert completed")
   107  	ctx, cancel = context.WithTimeout(context.Background(), time.Second*120)
   108  	defer cancel()
   109  	err = c.Flush(ctx, collectionName, false)
   110  	if err != nil {
   111  		log.Fatal("failed to flush collection:", err.Error())
   112  	}
   113  	log.Println("flush completed")
   114  
   115  	// load collection with async=false
   116  	err = c.LoadCollection(ctx, collectionName, false)
   117  	if err != nil {
   118  		log.Fatal("failed to load collection:", err.Error())
   119  	}
   120  	log.Println("load collection completed")
   121  
   122  	// searchFilm := films[0] // use first fim to search
   123  	// vector := entity.FloatVector(searchFilm.Vector[:])
   124  	// Use flat search param
   125  
   126  	r, err := c.CalcDistance(ctx, collectionName, []string{}, entity.L2, entity.NewColumnFloatVector("Vector", 8, vectors[0:2]), entity.NewColumnFloatVector("Vector", 8, vectors[3:4]))
   127  	if err != nil {
   128  		log.Fatal("failed to calc distance:", err.Error())
   129  	}
   130  	rcol, ok := r.(*entity.ColumnFloat)
   131  	if ok {
   132  		log.Println("distance", rcol.Data())
   133  	}
   134  
   135  	ridsColumn, ok := rids.(*entity.ColumnInt64)
   136  	if !ok {
   137  		log.Fatal("returned ids not int64 column")
   138  	}
   139  
   140  	r, err = c.CalcDistance(ctx, collectionName, []string{}, entity.L2, entity.NewColumnInt64("Vector", ridsColumn.Data()[0:1]), entity.NewColumnFloatVector("Vector", 8, vectors[3:4]))
   141  	if err != nil {
   142  		log.Fatal("failed to calc distance:", err.Error())
   143  	}
   144  	rcol, ok = r.(*entity.ColumnFloat)
   145  	if ok {
   146  		log.Println("distance", rcol.Data())
   147  	}
   148  
   149  	// clean up
   150  	_ = c.DropCollection(ctx, collectionName)
   151  }
   152  
   153  type film struct {
   154  	ID     int64
   155  	Title  string
   156  	Year   int32
   157  	Vector [8]float32 // fix length array
   158  }
   159  
   160  func loadFilmCSV() ([]film, error) {
   161  	f, err := os.Open("../films.csv") // assume you are in examples/insert folder, if not, please change the path
   162  	if err != nil {
   163  		return []film{}, err
   164  	}
   165  	r := csv.NewReader(f)
   166  	raw, err := r.ReadAll()
   167  	if err != nil {
   168  		return []film{}, err
   169  	}
   170  	films := make([]film, 0, len(raw))
   171  	for _, line := range raw {
   172  		if len(line) < 4 { // insuffcient column
   173  			continue
   174  		}
   175  		fi := film{}
   176  		// ID
   177  		v, err := strconv.ParseInt(line[0], 10, 64)
   178  		if err != nil {
   179  			continue
   180  		}
   181  		fi.ID = v
   182  		// Title
   183  		fi.Title = line[1]
   184  		// Year
   185  		v, err = strconv.ParseInt(line[2], 10, 64)
   186  		if err != nil {
   187  			continue
   188  		}
   189  		fi.Year = int32(v)
   190  		// Vector
   191  		vectorStr := strings.ReplaceAll(line[3], "[", "")
   192  		vectorStr = strings.ReplaceAll(vectorStr, "]", "")
   193  		parts := strings.Split(vectorStr, ",")
   194  		if len(parts) != 8 { // dim must be 8
   195  			continue
   196  		}
   197  		for idx, part := range parts {
   198  			part = strings.TrimSpace(part)
   199  			v, err := strconv.ParseFloat(part, 32)
   200  			if err != nil {
   201  				continue
   202  			}
   203  			fi.Vector[idx] = float32(v)
   204  		}
   205  		films = append(films, fi)
   206  	}
   207  	return films, nil
   208  }