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  }