Repository: milvus-io/milvus-sdk-go
Pull request #137 (2021-07-15 02:48:31)

Add index search param
Add index search parameters
Add search param validation

Related issue: #127 

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>

sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/137#" title="Author self-approved">congqixia</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
sunby: /lgtm
/approve
sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/137#" title="Author self-approved">congqixia</a>*, *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/137#issuecomment-880348406" title="Approved">sunby</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia,sunby]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/client/client.go b/client/client.go
index ee81933..46d0c0a 100644
--- a/client/client.go
+++ b/client/client.go
@@ -82,7 +82,7 @@ type Client interface {
 	Flush(ctx context.Context, collName string, async bool) error
 	// Search search with bool expression
 	Search(ctx context.Context, collName string, partitions []string,
-		expr string, outputFields []string, vectors []entity.Vector, vectorField string, metricType entity.MetricType, topK int, params map[string]string) ([]SearchResult, error)
+		expr string, outputFields []string, vectors []entity.Vector, vectorField string, metricType entity.MetricType, topK int, sp entity.SearchParam) ([]SearchResult, error)
 }
 
 // SearchResult search result
diff --git a/client/client_grpc_dm.go b/client/client_grpc_dm.go
index 4b06953..dfb7cde 100644
--- a/client/client_grpc_dm.go
+++ b/client/client_grpc_dm.go
@@ -114,11 +114,11 @@ func (c *grpcClient) Flush(ctx context.Context, collName string, async bool) err
 
 //BoolExprSearch search with bool expression
 func (c *grpcClient) Search(ctx context.Context, collName string, partitions []string,
-	expr string, outputFields []string, vectors []entity.Vector, vectorField string, metricType entity.MetricType, topK int, params map[string]string) ([]SearchResult, error) {
+	expr string, outputFields []string, vectors []entity.Vector, vectorField string, metricType entity.MetricType, topK int, sp entity.SearchParam) ([]SearchResult, error) {
 	if c.service == nil {
 		return []SearchResult{}, ErrClientNotReady
 	}
-	bs, _ := json.Marshal(params)
+	bs, _ := json.Marshal(sp.Params())
 	searchParams := entity.MapKvPairs(map[string]string{
 		"anns_field":  vectorField,
 		"topk":        fmt.Sprintf("%d", topK),
diff --git a/entity/genidx/genidx.go b/entity/genidx/genidx.go
index 2d12055..e123c8e 100644
--- a/entity/genidx/genidx.go
+++ b/entity/genidx/genidx.go
@@ -127,17 +127,103 @@ func TestIndex{{.IdxName}}(t *testing.T){
 	})
 }
 {{end}}{{end}}
+`))
+
+var indexSearchParamTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate at {{ .Timestamp }}
+
+//Package entity defineds entities used in sdk
+package entity
+
+import (
+	"errors"
+	"fmt"
+)
+
+{{ range .Indexes }}{{with.}}
+var _ SearchParam = &Index{{.IdxName}}SearchParam{}
+
+// Index{{.IdxName}}SearchParam search param struct for index type {{.IdxType}}
+type Index{{.IdxName}}SearchParam struct { //auto generated fields{{range .SearchParams}}{{with.}}
+	{{.Name}} {{.ParamType}}{{end}}{{end}}
+}
 
+// Params returns index construction params, implementing Index interface
+func(i *Index{{.IdxName}}SearchParam) Params() map[string]string {
+	return map[string]string {//auto generated mapping {{range .SearchParams}}{{with .}}
+		"{{.Name}}": fmt.Sprintf("%v",i.{{.Name}}),{{end}}{{end}}
+	}
+}
+
+// NewIndex{{.IdxName}}SearchParam create index search param
+func NewIndex{{.IdxName}}SearchParam({{range .SearchParams}}{{with .}}
+	{{.Name}} {{.ParamType}},
+{{end}}{{end}}) (*Index{{.IdxName}}SearchParam, error) {
+	// auto generate parameters validation code, if any{{range .SearchParams}}{{with .}}
+	{{.ValidationCode}}
+	{{end}}{{end}}
+	return &Index{{.IdxName}}SearchParam{ {{range .SearchParams}}{{with .}}
+	//auto generated setting
+	{{.Name}}: {{.Name}},{{end}}{{end}}
+	}, nil
+}
+{{end}}{{end}}
+`))
+
+var indexSearchParamTestTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate at {{ .Timestamp }}
+
+//Package entity defineds entities used in sdk
+package entity
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+{{range $idx := .Indexes}}{{with.}}
+func TestIndex{{.IdxName}}SearchParam(t *testing.T) {
+	{{range .SearchParams}}{{with.}}
+	var {{.Name}} {{.ParamType}}{{end}}{{end}}
+
+	t.Run("valid usage case", func(t *testing.T){
+		{{range $i, $example := .ValidSearchParams}}
+		{{$example}}
+		idx{{$i}}, err := NewIndex{{$idx.IdxName}}SearchParam({{range $idx.SearchParams}}{{with.}}
+			{{.Name}},{{end}}{{end}}
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx{{$i}})
+		assert.NotNil(t, idx{{$i}}.Params())
+		{{end}}
+	})
+	{{ if .InvalidSearchParams }}
+	t.Run("invalid usage case", func(t *testing.T){
+		{{range $i, $example := .InvalidSearchParams}}
+		{{$example}}
+		idx{{$i}}, err := NewIndex{{$idx.IdxName}}SearchParam({{range $idx.SearchParams}}{{with.}}
+			{{.Name}},{{end}}{{end}}
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx{{$i}})
+		{{end}}
+	})
+	{{end}}
+}
+{{end}}{{end}}
 `))
 
 type idxDef struct {
-	IdxName         string
-	IdxType         entity.IndexType
-	VectorSupport   int8
-	ConstructParams []idxParam
-	SearchParams    []idxParam
-	ValidExamples   []string // valid value examples, used in tests
-	InvalidExamples []string // invalid value examples, used in tests
+	IdxName             string
+	IdxType             entity.IndexType
+	VectorSupport       int8
+	ConstructParams     []idxParam
+	SearchParams        []idxParam
+	ValidExamples       []string // valid value examples, used in tests
+	InvalidExamples     []string // invalid value examples, used in tests
+	ValidSearchParams   []string
+	InvalidSearchParams []string
 }
 
 type idxParam struct {
@@ -183,10 +269,10 @@ func (ip idxParam) ValidationCode() string {
 		parts := strings.Split(raw, ",")
 		min := strings.TrimSpace(parts[0])
 		max := strings.TrimSpace(parts[1])
-		return fmt.Sprintf(`if %s <= %s {
+		return fmt.Sprintf(`if %s < %s {
 		return nil, errors.New("%s not valid")
 	}
-	if %s >= %s {
+	if %s > %s {
 		return nil, errors.New("%s not valid")
 	}`, ip.Name, min, ip.Name, ip.Name, max, ip.Name)
 	default:
@@ -216,6 +302,18 @@ func main() {
 		os.Exit(1)
 	}
 	defer ft.Close()
+	fp, err := os.OpenFile("indexes_search_param_gen.go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		fmt.Println(err.Error())
+		os.Exit(1)
+	}
+	defer fp.Close()
+	fpt, err := os.OpenFile("indexes_search_param_gen_test.go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		fmt.Println(err.Error())
+		os.Exit(1)
+	}
+	defer fpt.Close()
 
 	settings := struct {
 		Timestamp time.Time
@@ -233,13 +331,26 @@ func main() {
 						ValidationRule: "[1, 65536]",
 					},
 				},
+				SearchParams: []idxParam{
+					{
+						Name:           "nprobe",
+						ValidationRule: "[1, 65536]", //[1, nlist]
+					},
+				},
 				ValidExamples: []string{
-					"nlist = 10",
+					"nlist = 2048",
 				},
 				InvalidExamples: []string{
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// BIN_FLAT
 			{
@@ -252,6 +363,12 @@ func main() {
 						ValidationRule: "[1, 65536]",
 					},
 				},
+				SearchParams: []idxParam{
+					{
+						Name:           "nprobe",
+						ValidationRule: "[1, 65536]", //[1, nlist]
+					},
+				},
 				ValidExamples: []string{
 					"nlist = 10",
 				},
@@ -259,6 +376,13 @@ func main() {
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// IVF_FLAT
 			{
@@ -273,7 +397,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", // [1, nilist], refer to index construct param, not supported yet
+						ValidationRule: "[1, 65536]", // [1, nlist], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -283,6 +407,13 @@ func main() {
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// BIN_IVF_FLAT
 			{
@@ -298,7 +429,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", // [1, nilist], refer to index construct param, not supported yet
+						ValidationRule: "[1, 65536]", // [1, nlist], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -308,6 +439,13 @@ func main() {
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// IVF_SQ8
 			{
@@ -322,7 +460,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", // [1, nilist], refer to index construct param, not supported yet
+						ValidationRule: "[1, 65536]", // [1, nilist], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -332,6 +470,13 @@ func main() {
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// IVF_SQ8H
 			{
@@ -346,7 +491,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", // [1, nilist], refer to index construct param, not supported yet
+						ValidationRule: "[1, 65536]", // [1, nlist], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -356,6 +501,13 @@ func main() {
 					"nlist = 0",
 					"nlist = 65537",
 				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
+				},
 			},
 			// IVF_PQ
 			{
@@ -378,7 +530,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", // [1, nilist], refer to index construct param, not supported yet
+						ValidationRule: "[1, 65536]", // [1, nlist], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -388,7 +540,14 @@ func main() {
 					"nlist, m, nbits = 0, 8, 8",
 					"nlist, m, nbits = 65537, 8, 8",
 					"nlist, m, nbits = 10, 8, 0",
-					"nlist, m, nbits = 10, 8, 16",
+					"nlist, m, nbits = 10, 8, 17",
+				},
+				ValidSearchParams: []string{
+					"nprobe = 10",
+				},
+				InvalidSearchParams: []string{
+					"nprobe = 0",
+					"nprobe = 65537",
 				},
 			},
 			// RNSG
@@ -423,7 +582,7 @@ func main() {
 					"out_degree, candidate_pool_size, search_length, knng = 30, 300, 60, 50",
 				},
 				InvalidExamples: []string{
-					"out_degree, candidate_pool_size, search_length, knng = 5, 300, 60, 50",
+					"out_degree, candidate_pool_size, search_length, knng = 4, 300, 60, 50",
 					"out_degree, candidate_pool_size, search_length, knng = 301, 300, 60, 50",
 					"out_degree, candidate_pool_size, search_length, knng = 30, 49, 60, 50",
 					"out_degree, candidate_pool_size, search_length, knng = 30, 1001, 60, 50",
@@ -432,6 +591,13 @@ func main() {
 					"out_degree, candidate_pool_size, search_length, knng = 30, 300, 60, 4",
 					"out_degree, candidate_pool_size, search_length, knng = 30, 300, 60, 301",
 				},
+				ValidSearchParams: []string{
+					"search_length = 100",
+				},
+				InvalidSearchParams: []string{
+					"search_length = 9",
+					"search_length = 301",
+				},
 			},
 			// HNSW
 			{
@@ -450,7 +616,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "ef",
-						ValidationRule: "", // [topK, 32768], refer to index construct param, not supported yet
+						ValidationRule: "[1, 32768]", // [topK, 32768], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -462,6 +628,13 @@ func main() {
 					"M, efConstruction = 16, 7",
 					"M, efConstruction = 16, 513",
 				},
+				ValidSearchParams: []string{
+					"ef = 16",
+				},
+				InvalidSearchParams: []string{
+					"ef = 0",
+					"ef = 32769",
+				},
 			},
 			// RHNSW_FLAT
 			{
@@ -480,7 +653,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "ef",
-						ValidationRule: "", // [topK, 32768], refer to index construct param, not supported yet
+						ValidationRule: "[1, 32768]", // [topK, 32768], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -492,6 +665,13 @@ func main() {
 					"M, efConstruction = 16, 7",
 					"M, efConstruction = 16, 513",
 				},
+				ValidSearchParams: []string{
+					"ef = 16",
+				},
+				InvalidSearchParams: []string{
+					"ef = 0",
+					"ef = 32769",
+				},
 			},
 			// RHNSW_PQ
 			{
@@ -514,7 +694,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "ef",
-						ValidationRule: "", // [topK, 32768], refer to index construct param, not supported yet
+						ValidationRule: "[1, 32768]", // [topK, 32768], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -526,6 +706,13 @@ func main() {
 					"M, efConstruction, PQM = 16, 7, 8",
 					"M, efConstruction, PQM = 16, 513, 8",
 				},
+				ValidSearchParams: []string{
+					"ef = 16",
+				},
+				InvalidSearchParams: []string{
+					"ef = 0",
+					"ef = 32769",
+				},
 			},
 			// RHNSW_SQ
 			{
@@ -544,7 +731,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "ef",
-						ValidationRule: "", // [topK, 32768], refer to index construct param, not supported yet
+						ValidationRule: "[1, 32768]", // [topK, 32768], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -556,6 +743,13 @@ func main() {
 					"M, efConstruction = 16, 7",
 					"M, efConstruction = 16, 513",
 				},
+				ValidSearchParams: []string{
+					"ef = 16",
+				},
+				InvalidSearchParams: []string{
+					"ef = 0",
+					"ef = 32769",
+				},
 			},
 			// IVF_HNSW
 			{
@@ -578,11 +772,11 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "nprobe",
-						ValidationRule: "", //[1, nlist]
+						ValidationRule: "[1, 65536]", //[1, nlist]
 					},
 					{
 						Name:           "ef",
-						ValidationRule: "", // [topK, 32768], refer to index construct param, not supported yet
+						ValidationRule: "[1, 32768]", // [topK, 32768], refer to index construct param, not supported yet
 					},
 				},
 				ValidExamples: []string{
@@ -596,6 +790,15 @@ func main() {
 					"nlist, M, efConstruction = 10, 16, 7",
 					"nlist, M, efConstruction = 10, 16, 513",
 				},
+				ValidSearchParams: []string{
+					"nprobe, ef = 10, 16",
+				},
+				InvalidSearchParams: []string{
+					"nprobe, ef = 0, 16",
+					"nprobe, ef = 65537, 16",
+					"nprobe, ef = 10, 0",
+					"nprobe, ef = 10, 32769",
+				},
 			},
 			// ANNOY
 			{
@@ -620,6 +823,10 @@ func main() {
 					"n_trees = 0",
 					"n_trees = 1025",
 				},
+				ValidSearchParams: []string{
+					"search_k = -1",
+					"search_k = 20", // if 20 greater than top k
+				},
 			},
 			// NGT_PANNG
 			{
@@ -642,7 +849,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "max_search_edges",
-						ValidationRule: "[-1, 200]", // -1 or [topk, n * n_trees]
+						ValidationRule: "[-1, 200]",
 					},
 					{
 						Name:           "epsilon",
@@ -661,6 +868,16 @@ func main() {
 					"edge_size, forcedly_pruned_edge_size, selectively_pruned_edge_size = 20, 40, 40",
 					"edge_size, forcedly_pruned_edge_size, selectively_pruned_edge_size = 20, 40, 201",
 				},
+				ValidSearchParams: []string{
+					"max_search_edges, epsilon = 40, 0.1",
+					"max_search_edges, epsilon = -1, -0.5",
+				},
+				InvalidSearchParams: []string{
+					"max_search_edges, epsilon = -2, 0.1",
+					"max_search_edges, epsilon = 201, 0.1",
+					"max_search_edges, epsilon = 40, 1.2",
+					"max_search_edges, epsilon = 40, -1.1",
+				},
 			},
 			// NGT_ONNG
 			{
@@ -683,7 +900,7 @@ func main() {
 				SearchParams: []idxParam{
 					{
 						Name:           "max_search_edges",
-						ValidationRule: "[-1, 200]", // -1 or [topk, n * n_trees]
+						ValidationRule: "[-1, 200]",
 					},
 					{
 						Name:           "epsilon",
@@ -702,10 +919,22 @@ func main() {
 					"edge_size, outgoing_edge_size, incoming_edge_size = 20, 10, 0",
 					"edge_size, outgoing_edge_size, incoming_edge_size = 20, 10, 201",
 				},
+				ValidSearchParams: []string{
+					"max_search_edges, epsilon = 40, 0.1",
+					"max_search_edges, epsilon = -1, -0.5",
+				},
+				InvalidSearchParams: []string{
+					"max_search_edges, epsilon = -2, 0.1",
+					"max_search_edges, epsilon = 201, 0.1",
+					"max_search_edges, epsilon = 40, 1.2",
+					"max_search_edges, epsilon = 40, -1.1",
+				},
 			},
 		},
 	}
 
 	indexTemplate.Execute(f, settings)
 	indexTestTemplate.Execute(ft, settings)
+	indexSearchParamTemplate.Execute(fp, settings)
+	indexSearchParamTestTemplate.Execute(fpt, settings)
 }
