From 3844d10c6757d88094a913970c1cfd2f85522aaf Mon Sep 17 00:00:00 2001 From: ThreadDao Date: Fri, 1 Mar 2024 19:13:12 +0800 Subject: [PATCH] Add test cases for groupby search Signed-off-by: ThreadDao --- test/common/utils.go | 45 ++-- test/testcases/gorupby_search_test.go | 371 ++++++++++++++++++++++++++ test/testcases/index_test.go | 101 ++++--- test/testcases/search_test.go | 76 +++++- 4 files changed, 531 insertions(+), 62 deletions(-) create mode 100644 test/testcases/gorupby_search_test.go diff --git a/test/common/utils.go b/test/common/utils.go index 3fef2537c..fac2751cf 100644 --- a/test/common/utils.go +++ b/test/common/utils.go @@ -1030,26 +1030,37 @@ func MergeColumnsToDynamic(nb int, columns []entity.Column) *entity.ColumnJSONBy // --- gen row data --- // --- index utils --- +var SupportFloatMetricType = []entity.MetricType{ + entity.L2, + entity.IP, + entity.COSINE, +} + +var SupportBinFlatMetricType = []entity.MetricType{ + entity.JACCARD, + entity.HAMMING, + entity.SUBSTRUCTURE, + entity.SUPERSTRUCTURE, +} + +var SupportBinIvfFlatMetricType = []entity.MetricType{ + entity.JACCARD, + entity.HAMMING, +} // GenAllFloatIndex gen all float vector index -func GenAllFloatIndex(metricType entity.MetricType) []entity.Index { +func GenAllFloatIndex() []entity.Index { nlist := 128 - idxFlat, _ := entity.NewIndexFlat(metricType) - idxIvfFlat, _ := entity.NewIndexIvfFlat(metricType, nlist) - idxIvfSq8, _ := entity.NewIndexIvfSQ8(metricType, nlist) - idxIvfPq, _ := entity.NewIndexIvfPQ(metricType, nlist, 16, 8) - idxHnsw, _ := entity.NewIndexHNSW(metricType, 8, 96) - idxScann, _ := entity.NewIndexSCANN(metricType, 16, false) - idxDiskAnn, _ := entity.NewIndexDISKANN(metricType) - - allFloatIndex := []entity.Index{ - idxFlat, - idxIvfFlat, - idxIvfSq8, - idxIvfPq, - idxHnsw, - idxScann, - idxDiskAnn, + var allFloatIndex []entity.Index + for _, metricType := range SupportFloatMetricType { + idxFlat, _ := entity.NewIndexFlat(metricType) + idxIvfFlat, _ := entity.NewIndexIvfFlat(metricType, nlist) + idxIvfSq8, _ := entity.NewIndexIvfSQ8(metricType, nlist) + idxIvfPq, _ := entity.NewIndexIvfPQ(metricType, nlist, 16, 8) + idxHnsw, _ := entity.NewIndexHNSW(metricType, 8, 96) + idxScann, _ := entity.NewIndexSCANN(metricType, 16, false) + idxDiskAnn, _ := entity.NewIndexDISKANN(metricType) + allFloatIndex = append(allFloatIndex, idxFlat, idxIvfFlat, idxIvfSq8, idxIvfPq, idxHnsw, idxScann, idxDiskAnn) } return allFloatIndex } diff --git a/test/testcases/gorupby_search_test.go b/test/testcases/gorupby_search_test.go new file mode 100644 index 000000000..962eb7d98 --- /dev/null +++ b/test/testcases/gorupby_search_test.go @@ -0,0 +1,371 @@ +//go:build L0 + +package testcases + +import ( + "context" + "fmt" + "log" + "testing" + "time" + + "github.com/milvus-io/milvus-sdk-go/v2/client" + "github.com/milvus-io/milvus-sdk-go/v2/test/base" + + "github.com/milvus-io/milvus-sdk-go/v2/entity" + "github.com/milvus-io/milvus-sdk-go/v2/test/common" + + "github.com/stretchr/testify/require" +) + +// Generate groupBy-supported vector indexes +func genGroupByVectorIndex(metricType entity.MetricType) []entity.Index { + nlist := 128 + idxFlat, _ := entity.NewIndexFlat(metricType) + idxIvfFlat, _ := entity.NewIndexIvfFlat(metricType, nlist) + idxHnsw, _ := entity.NewIndexHNSW(metricType, 8, 96) + + allFloatIndex := []entity.Index{ + idxFlat, + idxIvfFlat, + idxHnsw, + } + return allFloatIndex +} + +// Generate groupBy-supported vector indexes +func genGroupByBinaryIndex(metricType entity.MetricType) []entity.Index { + nlist := 128 + idxBinFlat, _ := entity.NewIndexBinFlat(metricType, nlist) + idxBinIvfFlat, _ := entity.NewIndexBinIvfFlat(metricType, nlist) + + allFloatIndex := []entity.Index{ + idxBinFlat, + idxBinIvfFlat, + } + return allFloatIndex +} + +func genUnsupportedFloatGroupByIndex() []entity.Index { + idxIvfSq8, _ := entity.NewIndexIvfSQ8(entity.L2, 128) + idxIvfPq, _ := entity.NewIndexIvfPQ(entity.L2, 128, 16, 8) + idxScann, _ := entity.NewIndexSCANN(entity.L2, 16, false) + idxDiskAnn, _ := entity.NewIndexDISKANN(entity.L2) + return []entity.Index{ + idxIvfSq8, + idxIvfPq, + idxScann, + idxDiskAnn, + } +} + +func prepareDataForGroupBySearch(t *testing.T, loopInsert int, idx entity.Index, withGrowing bool) (*base.MilvusClient, context.Context, string) { + ctx := createContext(t, time.Second*common.DefaultTimeout) + mc := createMilvusClient(ctx, t) + + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: true, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) + + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: AllFields, + start: 0, nb: 1000, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} + for i := 0; i < loopInsert; i++ { + _, _ = insertData(ctx, t, mc, dp) + } + + if !withGrowing { + mc.Flush(ctx, collName, false) + } + + // create vector index and scalar index + supportedGroupByFields := []string{common.DefaultIntFieldName, "int8", "int16", "int32", "varchar", "bool"} + idxScalar := entity.NewScalarIndex() + for _, groupByField := range supportedGroupByFields { + mc.CreateIndex(ctx, collName, groupByField, idxScalar, false) + //common.CheckErr(t, err, true) + } + err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) + common.CheckErr(t, err, true) + + // load collection + err = mc.LoadCollection(ctx, collName, false) + common.CheckErr(t, err, true) + + return mc, ctx, collName +} + +// create coll with all datatype -> build all supported index +// -> search with WithGroupByField (int* + varchar + bool +// -> verify every top passage is the top of whole group +// output_fields: pk + groupBy +func TestSearchGroupByFloatDefault(t *testing.T) { + t.Parallel() + for _, metricType := range common.SupportFloatMetricType { + for _, idx := range genGroupByVectorIndex(metricType) { + // prepare data + mc, ctx, collName := prepareDataForGroupBySearch(t, 5, idx, false) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexIvfFlatSearchParam(32) + + // search with groupBy field + supportedGroupByFields := []string{common.DefaultIntFieldName, "int8", "int16", "int32", "varchar", "bool"} + for _, groupByField := range supportedGroupByFields { + resGroupBy, _ := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, groupByField}, queryVec, + common.DefaultFloatVecFieldName, metricType, common.DefaultTopK, sp, client.WithGroupByField(groupByField)) + + // verify each topK entity is the top1 of the whole group + hitsNum := 0 + total := 0 + for _, rs := range resGroupBy { + for i := 0; i < rs.ResultCount; i++ { + groupByValue, _ := rs.Fields.GetColumn(groupByField).Get(i) + pkValue, _ := rs.IDs.GetAsInt64(i) + var expr string + if groupByField == "varchar" { + expr = fmt.Sprintf("%s == '%v' ", groupByField, groupByValue) + } else { + expr = fmt.Sprintf("%s == %v", groupByField, groupByValue) + } + + // search filter with groupByValue is the top1 + resFilter, _ := mc.Search(ctx, collName, []string{}, expr, []string{common.DefaultIntFieldName, + groupByField}, queryVec, common.DefaultFloatVecFieldName, metricType, 1, sp) + filterTop1Pk, _ := resFilter[0].IDs.GetAsInt64(0) + //log.Printf("Search top1 with %s: groupByValue: %v, pkValue: %d. The returned pk by filter search is: %d", + // groupByField, groupByValue, pkValue, filterTop1Pk) + if filterTop1Pk == pkValue { + hitsNum += 1 + } + total += 1 + } + } + + // verify hits rate + hitsRate := float32(hitsNum) / float32(total) + _str := fmt.Sprintf("GroupBy search with field %s, nq=%d and limit=%d , then hitsNum= %d, hitsRate=%v\n", + groupByField, common.DefaultNq, common.DefaultTopK, hitsNum, hitsRate) + log.Println(_str) + require.GreaterOrEqualf(t, hitsRate, float32(0.2), _str) + } + } + } +} + +// binary vector -> not supported +func TestSearchGroupByBinaryDefault(t *testing.T) { + t.Parallel() + for _, metricType := range common.SupportBinIvfFlatMetricType { + for _, idx := range genGroupByBinaryIndex(metricType) { + ctx := createContext(t, time.Second*common.DefaultTimeout) + // connect + mc := createMilvusClient(ctx, t) + + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: VarcharBinaryVec, AutoID: false, EnableDynamicField: true, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) + + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: VarcharBinaryVec, + start: 0, nb: 1000, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} + for i := 0; i < 2; i++ { + _, _ = insertData(ctx, t, mc, dp) + } + mc.Flush(ctx, collName, false) + + // create index and load + err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idx, false) + common.CheckErr(t, err, true) + err = mc.LoadCollection(ctx, collName, false) + common.CheckErr(t, err, true) + + // search params + queryVec := common.GenSearchVectors(1, common.DefaultDim, entity.FieldTypeBinaryVector) + sp, _ := entity.NewIndexBinIvfFlatSearchParam(32) + supportedGroupByFields := []string{common.DefaultVarcharFieldName, common.DefaultBinaryVecFieldName} + + // search with groupBy field + for _, groupByField := range supportedGroupByFields { + _, err := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultVarcharFieldName, groupByField}, queryVec, + common.DefaultBinaryVecFieldName, metricType, common.DefaultTopK, sp, client.WithGroupByField(groupByField)) + common.CheckErr(t, err, false, "Unsupported dataType for chunk brute force iterator:VECTOR_BINARY") + } + } + } +} + +// binary vector -> growing segments, maybe brute force +// default Bounded ConsistencyLevel -> succ ?? +// strong ConsistencyLevel -> error +func TestSearchGroupByBinaryGrowing(t *testing.T) { + //t.Skip("#31134") + t.Parallel() + for _, metricType := range common.SupportBinIvfFlatMetricType { + idxBinIvfFlat, _ := entity.NewIndexBinIvfFlat(metricType, 128) + ctx := createContext(t, time.Second*common.DefaultTimeout) + // connect + mc := createMilvusClient(ctx, t) + + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: VarcharBinaryVec, AutoID: false, EnableDynamicField: true, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) + + // create index and load + err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idxBinIvfFlat, false) + common.CheckErr(t, err, true) + err = mc.LoadCollection(ctx, collName, false) + common.CheckErr(t, err, true) + + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: VarcharBinaryVec, + start: 0, nb: 1000, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} + _, _ = insertData(ctx, t, mc, dp) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector) + sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) + supportedGroupByFields := []string{common.DefaultVarcharFieldName} + + // search with groupBy field + for _, groupByField := range supportedGroupByFields { + _, err := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultVarcharFieldName, + groupByField}, queryVec, common.DefaultBinaryVecFieldName, metricType, common.DefaultTopK, sp, + client.WithGroupByField(groupByField), client.WithSearchQueryConsistencyLevel(entity.ClStrong)) + common.CheckErr(t, err, false, "Unsupported dataType for chunk brute force iterator:VECTOR_BINARY") + } + } +} + +// groupBy in growing segments, maybe growing index or brute force +func TestSearchGroupByFloatGrowing(t *testing.T) { + for _, metricType := range common.SupportFloatMetricType { + idxHnsw, _ := entity.NewIndexHNSW(metricType, 8, 96) + mc, ctx, collName := prepareDataForGroupBySearch(t, 1, idxHnsw, true) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexIvfFlatSearchParam(32) + supportedGroupByFields := []string{common.DefaultIntFieldName, "int8", "int16", "int32", "varchar", "bool"} + + // search with groupBy field + hitsNum := 0 + total := 0 + for _, groupByField := range supportedGroupByFields { + resGroupBy, _ := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, groupByField}, queryVec, + common.DefaultFloatVecFieldName, metricType, common.DefaultTopK, sp, client.WithGroupByField(groupByField), + client.WithSearchQueryConsistencyLevel(entity.ClStrong)) + + // verify each topK entity is the top1 in the group + for _, rs := range resGroupBy { + for i := 0; i < rs.ResultCount; i++ { + groupByValue, _ := rs.Fields.GetColumn(groupByField).Get(i) + pkValue, _ := rs.IDs.GetAsInt64(i) + var expr string + if groupByField == "varchar" { + expr = fmt.Sprintf("%s == '%v' ", groupByField, groupByValue) + } else { + expr = fmt.Sprintf("%s == %v", groupByField, groupByValue) + } + + resFilter, _ := mc.Search(ctx, collName, []string{}, expr, []string{common.DefaultIntFieldName, + groupByField}, queryVec, common.DefaultFloatVecFieldName, metricType, 1, sp) + + // search filter with groupByValue is the top1 + filterTop1Pk, _ := resFilter[0].IDs.GetAsInt64(0) + //log.Printf("Search top1 with %s: groupByValue: %v, pkValue: %d. The returned pk by filter search is: %d", + // groupByField, groupByValue, pkValue, filterTop1Pk) + if filterTop1Pk == pkValue { + hitsNum += 1 + } + total += 1 + } + } + // verify hits rate + hitsRate := float32(hitsNum) / float32(total) + _str := fmt.Sprintf("GroupBy search with field %s, nq=%d and limit=%d , then hitsNum= %d, hitsRate=%v\n", + groupByField, common.DefaultNq, common.DefaultTopK, hitsNum, hitsRate) + log.Println(_str) + require.GreaterOrEqual(t, hitsRate, float32(0.6), _str) + } + } +} + +// groupBy + pagination +func TestSearchGroupByPagination(t *testing.T) { + // create index and load + idx, _ := entity.NewIndexHNSW(entity.COSINE, 8, 96) + mc, ctx, collName := prepareDataForGroupBySearch(t, 5, idx, false) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexIvfFlatSearchParam(32) + var offset = int64(10) + + // search pagination & groupBy + resGroupByPagination, _ := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName}, + queryVec, common.DefaultFloatVecFieldName, entity.COSINE, common.DefaultTopK, sp, + client.WithGroupByField(common.DefaultVarcharFieldName), client.WithOffset(offset)) + + common.CheckSearchResult(t, resGroupByPagination, common.DefaultNq, common.DefaultTopK) + + // search limit=origin limit + offset + resGroupByDefault, _ := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName}, + queryVec, common.DefaultFloatVecFieldName, entity.COSINE, common.DefaultTopK+int(offset), sp, + client.WithGroupByField(common.DefaultVarcharFieldName)) + for i := 0; i < common.DefaultNq; i++ { + require.Equal(t, resGroupByDefault[i].IDs.(*entity.ColumnInt64).Data()[10:], resGroupByPagination[i].IDs.(*entity.ColumnInt64).Data()) + } +} + +// only support: "FLAT", "IVF_FLAT", "HNSW" +func TestSearchGroupByUnsupportedIndex(t *testing.T) { + t.Parallel() + for _, idx := range genUnsupportedFloatGroupByIndex() { + mc, ctx, collName := prepareDataForGroupBySearch(t, 3, idx, false) + + // groupBy search + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexIvfFlatSearchParam(32) + _, err := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName}, + queryVec, common.DefaultFloatVecFieldName, entity.MetricType(idx.Params()["metrics_type"]), + common.DefaultTopK, sp, client.WithGroupByField(common.DefaultVarcharFieldName)) + common.CheckErr(t, err, false, "trying to groupBy on unsupported index type will fail, "+ + "currently only support ivf-flat, ivf_cc and HNSW") + } +} + +// FLOAT, DOUBLE, JSON, ARRAY +func TestSearchGroupByUnsupportedDataType(t *testing.T) { + idxHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) + mc, ctx, collName := prepareDataForGroupBySearch(t, 1, idxHnsw, true) + + // groupBy search with unsupported field type + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexIvfFlatSearchParam(32) + for _, unsupportedField := range []string{"float", "double", "json", "floatVec", "int8Array", "floatArray"} { + _, err := mc.Search(ctx, collName, []string{}, "", []string{common.DefaultIntFieldName, common.DefaultVarcharFieldName}, + queryVec, common.DefaultFloatVecFieldName, entity.L2, + common.DefaultTopK, sp, client.WithGroupByField(unsupportedField)) + common.CheckErr(t, err, false, "unsupported data type") + } +} + +// groupBy + iterator -> not supported +func TestSearchGroupByIterator(t *testing.T) { + // TODO: sdk support +} + +// groupBy + range search +func TestSearchGroupByRangeSearch(t *testing.T) { + // TODO: sdk support +} + +// groupBy + advanced search +func TestSearchGroupByAdvancedSearch(t *testing.T) { + // TODO +} diff --git a/test/testcases/index_test.go b/test/testcases/index_test.go index 1da9e655e..739ddc8cc 100644 --- a/test/testcases/index_test.go +++ b/test/testcases/index_test.go @@ -16,12 +16,26 @@ import ( "github.com/milvus-io/milvus-sdk-go/v2/test/common" ) +func supportScalarIndexFieldType(field entity.FieldType) bool { + vectorFieldTypes := []entity.FieldType{ + entity.FieldTypeBinaryVector, entity.FieldTypeFloatVector, + entity.FieldTypeFloat16Vector, entity.FieldTypeBFloat16Vector, + entity.FieldTypeArray, entity.FieldTypeJSON, + } + for _, vectorFieldType := range vectorFieldTypes { + if field == vectorFieldType { + return false + } + } + return true +} + // test create index with supported float vector index, L2 metric type func TestCreateIndex(t *testing.T) { t.Parallel() // create index - allFloatIndexes := common.GenAllFloatIndex(entity.L2) + allFloatIndexes := common.GenAllFloatIndex() for _, idx := range allFloatIndexes { ctx := createContext(t, time.Second*common.DefaultTimeout*3) // connect @@ -60,21 +74,37 @@ func TestCreateIndexDup(t *testing.T) { common.CheckErr(t, err, false, "CreateIndex failed: at most one distinct index is allowed per field") } -// test create index for varchar field -func TestCreateIndexString(t *testing.T) { +// test create scalar index on all scalar field +func TestCreateScalarIndex(t *testing.T) { + //t.Skip("https://github.com/milvus-io/milvus-sdk-go/issues/671") ctx := createContext(t, time.Second*common.DefaultTimeout) //connect mc := createMilvusClient(ctx, t) - collName, _ := createVarcharCollectionWithDataIndex(ctx, t, mc, false) - idx := entity.NewScalarIndex() - err := mc.CreateIndex(ctx, collName, common.DefaultVarcharFieldName, idx, false, client.WithIndexName("scalar_index")) - common.CheckErr(t, err, true) + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: AllFields, AutoID: false, EnableDynamicField: true, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) - // describe index - indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultVarcharFieldName) - expIndex := entity.NewGenericIndex("scalar_index", "", idx.Params()) - common.CheckIndexResult(t, indexes, expIndex) + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: AllFields, + start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} + _, _ = insertData(ctx, t, mc, dp) + mc.Flush(ctx, collName, false) + + coll, _ := mc.DescribeCollection(ctx, collName) + idx := entity.NewScalarIndex() + for _, field := range coll.Schema.Fields { + if supportScalarIndexFieldType(field.DataType) { + err := mc.CreateIndex(ctx, collName, field.Name, idx, false, client.WithIndexName(field.Name)) + common.CheckErr(t, err, true) + + // describe index + indexes, _ := mc.DescribeIndex(ctx, collName, field.Name) + expIndex := entity.NewGenericIndex(field.Name, "", idx.Params()) + common.CheckIndexResult(t, indexes, expIndex) + } + } } // test create scalar index with vector field name @@ -172,38 +202,12 @@ func TestCreateIndexArrayField(t *testing.T) { } } -// test create index with supported float vector index, Ip metric type -func TestCreateIndexIp(t *testing.T) { - t.Parallel() - - // create index - allFloatIndexes := common.GenAllFloatIndex(entity.IP) - for _, idx := range allFloatIndexes { - ctx := createContext(t, time.Second*common.DefaultTimeout*3) - // connect - mc := createMilvusClient(ctx, t) - // create default collection with flush data - collName, _ := createCollectionWithDataIndex(ctx, t, mc, false, false) - err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithIndexName("my_index")) - common.CheckErr(t, err, true) - - // describe index - indexes, _ := mc.DescribeIndex(ctx, collName, common.DefaultFloatVecFieldName) - expIndex := entity.NewGenericIndex("my_index", idx.IndexType(), idx.Params()) - common.CheckIndexResult(t, indexes, expIndex) - } -} - // test create index with supported binary vector index func TestCreateIndexBinaryFlat(t *testing.T) { t.Parallel() // create index - metricTypes := []entity.MetricType{ - entity.JACCARD, - entity.HAMMING, - } - for _, metricType := range metricTypes { + for _, metricType := range common.SupportBinFlatMetricType { idx, _ := entity.NewIndexBinFlat(metricType, 128) ctx := createContext(t, time.Second*common.DefaultTimeout) // connect @@ -226,11 +230,7 @@ func TestCreateIndexBinaryIvfFlat(t *testing.T) { t.Parallel() // create index - metricTypes := []entity.MetricType{ - entity.JACCARD, - entity.HAMMING, - } - for _, metricType := range metricTypes { + for _, metricType := range common.SupportBinIvfFlatMetricType { idx, _ := entity.NewIndexBinIvfFlat(metricType, 128) ctx := createContext(t, time.Second*common.DefaultTimeout) // connect @@ -258,6 +258,8 @@ func TestCreateBinaryIndexNotSupportedMetricsType(t *testing.T) { // create BinIvfFlat, BinFlat index with not supported metric type invalidMetricTypes := []entity.MetricType{ entity.L2, + entity.COSINE, + entity.IP, entity.TANIMOTO, } for _, metricType := range invalidMetricTypes { @@ -265,11 +267,22 @@ func TestCreateBinaryIndexNotSupportedMetricsType(t *testing.T) { idxBinFlat, _ := entity.NewIndexBinFlat(metricType, 128) err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idxBinFlat, false, client.WithIndexName("my_index")) common.CheckErr(t, err, false, "supported: [HAMMING JACCARD SUBSTRUCTURE SUPERSTRUCTURE]") + } + + invalidMetricTypes2 := []entity.MetricType{ + entity.L2, + entity.COSINE, + entity.IP, + entity.TANIMOTO, + entity.SUBSTRUCTURE, + entity.SUPERSTRUCTURE, + } + for _, metricType := range invalidMetricTypes2 { // create BinIvfFlat index idxBinIvfFlat, _ := entity.NewIndexBinIvfFlat(metricType, 128) errIvf := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idxBinIvfFlat, false, client.WithIndexName("my_index2")) - common.CheckErr(t, errIvf, false, "supported: [HAMMING JACCARD SUBSTRUCTURE SUPERSTRUCTURE]") + common.CheckErr(t, errIvf, false, fmt.Sprintf("metric type %v not found or not supported", metricType)) } } diff --git a/test/testcases/search_test.go b/test/testcases/search_test.go index 7c03ecfa7..ab1827249 100644 --- a/test/testcases/search_test.go +++ b/test/testcases/search_test.go @@ -1,4 +1,4 @@ -///go:build L0 +//go:build L0 package testcases @@ -46,6 +46,80 @@ func TestSearch(t *testing.T) { common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) } +func TestSearchFloatGrowing(t *testing.T) { + t.Parallel() + for _, idx := range common.GenAllFloatIndex() { + ctx := createContext(t, time.Second*common.DefaultTimeout) + // connect + mc := createMilvusClient(ctx, t) + + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: Int64FloatVec, AutoID: false, EnableDynamicField: true, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) + + // create index and load + err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false) + common.CheckErr(t, err, true) + err = mc.LoadCollection(ctx, collName, false) + common.CheckErr(t, err, true) + + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: Int64FloatVec, + start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: true, WithRows: false} + _, err = insertData(ctx, t, mc, dp) + common.CheckErr(t, err, true) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector) + sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) + searchResult, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, + common.DefaultFloatVecFieldName, entity.MetricType(idx.Params()["metrics_type"]), common.DefaultTopK, sp, + client.WithSearchQueryConsistencyLevel(entity.ClStrong)) + common.CheckErr(t, errSearch, true) + common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatVecFieldName, + common.DefaultFloatFieldName, common.DefaultDynamicFieldName}) + common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) + } +} + +func TestSearchBinaryGrowing(t *testing.T) { + t.Parallel() + for _, metricType := range common.SupportBinIvfFlatMetricType { + idxBinIvfFlat, _ := entity.NewIndexBinIvfFlat(metricType, 128) + ctx := createContext(t, time.Second*common.DefaultTimeout) + // connect + mc := createMilvusClient(ctx, t) + + // create collection with all datatype + cp := CollectionParams{CollectionFieldsType: VarcharBinaryVec, AutoID: false, EnableDynamicField: false, + ShardsNum: common.DefaultShards, Dim: common.DefaultDim} + collName := createCollection(ctx, t, mc, cp) + + // create index and load + err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idxBinIvfFlat, false) + common.CheckErr(t, err, true) + err = mc.LoadCollection(ctx, collName, false) + common.CheckErr(t, err, true) + + // insert + dp := DataParams{CollectionName: collName, PartitionName: "", CollectionFieldsType: VarcharBinaryVec, + start: 0, nb: common.DefaultNb, dim: common.DefaultDim, EnableDynamicField: false, WithRows: false} + _, err = insertData(ctx, t, mc, dp) + common.CheckErr(t, err, true) + + // search params + queryVec := common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeBinaryVector) + sp, _ := entity.NewIndexBinIvfFlatSearchParam(64) + searchResult, errSearch := mc.Search(ctx, collName, []string{}, "", []string{"*"}, queryVec, + common.DefaultBinaryVecFieldName, metricType, common.DefaultTopK, sp, + client.WithSearchQueryConsistencyLevel(entity.ClStrong)) + common.CheckErr(t, errSearch, true) + common.CheckOutputFields(t, searchResult[0].Fields, []string{common.DefaultVarcharFieldName, common.DefaultBinaryVecFieldName}) + common.CheckSearchResult(t, searchResult, common.DefaultNq, common.DefaultTopK) + } +} + // test search collection not exist func TestSearchCollectionNotExist(t *testing.T) { ctx := createContext(t, time.Second*common.DefaultTimeout)