github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/test/testcases/load_release_test.go (about)

     1  //go:build L0
     2  
     3  package testcases
     4  
     5  import (
     6  	"fmt"
     7  	"log"
     8  	"strconv"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/milvus-io/milvus-sdk-go/v2/client"
    13  
    14  	"github.com/milvus-io/milvus-sdk-go/v2/entity"
    15  
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"github.com/milvus-io/milvus-sdk-go/v2/test/common"
    19  )
    20  
    21  // test load collection
    22  func TestLoadCollection(t *testing.T) {
    23  	//t.Skip("Issue: https://github.com/milvus-io/milvus-sdk-go/issues/374")
    24  	ctx := createContext(t, time.Second*common.DefaultTimeout)
    25  	// connect
    26  	mc := createMilvusClient(ctx, t)
    27  
    28  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
    29  
    30  	// load two replicas
    31  	errLoad := mc.LoadCollection(ctx, collName, false)
    32  	common.CheckErr(t, errLoad, true)
    33  
    34  	// check replicas
    35  	replicas, errReplicas := mc.GetReplicas(ctx, collName)
    36  	common.CheckErr(t, errReplicas, true)
    37  	require.Len(t, replicas, 1)
    38  
    39  	// check collection loaded
    40  	collection, _ := mc.DescribeCollection(ctx, collName)
    41  	log.Println(collection.Loaded)
    42  	//require.True(t, collection.Loaded)
    43  }
    44  
    45  // test load not existed collection
    46  func TestLoadCollectionNotExist(t *testing.T) {
    47  	ctx := createContext(t, time.Second*common.DefaultTimeout)
    48  	// connect
    49  	mc := createMilvusClient(ctx, t)
    50  
    51  	// Load collection
    52  	errLoad := mc.LoadCollection(ctx, "collName", false)
    53  	common.CheckErr(t, errLoad, false, "exist")
    54  }
    55  
    56  // test load collection async
    57  func TestLoadCollectionAsync(t *testing.T) {
    58  	t.Skip("Issue: https://github.com/milvus-io/milvus-sdk-go/issues/374")
    59  	ctx := createContext(t, time.Second*common.DefaultTimeout)
    60  	// connect
    61  	mc := createMilvusClient(ctx, t)
    62  
    63  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
    64  
    65  	// load collection async
    66  	errLoad := mc.LoadCollection(ctx, collName, true)
    67  	common.CheckErr(t, errLoad, true)
    68  
    69  	for {
    70  		time.Sleep(2 * time.Second)
    71  
    72  		// describe collection
    73  		collection, errDescribe := mc.DescribeCollection(ctx, collName)
    74  		if errDescribe == nil {
    75  			if collection.Loaded {
    76  				break
    77  			}
    78  		} else {
    79  			t.FailNow()
    80  		}
    81  	}
    82  }
    83  
    84  // load collection without index
    85  func TestLoadCollectionWithoutIndex(t *testing.T) {
    86  	ctx := createContext(t, time.Second*common.DefaultTimeout)
    87  	// connect
    88  	mc := createMilvusClient(ctx, t)
    89  
    90  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, false)
    91  	errLoad := mc.LoadCollection(ctx, collName, true)
    92  	common.CheckErr(t, errLoad, false, "index not found")
    93  
    94  	// load partitions without index
    95  	errLoadPartition := mc.LoadPartitions(ctx, collName, []string{common.DefaultPartition}, true)
    96  	common.CheckErr(t, errLoadPartition, false, "index not found")
    97  }
    98  
    99  // load collection with multi partitions
   100  func TestLoadCollectionMultiPartitions(t *testing.T) {
   101  	//t.Skip("Issue: https://github.com/milvus-io/milvus-sdk-go/issues/374")
   102  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   103  	// connect
   104  	mc := createMilvusClient(ctx, t)
   105  
   106  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   107  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   108  	createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   109  
   110  	// create index
   111  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   112  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   113  
   114  	// load partition
   115  	errLoad := mc.LoadCollection(ctx, collName, false)
   116  	common.CheckErr(t, errLoad, true)
   117  
   118  	// check all partitions loaded
   119  	partitions, _ := mc.ShowPartitions(ctx, collName)
   120  	for _, partition := range partitions {
   121  		log.Println(partition.Loaded)
   122  		//require.True(t, partition.Loaded)
   123  	}
   124  
   125  	// check collection loaded
   126  	collection, _ := mc.DescribeCollection(ctx, collName)
   127  	log.Println(collection.Loaded)
   128  	//require.True(t, collection.Loaded)
   129  }
   130  
   131  // test load with empty partition name ""
   132  func TestLoadEmptyPartitionName(t *testing.T) {
   133  	//t.Skip("Issue: https://github.com/milvus-io/milvus-sdk-go/issues/373")
   134  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   135  	// connect
   136  	mc := createMilvusClient(ctx, t)
   137  
   138  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   139  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   140  	createInsertTwoPartitions(ctx, t, mc, collName, 500)
   141  
   142  	// create index
   143  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   144  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   145  
   146  	// load partition with empty partition names
   147  	errLoadEmpty := mc.LoadPartitions(ctx, collName, []string{""}, false)
   148  	common.CheckErr(t, errLoadEmpty, false, "request failed")
   149  }
   150  
   151  // test load partitions with empty slice []string{}
   152  func TestLoadEmptyPartitionSlice(t *testing.T) {
   153  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   154  	// connect
   155  	mc := createMilvusClient(ctx, t)
   156  
   157  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   158  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   159  	createInsertTwoPartitions(ctx, t, mc, collName, 500)
   160  
   161  	// create index
   162  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   163  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   164  
   165  	// load partition with empty partition names
   166  	errLoadEmpty := mc.LoadPartitions(ctx, collName, []string{}, false)
   167  	common.CheckErr(t, errLoadEmpty, false, "due to no partition specified")
   168  }
   169  
   170  // test load partitions not exist
   171  func TestLoadPartitionsNotExist(t *testing.T) {
   172  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   173  	// connect
   174  	mc := createMilvusClient(ctx, t)
   175  
   176  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   177  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   178  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, 500)
   179  
   180  	// create index
   181  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   182  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   183  
   184  	// load with not exist partition names
   185  	errLoadNotExist := mc.LoadPartitions(ctx, collName, []string{"xxx"}, false)
   186  	common.CheckErr(t, errLoadNotExist, false, fmt.Sprintf("partition xxx of collection %s does not exist", collName))
   187  
   188  	// load partition with part exist partition names
   189  	errLoadPartExist := mc.LoadPartitions(ctx, collName, []string{"xxx", partitionName}, false)
   190  	common.CheckErr(t, errLoadPartExist, false, fmt.Sprintf("partition xxx of collection %s does not exist", collName))
   191  }
   192  
   193  // test load partition
   194  func TestLoadPartitions(t *testing.T) {
   195  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   196  	// connect
   197  	mc := createMilvusClient(ctx, t)
   198  
   199  	nb := 1000
   200  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   201  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   202  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, nb)
   203  
   204  	// create index
   205  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   206  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   207  
   208  	// load partition
   209  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName}, false)
   210  	common.CheckErr(t, errLoad, true)
   211  
   212  	// check collection loaded false
   213  	collection, _ := mc.DescribeCollection(ctx, collName)
   214  	require.False(t, collection.Loaded)
   215  
   216  	partitions, _ := mc.ShowPartitions(ctx, collName)
   217  	for _, p := range partitions {
   218  		if p.Name == partitionName {
   219  			//require.True(t, p.Loaded)
   220  			log.Println(p.Loaded)
   221  		} else {
   222  			log.Println(p.Loaded)
   223  			//require.True(t, p.Loaded)
   224  		}
   225  		log.Printf("id: %d, name: %s, loaded %t", p.ID, p.Name, p.Loaded)
   226  	}
   227  
   228  	//query from nb from partition
   229  	queryIds := entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0, int64(nb)})
   230  	queryResultPartition, _ := mc.QueryByPks(ctx, collName, []string{}, queryIds, []string{common.DefaultIntFieldName})
   231  	common.CheckQueryResult(t, queryResultPartition, []entity.Column{
   232  		entity.NewColumnInt64(common.DefaultIntFieldName, []int64{int64(nb)}),
   233  	})
   234  }
   235  
   236  // test load multi partition
   237  func TestLoadMultiPartitions(t *testing.T) {
   238  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   239  	// connect
   240  	mc := createMilvusClient(ctx, t)
   241  
   242  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   243  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   244  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   245  
   246  	// create index
   247  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   248  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   249  
   250  	// load partition
   251  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName, common.DefaultPartition}, false)
   252  	common.CheckErr(t, errLoad, true)
   253  
   254  	//query nb from partition
   255  	queryIds := entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0, common.DefaultNb})
   256  	queryResultPartition, _ := mc.QueryByPks(ctx, collName, []string{}, queryIds, []string{common.DefaultIntFieldName})
   257  	common.CheckQueryResult(t, queryResultPartition, []entity.Column{
   258  		entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0, common.DefaultNb}),
   259  	})
   260  }
   261  
   262  // test load partitions repeatedly
   263  func TestLoadPartitionsRepeatedly(t *testing.T) {
   264  	ctx := createContext(t, time.Second*common.DefaultTimeout*3)
   265  	// connect
   266  	mc := createMilvusClient(ctx, t)
   267  
   268  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   269  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   270  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   271  
   272  	// create index
   273  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   274  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   275  
   276  	// load repeated partition names
   277  	errLoadRepeat := mc.LoadPartitions(ctx, collName, []string{partitionName, partitionName}, false)
   278  	common.CheckErr(t, errLoadRepeat, true)
   279  
   280  	//query from nb from partition
   281  	queryIds := entity.NewColumnInt64(common.DefaultIntFieldName, []int64{common.DefaultNb})
   282  	queryResultPartition, _ := mc.QueryByPks(ctx, collName, []string{}, queryIds, []string{common.DefaultIntFieldName})
   283  	common.CheckQueryResult(t, queryResultPartition, []entity.Column{queryIds})
   284  }
   285  
   286  // test load partitions async
   287  func TestLoadPartitionsAsync(t *testing.T) {
   288  	t.Skipf("Issue: https://github.com/milvus-io/milvus-sdk-go/issues/374")
   289  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   290  	// connect
   291  	mc := createMilvusClient(ctx, t)
   292  
   293  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   294  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   295  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   296  
   297  	// create index
   298  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   299  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   300  
   301  	// load partitions async
   302  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName}, true)
   303  	common.CheckErr(t, errLoad, true)
   304  
   305  	// check load results
   306  	for {
   307  		time.Sleep(time.Second * 5)
   308  
   309  		// check partition loaded
   310  		partitions, errShow := mc.ShowPartitions(ctx, collName)
   311  		if errShow == nil {
   312  			for _, p := range partitions {
   313  				log.Printf("id: %d, name: %s, loaded %t", p.ID, p.Name, p.Loaded)
   314  				if p.Name == partitionName && p.Loaded {
   315  					break
   316  				}
   317  			}
   318  		} else {
   319  			t.FailNow()
   320  		}
   321  	}
   322  }
   323  
   324  func TestLoadCollectionMultiVectors(t *testing.T) {
   325  	ctx := createContext(t, time.Second*common.DefaultTimeout*5)
   326  	// connect
   327  	mc := createMilvusClient(ctx, t)
   328  
   329  	// create collection
   330  	cp := CollectionParams{CollectionFieldsType: AllVectors, AutoID: false, EnableDynamicField: true,
   331  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   332  	collName := createCollection(ctx, t, mc, cp)
   333  
   334  	// insert
   335  	dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: AllVectors,
   336  		start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false}
   337  	_, _ = insertData(ctx, t, mc, dp)
   338  	mc.Flush(ctx, collName, false)
   339  
   340  	// create hnsw index on part vector field and load -> load failed
   341  	indexHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   342  	for _, field := range []string{common.DefaultFloatVecFieldName, common.DefaultFloat16VecFieldName, common.DefaultBFloat16VecFieldName} {
   343  		err := mc.CreateIndex(ctx, collName, field, indexHnsw, false)
   344  		common.CheckErr(t, err, true)
   345  	}
   346  
   347  	err := mc.LoadCollection(ctx, collName, false)
   348  	common.CheckErr(t, err, false, "there is no vector index on field")
   349  
   350  	// create index for another vector field
   351  	indexBinary, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 64)
   352  	for _, field := range []string{common.DefaultBinaryVecFieldName} {
   353  		err := mc.CreateIndex(ctx, collName, field, indexBinary, false)
   354  		common.CheckErr(t, err, true)
   355  	}
   356  	err = mc.LoadCollection(ctx, collName, false)
   357  	common.CheckErr(t, err, true)
   358  }
   359  
   360  // test release partition
   361  func TestReleasePartition(t *testing.T) {
   362  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   363  	// connect
   364  	mc := createMilvusClient(ctx, t)
   365  
   366  	// create collection -> insert data -> create index
   367  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
   368  
   369  	//load collection
   370  	errLoad := mc.LoadCollection(ctx, collName, true)
   371  	common.CheckErr(t, errLoad, true)
   372  
   373  	// release collection
   374  	errRelease := mc.ReleaseCollection(ctx, collName)
   375  	common.CheckErr(t, errRelease, true)
   376  
   377  	// check collection loaded
   378  	collection, _ := mc.DescribeCollection(ctx, collName)
   379  	require.False(t, collection.Loaded)
   380  
   381  	// check release success
   382  	_, errQuery := mc.QueryByPks(ctx, collName, []string{}, entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0}),
   383  		[]string{common.DefaultIntFieldName})
   384  	// TODO change error msg or code
   385  	common.CheckErr(t, errQuery, false, "not loaded")
   386  }
   387  
   388  // test release not exist collection
   389  func TestReleaseCollectionNotExist(t *testing.T) {
   390  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   391  	// connect
   392  	mc := createMilvusClient(ctx, t)
   393  
   394  	// create collection -> insert data -> create index
   395  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
   396  
   397  	//load collection
   398  	errLoad := mc.LoadCollection(ctx, collName, true)
   399  	common.CheckErr(t, errLoad, true)
   400  
   401  	// release collection
   402  	errRelease := mc.ReleaseCollection(ctx, "collName")
   403  	common.CheckErr(t, errRelease, false, "not exist")
   404  }
   405  
   406  // test release partitions
   407  func TestReleasePartitions(t *testing.T) {
   408  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   409  	// connect
   410  	mc := createMilvusClient(ctx, t)
   411  
   412  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   413  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   414  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   415  
   416  	// create index
   417  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   418  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   419  
   420  	// load partitions async
   421  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName}, true)
   422  	common.CheckErr(t, errLoad, true)
   423  
   424  	// release partition
   425  	errRelease := mc.ReleasePartitions(ctx, collName, []string{partitionName})
   426  	common.CheckErr(t, errRelease, true)
   427  
   428  	// check release success
   429  	partitions, _ := mc.ShowPartitions(ctx, collName)
   430  	for _, p := range partitions {
   431  		if p.Name == partitionName {
   432  			require.False(t, p.Loaded)
   433  		}
   434  	}
   435  
   436  	// check release success
   437  	_, errQuery := mc.QueryByPks(ctx, collName, []string{partitionName}, entity.NewColumnInt64(common.DefaultIntFieldName, []int64{common.DefaultNb}),
   438  		[]string{common.DefaultIntFieldName})
   439  
   440  	// TODO fix error msg or code
   441  	common.CheckErr(t, errQuery, false, "not loaded")
   442  }
   443  
   444  // test release partition not exist -> error or part exist -> success
   445  func TestReleasePartitionsNotExist(t *testing.T) {
   446  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   447  	// connect
   448  	mc := createMilvusClient(ctx, t)
   449  
   450  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   451  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   452  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   453  
   454  	// create index
   455  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   456  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   457  
   458  	// load partitions
   459  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName}, false)
   460  	common.CheckErr(t, errLoad, true)
   461  
   462  	// release partition
   463  	errRelease := mc.ReleasePartitions(ctx, collName, []string{"partitionName"})
   464  	common.CheckErr(t, errRelease, false, "not exist")
   465  
   466  	// release partition
   467  	errRelease2 := mc.ReleasePartitions(ctx, collName, []string{"partitionName", partitionName})
   468  	common.CheckErr(t, errRelease2, false, "not exist")
   469  
   470  	// check release success
   471  	partitions, _ := mc.ShowPartitions(ctx, collName)
   472  	for _, p := range partitions {
   473  		if p.Name == partitionName {
   474  			require.False(t, p.Loaded)
   475  		}
   476  	}
   477  
   478  	// check release success
   479  	queryIds := entity.NewColumnInt64(common.DefaultIntFieldName, []int64{common.DefaultNb})
   480  	_, errQuery := mc.QueryByPks(ctx, collName, []string{partitionName}, queryIds,
   481  		[]string{common.DefaultIntFieldName})
   482  	common.CheckErr(t, errQuery, true)
   483  }
   484  
   485  func TestReleaseMultiPartitions(t *testing.T) {
   486  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   487  	// connect
   488  	mc := createMilvusClient(ctx, t)
   489  
   490  	// create collection and insert [0, nb) into default partition, [nb, nb*2) into new partition
   491  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   492  	partitionName, _, _ := createInsertTwoPartitions(ctx, t, mc, collName, common.DefaultNb)
   493  
   494  	// create index
   495  	idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   496  	mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false)
   497  
   498  	// load multi partitions
   499  	errLoad := mc.LoadPartitions(ctx, collName, []string{partitionName, common.DefaultPartition}, false)
   500  	common.CheckErr(t, errLoad, true)
   501  
   502  	// release partition
   503  	errRelease := mc.ReleasePartitions(ctx, collName, []string{partitionName, common.DefaultPartition})
   504  	common.CheckErr(t, errRelease, true)
   505  
   506  	// check release success
   507  	partitions, _ := mc.ShowPartitions(ctx, collName)
   508  	for _, p := range partitions {
   509  		require.False(t, p.Loaded)
   510  	}
   511  
   512  	// check release success
   513  	queryIds := entity.NewColumnInt64(common.DefaultIntFieldName, []int64{0, common.DefaultNb})
   514  	_, errQuery := mc.QueryByPks(ctx, collName, []string{partitionName, common.DefaultPartition}, queryIds,
   515  		[]string{common.DefaultIntFieldName})
   516  	common.CheckErr(t, errQuery, false, "collection not loaded")
   517  }
   518  
   519  // test mmap collection raw data and index
   520  // create -> insert -> flush -> index with mmap -> load -> alter collection with mmap -> reload -> read op
   521  func TestMmapCollectionIndexDefault(t *testing.T) {
   522  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   523  	// connect
   524  	mc := createMilvusClient(ctx, t)
   525  
   526  	// create -> insert [0, 3000) -> flush
   527  	cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: true,
   528  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   529  	collName := createCollection(ctx, t, mc, cp)
   530  
   531  	dp := DataParams{DoInsert: true, CollectionName: collName, CollectionFieldsType: AllFields, start: 0,
   532  		nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true}
   533  	insertData(ctx, t, mc, dp)
   534  	_ = mc.Flush(ctx, collName, false)
   535  
   536  	// create vector index with mmap
   537  	GenDefaultIndexParamsForAllVectors()
   538  	indexHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   539  	indexBinary, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 64)
   540  	for _, fieldName := range common.AllVectorsFieldsName {
   541  		if fieldName == common.DefaultBinaryVecFieldName {
   542  			err := mc.CreateIndex(ctx, collName, fieldName, indexBinary, false, client.WithMmap(true))
   543  			common.CheckErr(t, err, true)
   544  		} else if fieldName == common.DefaultFloatVecFieldName {
   545  			err := mc.CreateIndex(ctx, collName, fieldName, indexHnsw, false, client.WithMmap(true))
   546  			common.CheckErr(t, err, true)
   547  		} else {
   548  			err := mc.CreateIndex(ctx, collName, fieldName, indexHnsw, false)
   549  			common.CheckErr(t, err, true)
   550  		}
   551  	}
   552  
   553  	// describe index and check mmap
   554  	for _, fieldName := range common.AllVectorsFieldsName {
   555  		if fieldName == common.DefaultFloatVecFieldName || fieldName == common.DefaultBinaryVecFieldName {
   556  			indexes, _ := mc.DescribeIndex(ctx, collName, fieldName)
   557  			require.Len(t, indexes, 1)
   558  			// check index mmap
   559  			require.Equal(t, "true", indexes[0].Params()["mmap.enabled"])
   560  		}
   561  	}
   562  
   563  	// load collection -> describe collection and check mmap false
   564  	_ = mc.LoadCollection(ctx, collName, false)
   565  	coll, _ := mc.DescribeCollection(ctx, collName)
   566  	require.Equal(t, "", coll.Properties["mmap.enabled"])
   567  
   568  	// alter collection and check collection mmap
   569  	_ = mc.ReleaseCollection(ctx, collName)
   570  	err := mc.AlterCollection(ctx, collName, entity.Mmap(true))
   571  	common.CheckErr(t, err, true)
   572  
   573  	//describe collection
   574  	mc.LoadCollection(ctx, collName, false)
   575  	coll, _ = mc.DescribeCollection(ctx, collName)
   576  	require.Equal(t, "true", coll.Properties["mmap.enabled"])
   577  
   578  	// query
   579  	queryRes, err := mc.Query(ctx, collName, []string{}, fmt.Sprintf("%s < 10", common.DefaultIntFieldName), []string{"*"})
   580  	common.CheckErr(t, err, true)
   581  	require.Equal(t, queryRes.GetColumn(common.DefaultIntFieldName).Len(), 10)
   582  	common.CheckOutputFields(t, queryRes, common.GetAllFieldsName(true, false))
   583  
   584  	// search
   585  	queryVec1 := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector)
   586  	sp, _ := entity.NewIndexHNSWSearchParam(74)
   587  	expr := fmt.Sprintf("%s > 10", common.DefaultIntFieldName)
   588  	searchRes, _ := mc.Search(ctx, collName, []string{}, expr, []string{"*"}, queryVec1, common.DefaultFloatVecFieldName,
   589  		entity.L2, common.DefaultTopK, sp)
   590  	common.CheckOutputFields(t, searchRes[0].Fields, common.GetAllFieldsName(true, false))
   591  
   592  	// hybrid search
   593  	queryVec2 := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector)
   594  	sReqs := []*client.ANNSearchRequest{
   595  		client.NewANNSearchRequest(common.DefaultFloatVecFieldName, entity.L2, "", queryVec1, sp, common.DefaultTopK, client.WithOffset(3)),
   596  		client.NewANNSearchRequest(common.DefaultBinaryVecFieldName, entity.JACCARD, "", queryVec2, sp, common.DefaultTopK),
   597  	}
   598  	_, errSearch := mc.HybridSearch(ctx, collName, []string{}, common.DefaultTopK, []string{}, client.NewRRFReranker(), sReqs)
   599  	common.CheckErr(t, errSearch, true)
   600  }
   601  
   602  // test mmap collection raw data and index
   603  // create -> insert -> flush -> index -> load -> alter collection with mmap -> alter index with mmap -> reload -> read op
   604  func TestMmapAlterCollectionIndexDefault(t *testing.T) {
   605  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   606  	// connect
   607  	mc := createMilvusClient(ctx, t)
   608  
   609  	// create -> insert [0, 3000) -> flush
   610  	cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: true,
   611  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   612  
   613  	dp := DataParams{DoInsert: true, CollectionFieldsType: AllFields, start: 0,
   614  		nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true}
   615  
   616  	ips := GenDefaultIndexParamsForAllVectors()
   617  	collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong)))
   618  
   619  	// describe index and check mmap
   620  	for _, fieldName := range common.AllVectorsFieldsName {
   621  		indexes, _ := mc.DescribeIndex(ctx, collName, fieldName)
   622  		// check index mmap
   623  		require.Equal(t, "", indexes[0].Params()["mmap.enabled"])
   624  	}
   625  
   626  	//describe collection
   627  	mc.LoadCollection(ctx, collName, false)
   628  	coll, _ := mc.DescribeCollection(ctx, collName)
   629  	require.Equal(t, "", coll.Properties["mmap.enabled"])
   630  
   631  	// alter mmap: collection and index
   632  	_ = mc.ReleaseCollection(ctx, collName)
   633  	err := mc.AlterCollection(ctx, collName, entity.Mmap(true))
   634  	common.CheckErr(t, err, true)
   635  	for _, fieldName := range common.AllVectorsFieldsName {
   636  		err := mc.AlterIndex(ctx, collName, fieldName, client.WithMmap(true))
   637  		common.CheckErr(t, err, true)
   638  	}
   639  
   640  	// load collection -> describe collection and check mmap false
   641  	//describe collection
   642  	mc.LoadCollection(ctx, collName, false)
   643  	coll, _ = mc.DescribeCollection(ctx, collName)
   644  	require.Equal(t, "true", coll.Properties["mmap.enabled"])
   645  	for _, fieldName := range common.AllVectorsFieldsName {
   646  		idx, _ := mc.DescribeIndex(ctx, collName, fieldName)
   647  		require.Equal(t, "true", idx[0].Params()["mmap.enabled"])
   648  	}
   649  
   650  	// query
   651  	queryRes, err := mc.Query(ctx, collName, []string{}, fmt.Sprintf("%s < 10", common.DefaultIntFieldName), []string{"*"})
   652  	common.CheckErr(t, err, true)
   653  	require.Equal(t, queryRes.GetColumn(common.DefaultIntFieldName).Len(), 10)
   654  	common.CheckOutputFields(t, queryRes, common.GetAllFieldsName(true, false))
   655  
   656  	// search
   657  	queryVec1 := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector)
   658  	sp, _ := entity.NewIndexHNSWSearchParam(74)
   659  	expr := fmt.Sprintf("%s > 10", common.DefaultIntFieldName)
   660  	searchRes, _ := mc.Search(ctx, collName, []string{}, expr, []string{"*"}, queryVec1, common.DefaultFloatVecFieldName,
   661  		entity.L2, common.DefaultTopK, sp)
   662  	common.CheckOutputFields(t, searchRes[0].Fields, common.GetAllFieldsName(true, false))
   663  
   664  	// hybrid search
   665  	queryVec2 := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector)
   666  	sReqs := []*client.ANNSearchRequest{
   667  		client.NewANNSearchRequest(common.DefaultFloatVecFieldName, entity.L2, "", queryVec1, sp, common.DefaultTopK, client.WithOffset(3)),
   668  		client.NewANNSearchRequest(common.DefaultBinaryVecFieldName, entity.JACCARD, "", queryVec2, sp, common.DefaultTopK),
   669  	}
   670  	_, errSearch := mc.HybridSearch(ctx, collName, []string{}, common.DefaultTopK, []string{}, client.NewRRFReranker(), sReqs)
   671  	common.CheckErr(t, errSearch, true)
   672  }
   673  
   674  // test mmap collection loaded
   675  func TestMmapCollectionLoaded(t *testing.T) {
   676  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   677  	// connect
   678  	mc := createMilvusClient(ctx, t)
   679  
   680  	// create -> insert -> flush -> index -> load
   681  	cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: false,
   682  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   683  
   684  	dp := DataParams{DoInsert: true, CollectionFieldsType: Int64FloatVec, start: 0, nb: common.DefaultNb,
   685  		dim: common.DefaultDim, EnableDynamicField: false}
   686  
   687  	collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong)))
   688  
   689  	// mmap collection raw data
   690  	err := mc.AlterCollection(ctx, collName, entity.Mmap(true))
   691  	common.CheckErr(t, err, false, "can not alter mmap properties if collection loaded")
   692  
   693  	// mmap index
   694  	err = mc.AlterIndex(ctx, collName, common.DefaultFloatVecFieldName, client.WithMmap(true))
   695  	common.CheckErr(t, err, false, "can't alter index on loaded collection, please release the collection first")
   696  }
   697  
   698  // test mmap collection which scalar field indexed
   699  func TestMmapCollectionScalarIndexed(t *testing.T) {
   700  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   701  	// connect
   702  	mc := createMilvusClient(ctx, t)
   703  
   704  	// create -> insert -> flush -> index -> load
   705  	cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: false,
   706  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   707  
   708  	dp := DataParams{DoInsert: true, CollectionFieldsType: Int64FloatVec, start: 0, nb: common.DefaultNb,
   709  		dim: common.DefaultDim, EnableDynamicField: false}
   710  
   711  	collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong)))
   712  
   713  	// create scalar index
   714  	for _, fName := range []string{common.DefaultIntFieldName, common.DefaultFloatFieldName} {
   715  		err := mc.CreateIndex(ctx, collName, fName, entity.NewScalarIndexWithType(entity.Inverted), false)
   716  		common.CheckErr(t, err, true)
   717  	}
   718  
   719  	// mmap collection
   720  	mc.ReleaseCollection(ctx, collName)
   721  	err := mc.AlterCollection(ctx, collName, entity.Mmap(true))
   722  	common.CheckErr(t, err, true)
   723  	err = mc.LoadCollection(ctx, collName, false)
   724  	common.CheckErr(t, err, true)
   725  }
   726  
   727  // test mmap unsupported index: DiskANN, GPU-class
   728  func TestMmapIndexUnsupported(t *testing.T) {
   729  	t.Skip("https://github.com/milvus-io/milvus-sdk-go/issues/714")
   730  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   731  	// connect
   732  	mc := createMilvusClient(ctx, t)
   733  
   734  	// create -> insert -> flush -> index -> load
   735  	cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: false,
   736  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   737  	collName := createCollection(ctx, t, mc, cp)
   738  
   739  	dp := DataParams{DoInsert: true, CollectionName: collName, CollectionFieldsType: Int64FloatVec, start: 0,
   740  		nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: false}
   741  	insertData(ctx, t, mc, dp)
   742  	mc.Flush(ctx, collName, false)
   743  
   744  	//create index with mmap
   745  	idx, _ := entity.NewIndexDISKANN(entity.COSINE)
   746  	err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithMmap(true))
   747  	common.CheckErr(t, err, false, "index type DISKANN does not support mmap")
   748  
   749  	//create scalar index with mmap
   750  	for _, idx := range []entity.Index{entity.NewScalarIndex(), entity.NewScalarIndexWithType(entity.Inverted)} {
   751  		err := mc.CreateIndex(ctx, collName, common.DefaultFloatFieldName, idx, false, client.WithMmap(true))
   752  		common.CheckErr(t, err, false, "does not support mmap")
   753  	}
   754  }
   755  
   756  func TestAlterIndexMmapUnsupportedIndex(t *testing.T) {
   757  	ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   758  	// connect
   759  	mc := createMilvusClient(ctx, t)
   760  
   761  	// create -> insert -> flush -> index -> load
   762  	cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: false,
   763  		ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   764  	collName := createCollection(ctx, t, mc, cp)
   765  
   766  	dp := DataParams{DoInsert: true, CollectionName: collName, CollectionFieldsType: Int64FloatVec, start: 0,
   767  		nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: false}
   768  	insertData(ctx, t, mc, dp)
   769  	mc.Flush(ctx, collName, false)
   770  
   771  	idxHnsw, _ := entity.NewIndexDISKANN(entity.IP)
   772  	err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idxHnsw, false)
   773  	common.CheckErr(t, err, true)
   774  	for _, mmap := range []bool{true, false} {
   775  		err = mc.AlterIndex(ctx, collName, common.DefaultFloatVecFieldName, client.WithMmap(mmap))
   776  		common.CheckErr(t, err, false, "index type DISKANN does not support mmap: invalid parameter")
   777  	}
   778  }
   779  
   780  func TestMmapAlterIndex(t *testing.T) {
   781  	t.Parallel()
   782  	for _, mmap := range []bool{true, false} {
   783  		ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   784  		// connect
   785  		mc := createMilvusClient(ctx, t)
   786  
   787  		// create -> insert -> flush -> index -> load
   788  		cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: false,
   789  			ShardsNum: common.DefaultShards, Dim: common.DefaultDim}
   790  		collName := createCollection(ctx, t, mc, cp)
   791  
   792  		dp := DataParams{DoInsert: true, CollectionName: collName, CollectionFieldsType: Int64FloatVec, start: 0,
   793  			nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: false}
   794  		insertData(ctx, t, mc, dp)
   795  		mc.Flush(ctx, collName, false)
   796  
   797  		// create index and enable mmap
   798  		idxHnsw, _ := entity.NewIndexHNSW(entity.COSINE, 8, 96)
   799  		err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idxHnsw, false, client.WithMmap(!mmap))
   800  		common.CheckErr(t, err, true)
   801  
   802  		// alter index and enable mmap
   803  		err = mc.AlterIndex(ctx, collName, common.DefaultFloatVecFieldName, client.WithMmap(mmap))
   804  		common.CheckErr(t, err, true)
   805  
   806  		idx, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName)
   807  		require.Equal(t, strconv.FormatBool(mmap), idx[0].Params()["mmap.enabled"])
   808  
   809  		err = mc.LoadCollection(ctx, collName, false)
   810  		common.CheckErr(t, err, true)
   811  
   812  		queryVec1 := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector)
   813  		sp, _ := entity.NewIndexHNSWSearchParam(74)
   814  		expr := fmt.Sprintf("%s > 10", common.DefaultIntFieldName)
   815  		searchRes, _ := mc.Search(ctx, collName, []string{}, expr, []string{"*"}, queryVec1, common.DefaultFloatVecFieldName,
   816  			entity.COSINE, common.DefaultTopK, sp)
   817  		common.CheckOutputFields(t, searchRes[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, common.DefaultFloatVecFieldName})
   818  	}
   819  }
   820  
   821  // test search when mmap sparse collection
   822  func TestMmapSparseCollection(t *testing.T) {
   823  	t.Skip("sparse index support mmap now")
   824  	t.Parallel()
   825  	idxInverted, _ := entity.NewIndexSparseInverted(entity.IP, 0)
   826  	idxWand, _ := entity.NewIndexSparseWAND(entity.IP, 0)
   827  	for _, idx := range []entity.Index{idxInverted, idxWand} {
   828  		ctx := createContext(t, time.Second*common.DefaultTimeout*2)
   829  		// connect
   830  		mc := createMilvusClient(ctx, t)
   831  
   832  		// create -> insert [0, 3000) -> flush -> index -> load
   833  		cp := CollectionParams{CollectionFieldsType: Int64VarcharSparseVec, AutoID: false, EnableDynamicField: true,
   834  			ShardsNum: common.DefaultShards, Dim: common.DefaultDim, MaxLength: common.TestMaxLen}
   835  
   836  		dp := DataParams{DoInsert: true, CollectionFieldsType: Int64VarcharSparseVec, start: 0, nb: common.DefaultNb * 5,
   837  			dim: common.DefaultDim, EnableDynamicField: true}
   838  
   839  		// index params
   840  		idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96)
   841  		ips := []IndexParams{
   842  			{BuildIndex: true, Index: idx, FieldName: common.DefaultSparseVecFieldName, async: false},
   843  			{BuildIndex: true, Index: idxHnsw, FieldName: common.DefaultFloatVecFieldName, async: false},
   844  		}
   845  		collName := prepareCollection(ctx, t, mc, cp, WithDataParams(dp), WithIndexParams(ips), WithCreateOption(client.WithConsistencyLevel(entity.ClStrong)))
   846  
   847  		// alter mmap
   848  		mc.ReleaseCollection(ctx, collName)
   849  		// alter index and enable mmap
   850  		err := mc.AlterIndex(ctx, collName, common.DefaultSparseVecFieldName, client.WithMmap(true))
   851  		common.CheckErr(t, err, false, fmt.Sprintf("index type %s does not support mmap", idx.IndexType()))
   852  		err = mc.AlterIndex(ctx, collName, common.DefaultFloatVecFieldName, client.WithMmap(true))
   853  		common.CheckErr(t, err, true)
   854  		err = mc.AlterCollection(ctx, collName, entity.Mmap(true))
   855  		common.CheckErr(t, err, true)
   856  		err = mc.LoadCollection(ctx, collName, false)
   857  		common.CheckErr(t, err, true)
   858  
   859  		// search with floatVec field
   860  		outputFields := []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName, common.DefaultFloatVecFieldName,
   861  			common.DefaultSparseVecFieldName, common.DefaultDynamicFieldName}
   862  		queryVecFloat := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeFloatVector)
   863  		sp, _ := entity.NewIndexSparseInvertedSearchParam(0)
   864  		resSearch, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVecFloat, common.DefaultFloatVecFieldName,
   865  			entity.L2, common.DefaultTopK, sp)
   866  		common.CheckErr(t, errSearch, true)
   867  		common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
   868  		common.CheckOutputFields(t, resSearch[0].Fields, outputFields)
   869  
   870  		// search with sparse vector field
   871  		queryVecSparse := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeSparseVector)
   872  		resSearch, errSearch = mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVecSparse, common.DefaultSparseVecFieldName,
   873  			entity.IP, common.DefaultTopK, sp)
   874  		common.CheckErr(t, errSearch, true)
   875  		common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
   876  		common.CheckOutputFields(t, resSearch[0].Fields, outputFields)
   877  	}
   878  }