diff --git a/entity/index.go b/entity/index.go
index 917221f..1897c1e 100644
--- a/entity/index.go
+++ b/entity/index.go
@@ -69,6 +69,12 @@ type Index interface {
 	Params() map[string]string
 }
 
+// SearchParam interface for index related search param
+type SearchParam interface {
+	// returns parameters for search/query
+	Params() map[string]string
+}
+
 type baseIndex struct {
 	it   IndexType
 	name string
diff --git a/entity/indexes_gen.go b/entity/indexes_gen.go
index c1c0dac..fc5989a 100755
--- a/entity/indexes_gen.go
+++ b/entity/indexes_gen.go
@@ -1,5 +1,5 @@
 // Code generated by go generate; DO NOT EDIT
-// This file is generated by go generate at 2021-07-14 17:46:20.325910399 +0800 CST m=+0.003759080
+// This file is generated by go generate at 2021-07-15 10:38:56.086006767 +0800 CST m=+0.005470307
 
 //Package entity defineds entities used in sdk
 package entity
@@ -45,10 +45,10 @@ func NewIndexFlat(
 	nlist int,
 ) (*IndexFlat, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -93,10 +93,10 @@ func NewIndexBinFlat(
 	nlist int,
 ) (*IndexBinFlat, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -141,10 +141,10 @@ func NewIndexIvfFlat(
 	nlist int,
 ) (*IndexIvfFlat, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -189,10 +189,10 @@ func NewIndexBinIvfFlat(
 	nlist int,
 ) (*IndexBinIvfFlat, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -237,10 +237,10 @@ func NewIndexIvfSQ8(
 	nlist int,
 ) (*IndexIvfSQ8, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -285,10 +285,10 @@ func NewIndexIvfSQ8H(
 	nlist int,
 ) (*IndexIvfSQ8H, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
@@ -341,19 +341,19 @@ func NewIndexIvfPQ(
 	nbits int,
 ) (*IndexIvfPQ, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
 	
 	
-	if nbits <= 1 {
+	if nbits < 1 {
 		return nil, errors.New("nbits not valid")
 	}
-	if nbits >= 16 {
+	if nbits > 16 {
 		return nil, errors.New("nbits not valid")
 	}
 	
@@ -414,31 +414,31 @@ func NewIndexRNSG(
 	knng int,
 ) (*IndexRNSG, error) {
 	// auto generate parameters validation code, if any
-	if out_degree <= 5 {
+	if out_degree < 5 {
 		return nil, errors.New("out_degree not valid")
 	}
-	if out_degree >= 300 {
+	if out_degree > 300 {
 		return nil, errors.New("out_degree not valid")
 	}
 	
-	if candidate_pool_size <= 50 {
+	if candidate_pool_size < 50 {
 		return nil, errors.New("candidate_pool_size not valid")
 	}
-	if candidate_pool_size >= 1000 {
+	if candidate_pool_size > 1000 {
 		return nil, errors.New("candidate_pool_size not valid")
 	}
 	
-	if search_length <= 10 {
+	if search_length < 10 {
 		return nil, errors.New("search_length not valid")
 	}
-	if search_length >= 300 {
+	if search_length > 300 {
 		return nil, errors.New("search_length not valid")
 	}
 	
-	if knng <= 5 {
+	if knng < 5 {
 		return nil, errors.New("knng not valid")
 	}
-	if knng >= 300 {
+	if knng > 300 {
 		return nil, errors.New("knng not valid")
 	}
 	
@@ -493,17 +493,17 @@ func NewIndexHNSW(
 	efConstruction int,
 ) (*IndexHNSW, error) {
 	// auto generate parameters validation code, if any
-	if M <= 4 {
+	if M < 4 {
 		return nil, errors.New("M not valid")
 	}
-	if M >= 64 {
+	if M > 64 {
 		return nil, errors.New("M not valid")
 	}
 	
-	if efConstruction <= 8 {
+	if efConstruction < 8 {
 		return nil, errors.New("efConstruction not valid")
 	}
-	if efConstruction >= 512 {
+	if efConstruction > 512 {
 		return nil, errors.New("efConstruction not valid")
 	}
 	
@@ -554,17 +554,17 @@ func NewIndexRHNSWFlat(
 	efConstruction int,
 ) (*IndexRHNSWFlat, error) {
 	// auto generate parameters validation code, if any
-	if M <= 4 {
+	if M < 4 {
 		return nil, errors.New("M not valid")
 	}
-	if M >= 64 {
+	if M > 64 {
 		return nil, errors.New("M not valid")
 	}
 	
-	if efConstruction <= 8 {
+	if efConstruction < 8 {
 		return nil, errors.New("efConstruction not valid")
 	}
-	if efConstruction >= 512 {
+	if efConstruction > 512 {
 		return nil, errors.New("efConstruction not valid")
 	}
 	
@@ -619,17 +619,17 @@ func NewIndexRHNSW_PQ(
 	PQM int,
 ) (*IndexRHNSW_PQ, error) {
 	// auto generate parameters validation code, if any
-	if M <= 4 {
+	if M < 4 {
 		return nil, errors.New("M not valid")
 	}
-	if M >= 64 {
+	if M > 64 {
 		return nil, errors.New("M not valid")
 	}
 	
-	if efConstruction <= 8 {
+	if efConstruction < 8 {
 		return nil, errors.New("efConstruction not valid")
 	}
-	if efConstruction >= 512 {
+	if efConstruction > 512 {
 		return nil, errors.New("efConstruction not valid")
 	}
 	
@@ -684,17 +684,17 @@ func NewIndexRHNSW_SQ(
 	efConstruction int,
 ) (*IndexRHNSW_SQ, error) {
 	// auto generate parameters validation code, if any
-	if M <= 4 {
+	if M < 4 {
 		return nil, errors.New("M not valid")
 	}
-	if M >= 64 {
+	if M > 64 {
 		return nil, errors.New("M not valid")
 	}
 	
-	if efConstruction <= 8 {
+	if efConstruction < 8 {
 		return nil, errors.New("efConstruction not valid")
 	}
-	if efConstruction >= 512 {
+	if efConstruction > 512 {
 		return nil, errors.New("efConstruction not valid")
 	}
 	
@@ -749,24 +749,24 @@ func NewIndexIvfHNSW(
 	efConstruction int,
 ) (*IndexIvfHNSW, error) {
 	// auto generate parameters validation code, if any
-	if nlist <= 1 {
+	if nlist < 1 {
 		return nil, errors.New("nlist not valid")
 	}
-	if nlist >= 65536 {
+	if nlist > 65536 {
 		return nil, errors.New("nlist not valid")
 	}
 	
-	if M <= 4 {
+	if M < 4 {
 		return nil, errors.New("M not valid")
 	}
-	if M >= 64 {
+	if M > 64 {
 		return nil, errors.New("M not valid")
 	}
 	
-	if efConstruction <= 8 {
+	if efConstruction < 8 {
 		return nil, errors.New("efConstruction not valid")
 	}
-	if efConstruction >= 512 {
+	if efConstruction > 512 {
 		return nil, errors.New("efConstruction not valid")
 	}
 	
@@ -815,10 +815,10 @@ func NewIndexANNOY(
 	n_trees int,
 ) (*IndexANNOY, error) {
 	// auto generate parameters validation code, if any
-	if n_trees <= 1 {
+	if n_trees < 1 {
 		return nil, errors.New("n_trees not valid")
 	}
-	if n_trees >= 1024 {
+	if n_trees > 1024 {
 		return nil, errors.New("n_trees not valid")
 	}
 	
@@ -871,24 +871,24 @@ func NewIndexNGTPANNG(
 	selectively_pruned_edge_size int,
 ) (*IndexNGTPANNG, error) {
 	// auto generate parameters validation code, if any
-	if edge_size <= 1 {
+	if edge_size < 1 {
 		return nil, errors.New("edge_size not valid")
 	}
-	if edge_size >= 200 {
+	if edge_size > 200 {
 		return nil, errors.New("edge_size not valid")
 	}
 	
-	if forcedly_pruned_edge_size <= selectively_pruned_edge_size + 1 {
+	if forcedly_pruned_edge_size < selectively_pruned_edge_size + 1 {
 		return nil, errors.New("forcedly_pruned_edge_size not valid")
 	}
-	if forcedly_pruned_edge_size >= 200 {
+	if forcedly_pruned_edge_size > 200 {
 		return nil, errors.New("forcedly_pruned_edge_size not valid")
 	}
 	
-	if selectively_pruned_edge_size <= 1 {
+	if selectively_pruned_edge_size < 1 {
 		return nil, errors.New("selectively_pruned_edge_size not valid")
 	}
-	if selectively_pruned_edge_size >= forcedly_pruned_edge_size -1 {
+	if selectively_pruned_edge_size > forcedly_pruned_edge_size -1 {
 		return nil, errors.New("selectively_pruned_edge_size not valid")
 	}
 	
@@ -945,24 +945,24 @@ func NewIndexNGTONNG(
 	incoming_edge_size int,
 ) (*IndexNGTONNG, error) {
 	// auto generate parameters validation code, if any
-	if edge_size <= 1 {
+	if edge_size < 1 {
 		return nil, errors.New("edge_size not valid")
 	}
-	if edge_size >= 200 {
+	if edge_size > 200 {
 		return nil, errors.New("edge_size not valid")
 	}
 	
-	if outgoing_edge_size <= 1 {
+	if outgoing_edge_size < 1 {
 		return nil, errors.New("outgoing_edge_size not valid")
 	}
-	if outgoing_edge_size >= 200 {
+	if outgoing_edge_size > 200 {
 		return nil, errors.New("outgoing_edge_size not valid")
 	}
 	
-	if incoming_edge_size <= 1 {
+	if incoming_edge_size < 1 {
 		return nil, errors.New("incoming_edge_size not valid")
 	}
-	if incoming_edge_size >= 200 {
+	if incoming_edge_size > 200 {
 		return nil, errors.New("incoming_edge_size not valid")
 	}
 	
diff --git a/entity/indexes_search_param_gen.go b/entity/indexes_search_param_gen.go
new file mode 100755
index 0000000..16f74e4
--- /dev/null
+++ b/entity/indexes_search_param_gen.go
@@ -0,0 +1,555 @@
+// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate at 2021-07-15 10:38:56.086006767 +0800 CST m=+0.005470307
+
+//Package entity defineds entities used in sdk
+package entity
+
+import (
+	"errors"
+	"fmt"
+)
+
+var _ SearchParam = &IndexFlatSearchParam{}
+
+// IndexFlatSearchParam search param struct for index type FLAT
+type IndexFlatSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexFlatSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexFlatSearchParam create index search param
+func NewIndexFlatSearchParam(
+	nprobe int,
+) (*IndexFlatSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexFlatSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexBinFlatSearchParam{}
+
+// IndexBinFlatSearchParam search param struct for index type BIN_FLAT
+type IndexBinFlatSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexBinFlatSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexBinFlatSearchParam create index search param
+func NewIndexBinFlatSearchParam(
+	nprobe int,
+) (*IndexBinFlatSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexBinFlatSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexIvfFlatSearchParam{}
+
+// IndexIvfFlatSearchParam search param struct for index type IVF_FLAT
+type IndexIvfFlatSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexIvfFlatSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexIvfFlatSearchParam create index search param
+func NewIndexIvfFlatSearchParam(
+	nprobe int,
+) (*IndexIvfFlatSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexIvfFlatSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexBinIvfFlatSearchParam{}
+
+// IndexBinIvfFlatSearchParam search param struct for index type BIN_IVF_FLAT
+type IndexBinIvfFlatSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexBinIvfFlatSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexBinIvfFlatSearchParam create index search param
+func NewIndexBinIvfFlatSearchParam(
+	nprobe int,
+) (*IndexBinIvfFlatSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexBinIvfFlatSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexIvfSQ8SearchParam{}
+
+// IndexIvfSQ8SearchParam search param struct for index type IVF_SQ8
+type IndexIvfSQ8SearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexIvfSQ8SearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexIvfSQ8SearchParam create index search param
+func NewIndexIvfSQ8SearchParam(
+	nprobe int,
+) (*IndexIvfSQ8SearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexIvfSQ8SearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexIvfSQ8HSearchParam{}
+
+// IndexIvfSQ8HSearchParam search param struct for index type IVF_SQ8_HYBRID
+type IndexIvfSQ8HSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexIvfSQ8HSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexIvfSQ8HSearchParam create index search param
+func NewIndexIvfSQ8HSearchParam(
+	nprobe int,
+) (*IndexIvfSQ8HSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexIvfSQ8HSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexIvfPQSearchParam{}
+
+// IndexIvfPQSearchParam search param struct for index type IVF_PQ
+type IndexIvfPQSearchParam struct { //auto generated fields
+	nprobe int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexIvfPQSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+	}
+}
+
+// NewIndexIvfPQSearchParam create index search param
+func NewIndexIvfPQSearchParam(
+	nprobe int,
+) (*IndexIvfPQSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	return &IndexIvfPQSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+	}, nil
+}
+
+var _ SearchParam = &IndexRNSGSearchParam{}
+
+// IndexRNSGSearchParam search param struct for index type NSG
+type IndexRNSGSearchParam struct { //auto generated fields
+	search_length int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexRNSGSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"search_length": fmt.Sprintf("%v", i.search_length),
+	}
+}
+
+// NewIndexRNSGSearchParam create index search param
+func NewIndexRNSGSearchParam(
+	search_length int,
+) (*IndexRNSGSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if search_length < 10 {
+		return nil, errors.New("search_length not valid")
+	}
+	if search_length > 300 {
+		return nil, errors.New("search_length not valid")
+	}
+
+	return &IndexRNSGSearchParam{
+		//auto generated setting
+		search_length: search_length,
+	}, nil
+}
+
+var _ SearchParam = &IndexHNSWSearchParam{}
+
+// IndexHNSWSearchParam search param struct for index type HNSW
+type IndexHNSWSearchParam struct { //auto generated fields
+	ef int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexHNSWSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"ef": fmt.Sprintf("%v", i.ef),
+	}
+}
+
+// NewIndexHNSWSearchParam create index search param
+func NewIndexHNSWSearchParam(
+	ef int,
+) (*IndexHNSWSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if ef < 1 {
+		return nil, errors.New("ef not valid")
+	}
+	if ef > 32768 {
+		return nil, errors.New("ef not valid")
+	}
+
+	return &IndexHNSWSearchParam{
+		//auto generated setting
+		ef: ef,
+	}, nil
+}
+
+var _ SearchParam = &IndexRHNSWFlatSearchParam{}
+
+// IndexRHNSWFlatSearchParam search param struct for index type RHNSW_FLAT
+type IndexRHNSWFlatSearchParam struct { //auto generated fields
+	ef int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexRHNSWFlatSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"ef": fmt.Sprintf("%v", i.ef),
+	}
+}
+
+// NewIndexRHNSWFlatSearchParam create index search param
+func NewIndexRHNSWFlatSearchParam(
+	ef int,
+) (*IndexRHNSWFlatSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if ef < 1 {
+		return nil, errors.New("ef not valid")
+	}
+	if ef > 32768 {
+		return nil, errors.New("ef not valid")
+	}
+
+	return &IndexRHNSWFlatSearchParam{
+		//auto generated setting
+		ef: ef,
+	}, nil
+}
+
+var _ SearchParam = &IndexRHNSW_PQSearchParam{}
+
+// IndexRHNSW_PQSearchParam search param struct for index type RHNSW_PQ
+type IndexRHNSW_PQSearchParam struct { //auto generated fields
+	ef int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexRHNSW_PQSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"ef": fmt.Sprintf("%v", i.ef),
+	}
+}
+
+// NewIndexRHNSW_PQSearchParam create index search param
+func NewIndexRHNSW_PQSearchParam(
+	ef int,
+) (*IndexRHNSW_PQSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if ef < 1 {
+		return nil, errors.New("ef not valid")
+	}
+	if ef > 32768 {
+		return nil, errors.New("ef not valid")
+	}
+
+	return &IndexRHNSW_PQSearchParam{
+		//auto generated setting
+		ef: ef,
+	}, nil
+}
+
+var _ SearchParam = &IndexRHNSW_SQSearchParam{}
+
+// IndexRHNSW_SQSearchParam search param struct for index type RHNSW_SQ
+type IndexRHNSW_SQSearchParam struct { //auto generated fields
+	ef int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexRHNSW_SQSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"ef": fmt.Sprintf("%v", i.ef),
+	}
+}
+
+// NewIndexRHNSW_SQSearchParam create index search param
+func NewIndexRHNSW_SQSearchParam(
+	ef int,
+) (*IndexRHNSW_SQSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if ef < 1 {
+		return nil, errors.New("ef not valid")
+	}
+	if ef > 32768 {
+		return nil, errors.New("ef not valid")
+	}
+
+	return &IndexRHNSW_SQSearchParam{
+		//auto generated setting
+		ef: ef,
+	}, nil
+}
+
+var _ SearchParam = &IndexIvfHNSWSearchParam{}
+
+// IndexIvfHNSWSearchParam search param struct for index type IVF_HNSW
+type IndexIvfHNSWSearchParam struct { //auto generated fields
+	nprobe int
+	ef     int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexIvfHNSWSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"nprobe": fmt.Sprintf("%v", i.nprobe),
+		"ef":     fmt.Sprintf("%v", i.ef),
+	}
+}
+
+// NewIndexIvfHNSWSearchParam create index search param
+func NewIndexIvfHNSWSearchParam(
+	nprobe int,
+
+	ef int,
+) (*IndexIvfHNSWSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if nprobe < 1 {
+		return nil, errors.New("nprobe not valid")
+	}
+	if nprobe > 65536 {
+		return nil, errors.New("nprobe not valid")
+	}
+
+	if ef < 1 {
+		return nil, errors.New("ef not valid")
+	}
+	if ef > 32768 {
+		return nil, errors.New("ef not valid")
+	}
+
+	return &IndexIvfHNSWSearchParam{
+		//auto generated setting
+		nprobe: nprobe,
+		//auto generated setting
+		ef: ef,
+	}, nil
+}
+
+var _ SearchParam = &IndexANNOYSearchParam{}
+
+// IndexANNOYSearchParam search param struct for index type ANNOY
+type IndexANNOYSearchParam struct { //auto generated fields
+	search_k int
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexANNOYSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"search_k": fmt.Sprintf("%v", i.search_k),
+	}
+}
+
+// NewIndexANNOYSearchParam create index search param
+func NewIndexANNOYSearchParam(
+	search_k int,
+) (*IndexANNOYSearchParam, error) {
+	// auto generate parameters validation code, if any
+
+	return &IndexANNOYSearchParam{
+		//auto generated setting
+		search_k: search_k,
+	}, nil
+}
+
+var _ SearchParam = &IndexNGTPANNGSearchParam{}
+
+// IndexNGTPANNGSearchParam search param struct for index type NGT_PANNG
+type IndexNGTPANNGSearchParam struct { //auto generated fields
+	max_search_edges int
+	epsilon          float64
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexNGTPANNGSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"max_search_edges": fmt.Sprintf("%v", i.max_search_edges),
+		"epsilon":          fmt.Sprintf("%v", i.epsilon),
+	}
+}
+
+// NewIndexNGTPANNGSearchParam create index search param
+func NewIndexNGTPANNGSearchParam(
+	max_search_edges int,
+
+	epsilon float64,
+) (*IndexNGTPANNGSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if max_search_edges < -1 {
+		return nil, errors.New("max_search_edges not valid")
+	}
+	if max_search_edges > 200 {
+		return nil, errors.New("max_search_edges not valid")
+	}
+
+	if epsilon < -1.0 {
+		return nil, errors.New("epsilon not valid")
+	}
+	if epsilon > 1.0 {
+		return nil, errors.New("epsilon not valid")
+	}
+
+	return &IndexNGTPANNGSearchParam{
+		//auto generated setting
+		max_search_edges: max_search_edges,
+		//auto generated setting
+		epsilon: epsilon,
+	}, nil
+}
+
+var _ SearchParam = &IndexNGTONNGSearchParam{}
+
+// IndexNGTONNGSearchParam search param struct for index type NGT_ONNG
+type IndexNGTONNGSearchParam struct { //auto generated fields
+	max_search_edges int
+	epsilon          float64
+}
+
+// Params returns index construction params, implementing Index interface
+func (i *IndexNGTONNGSearchParam) Params() map[string]string {
+	return map[string]string{ //auto generated mapping
+		"max_search_edges": fmt.Sprintf("%v", i.max_search_edges),
+		"epsilon":          fmt.Sprintf("%v", i.epsilon),
+	}
+}
+
+// NewIndexNGTONNGSearchParam create index search param
+func NewIndexNGTONNGSearchParam(
+	max_search_edges int,
+
+	epsilon float64,
+) (*IndexNGTONNGSearchParam, error) {
+	// auto generate parameters validation code, if any
+	if max_search_edges < -1 {
+		return nil, errors.New("max_search_edges not valid")
+	}
+	if max_search_edges > 200 {
+		return nil, errors.New("max_search_edges not valid")
+	}
+
+	if epsilon < -1.0 {
+		return nil, errors.New("epsilon not valid")
+	}
+	if epsilon > 1.0 {
+		return nil, errors.New("epsilon not valid")
+	}
+
+	return &IndexNGTONNGSearchParam{
+		//auto generated setting
+		max_search_edges: max_search_edges,
+		//auto generated setting
+		epsilon: epsilon,
+	}, nil
+}


Test patch:
diff --git a/client/client_grpc_dm_test.go b/client/client_grpc_dm_test.go
index 7376940..b4d1901 100644
--- a/client/client_grpc_dm_test.go
+++ b/client/client_grpc_dm_test.go
@@ -127,11 +127,11 @@ func TestGrpcSearch(t *testing.T) {
 	c := testClient(ctx, t)
 
 	vectors := generateFloatVector(4096, testVectorDim)
-
+	sp, err := entity.NewIndexFlatSearchParam(10)
+	assert.Nil(t, err)
+	assert.NotNil(t, sp)
 	results, err := c.Search(ctx, testCollectionName, []string{}, "int64 > 0", []string{"int64"}, []entity.Vector{entity.FloatVector(vectors[0])},
-		testVectorField, entity.L2, 10, map[string]string{
-			"nprobe": "10",
-		})
+		testVectorField, entity.L2, 10, sp)
 
 	assert.Nil(t, err)
 	assert.NotNil(t, results)
diff --git a/entity/indexes_gen_test.go b/entity/indexes_gen_test.go
index f979aff..d409a87 100755
--- a/entity/indexes_gen_test.go
+++ b/entity/indexes_gen_test.go
@@ -1,5 +1,5 @@
 // Code generated by go generate; DO NOT EDIT
-// This file is generated by go generate at 2021-07-14 17:46:20.325910399 +0800 CST m=+0.003759080
+// This file is generated by go generate at 2021-07-15 10:38:56.086006767 +0800 CST m=+0.005470307
 
 //Package entity defineds entities used in sdk
 package entity
@@ -17,7 +17,7 @@ func TestIndexFlat(t *testing.T){
 
 	t.Run("valid usage case", func(t *testing.T){
 		
-		nlist = 10
+		nlist = 2048
 		idx0, err := NewIndexFlat(
 			nlist,
 		)
@@ -291,7 +291,7 @@ func TestIndexIvfPQ(t *testing.T){
 		assert.NotNil(t, err)
 		assert.Nil(t, idx2)
 		
-		nlist, m, nbits = 10, 8, 16
+		nlist, m, nbits = 10, 8, 17
 		idx3, err := NewIndexIvfPQ(
 			nlist,
 			m,
@@ -330,7 +330,7 @@ func TestIndexRNSG(t *testing.T){
 
 	t.Run("invalid usage case", func(t *testing.T){
 		
-		out_degree, candidate_pool_size, search_length, knng = 5, 300, 60, 50
+		out_degree, candidate_pool_size, search_length, knng = 4, 300, 60, 50
 		idx0, err := NewIndexRNSG(
 			out_degree,
 			candidate_pool_size,
@@ -935,4 +935,3 @@ func TestIndexNGTONNG(t *testing.T){
 	})
 }
 
-
diff --git a/entity/indexes_search_param_gen_test.go b/entity/indexes_search_param_gen_test.go
new file mode 100755
index 0000000..209da68
--- /dev/null
+++ b/entity/indexes_search_param_gen_test.go
@@ -0,0 +1,657 @@
+// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate at 2021-07-15 10:38:56.086006767 +0800 CST m=+0.005470307
+
+//Package entity defineds entities used in sdk
+package entity
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+
+func TestIndexFlatSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexFlatSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexBinFlatSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexBinFlatSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexBinFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexBinFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexIvfFlatSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexBinIvfFlatSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexBinIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexBinIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexBinIvfFlatSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexIvfSQ8SearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexIvfSQ8SearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexIvfSQ8SearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexIvfSQ8SearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexIvfSQ8HSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexIvfSQ8HSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexIvfSQ8HSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexIvfSQ8HSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexIvfPQSearchParam(t *testing.T) {
+	
+	var nprobe int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe = 10
+		idx0, err := NewIndexIvfPQSearchParam(
+			nprobe,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe = 0
+		idx0, err := NewIndexIvfPQSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe = 65537
+		idx1, err := NewIndexIvfPQSearchParam(
+			nprobe,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexRNSGSearchParam(t *testing.T) {
+	
+	var search_length int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		search_length = 100
+		idx0, err := NewIndexRNSGSearchParam(
+			search_length,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		search_length = 9
+		idx0, err := NewIndexRNSGSearchParam(
+			search_length,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		search_length = 301
+		idx1, err := NewIndexRNSGSearchParam(
+			search_length,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexHNSWSearchParam(t *testing.T) {
+	
+	var ef int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		ef = 16
+		idx0, err := NewIndexHNSWSearchParam(
+			ef,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		ef = 0
+		idx0, err := NewIndexHNSWSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		ef = 32769
+		idx1, err := NewIndexHNSWSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexRHNSWFlatSearchParam(t *testing.T) {
+	
+	var ef int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		ef = 16
+		idx0, err := NewIndexRHNSWFlatSearchParam(
+			ef,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		ef = 0
+		idx0, err := NewIndexRHNSWFlatSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		ef = 32769
+		idx1, err := NewIndexRHNSWFlatSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexRHNSW_PQSearchParam(t *testing.T) {
+	
+	var ef int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		ef = 16
+		idx0, err := NewIndexRHNSW_PQSearchParam(
+			ef,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		ef = 0
+		idx0, err := NewIndexRHNSW_PQSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		ef = 32769
+		idx1, err := NewIndexRHNSW_PQSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexRHNSW_SQSearchParam(t *testing.T) {
+	
+	var ef int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		ef = 16
+		idx0, err := NewIndexRHNSW_SQSearchParam(
+			ef,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		ef = 0
+		idx0, err := NewIndexRHNSW_SQSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		ef = 32769
+		idx1, err := NewIndexRHNSW_SQSearchParam(
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+	})
+	
+}
+
+func TestIndexIvfHNSWSearchParam(t *testing.T) {
+	
+	var nprobe int
+	var ef int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		nprobe, ef = 10, 16
+		idx0, err := NewIndexIvfHNSWSearchParam(
+			nprobe,
+			ef,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		nprobe, ef = 0, 16
+		idx0, err := NewIndexIvfHNSWSearchParam(
+			nprobe,
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		nprobe, ef = 65537, 16
+		idx1, err := NewIndexIvfHNSWSearchParam(
+			nprobe,
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+		nprobe, ef = 10, 0
+		idx2, err := NewIndexIvfHNSWSearchParam(
+			nprobe,
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx2)
+		
+		nprobe, ef = 10, 32769
+		idx3, err := NewIndexIvfHNSWSearchParam(
+			nprobe,
+			ef,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx3)
+		
+	})
+	
+}
+
+func TestIndexANNOYSearchParam(t *testing.T) {
+	
+	var search_k int
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		search_k = -1
+		idx0, err := NewIndexANNOYSearchParam(
+			search_k,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+		search_k = 20
+		idx1, err := NewIndexANNOYSearchParam(
+			search_k,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx1)
+		assert.NotNil(t, idx1.Params())
+		
+	})
+	
+}
+
+func TestIndexNGTPANNGSearchParam(t *testing.T) {
+	
+	var max_search_edges int
+	var epsilon float64
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		max_search_edges, epsilon = 40, 0.1
+		idx0, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+		max_search_edges, epsilon = -1, -0.5
+		idx1, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx1)
+		assert.NotNil(t, idx1.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		max_search_edges, epsilon = -2, 0.1
+		idx0, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		max_search_edges, epsilon = 201, 0.1
+		idx1, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+		max_search_edges, epsilon = 40, 1.2
+		idx2, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx2)
+		
+		max_search_edges, epsilon = 40, -1.1
+		idx3, err := NewIndexNGTPANNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx3)
+		
+	})
+	
+}
+
+func TestIndexNGTONNGSearchParam(t *testing.T) {
+	
+	var max_search_edges int
+	var epsilon float64
+
+	t.Run("valid usage case", func(t *testing.T){
+		
+		max_search_edges, epsilon = 40, 0.1
+		idx0, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx0)
+		assert.NotNil(t, idx0.Params())
+		
+		max_search_edges, epsilon = -1, -0.5
+		idx1, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.Nil(t, err)
+		assert.NotNil(t, idx1)
+		assert.NotNil(t, idx1.Params())
+		
+	})
+	
+	t.Run("invalid usage case", func(t *testing.T){
+		
+		max_search_edges, epsilon = -2, 0.1
+		idx0, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx0)
+		
+		max_search_edges, epsilon = 201, 0.1
+		idx1, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx1)
+		
+		max_search_edges, epsilon = 40, 1.2
+		idx2, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx2)
+		
+		max_search_edges, epsilon = 40, -1.1
+		idx3, err := NewIndexNGTONNGSearchParam(
+			max_search_edges,
+			epsilon,
+		)
+		assert.NotNil(t, err)
+		assert.Nil(t, idx3)
+		
+	})
+	
+}
+