Repository: milvus-io/milvus-sdk-go
Pull request #606 (2023-10-24 15:23:50)

Bump SDK Version & milvus-proto/go-api to v2.3.2
/kind improvement

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/606#" 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":[]} -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/606?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) Report
> Merging [#606](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/606?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (90c1ad3) into [master](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/commit/647cbab091d5ee9825dcc9061acf5c2b817da27a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (647cbab) will **not change** coverage.
> Report is 1 commits behind head on master.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/606/graphs/tree.svg?width=650&height=150&src=pr&token=WJK43PV390&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/606?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)

```diff
@@           Coverage Diff           @@
##           master     #606   +/-   ##
=======================================
  Coverage   82.85%   82.85%           
=======================================
  Files          40       40           
  Lines        3640     3640           
=======================================
  Hits         3016     3016           
  Misses        512      512           
  Partials      112      112           
```




Patch:
diff --git a/client/admin.go b/client/admin.go
index 69ebd9f..3246d65 100644
--- a/client/admin.go
+++ b/client/admin.go
@@ -15,9 +15,10 @@ import (
 	"context"
 
 	"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
+	"github.com/milvus-io/milvus-sdk-go/v2/entity"
 )
 
-// GetVersion returns milvus milvuspb.version information.
+// GetVersion returns milvus server version information.
 func (c *GrpcClient) GetVersion(ctx context.Context) (string, error) {
 	if c.Service == nil {
 		return "", ErrClientNotReady
@@ -28,3 +29,25 @@ func (c *GrpcClient) GetVersion(ctx context.Context) (string, error) {
 	}
 	return resp.GetVersion(), nil
 }
+
+// CheckHealth returns milvus state
+func (c *GrpcClient) CheckHealth(ctx context.Context) (*entity.MilvusState, error) {
+	if c.Service == nil {
+		return nil, ErrClientNotReady
+	}
+	resp, err := c.Service.CheckHealth(ctx, &milvuspb.CheckHealthRequest{})
+	if err != nil {
+		return nil, err
+	}
+
+	states := make([]entity.QuotaState, 0, len(resp.GetQuotaStates()))
+	for _, state := range resp.GetQuotaStates() {
+		states = append(states, entity.QuotaState(state))
+	}
+
+	return &entity.MilvusState{
+		IsHealthy:   resp.GetIsHealthy(),
+		Reasons:     resp.GetReasons(),
+		QuotaStates: states,
+	}, nil
+}
diff --git a/client/client.go b/client/client.go
index b974b53..5f066b0 100644
--- a/client/client.go
+++ b/client/client.go
@@ -209,6 +209,8 @@ type Client interface {
 
 	// GetVersion get milvus version
 	GetVersion(ctx context.Context) (string, error)
+	// CheckHealth returns milvus state
+	CheckHealth(ctx context.Context) (*entity.MilvusState, error)
 }
 
 // NewClient create a client connected to remote milvus cluster.
diff --git a/client/data.go b/client/data.go
index 4d18ed4..106f53f 100644
--- a/client/data.go
+++ b/client/data.go
@@ -92,7 +92,8 @@ func (c *GrpcClient) Search(ctx context.Context, collName string, partitions []s
 	return sr, nil
 }
 
-func (c *GrpcClient) parseSearchResult(_ *entity.Schema, outputFields []string, fieldDataList []*schemapb.FieldData, _, from, to int) ([]entity.Column, error) {
+func (c *GrpcClient) parseSearchResult(sch *entity.Schema, outputFields []string, fieldDataList []*schemapb.FieldData, _, from, to int) ([]entity.Column, error) {
+	outputFields = expandWildcard(sch, outputFields)
 	// duplicated name will have only one column now
 	outputSet := make(map[string]struct{})
 	for _, output := range outputFields {
@@ -141,6 +142,37 @@ func (c *GrpcClient) parseSearchResult(_ *entity.Schema, outputFields []string,
 	return columns, nil
 }
 
+func expandWildcard(schema *entity.Schema, outputFields []string) []string {
+	wildcard := false
+	for _, outputField := range outputFields {
+		if outputField == "*" {
+			wildcard = true
+		}
+	}
+	if !wildcard {
+		return outputFields
+	}
+
+	set := make(map[string]struct{})
+	result := make([]string, 0, len(schema.Fields))
+	for _, field := range schema.Fields {
+		result = append(result, field.Name)
+		set[field.Name] = struct{}{}
+	}
+
+	// add dynamic fields output
+	for _, output := range outputFields {
+		if output == "*" {
+			continue
+		}
+		_, ok := set[output]
+		if !ok {
+			result = append(result, output)
+		}
+	}
+	return result
+}
+
 func PKs2Expr(backName string, ids entity.Column) string {
 	var expr string
 	var pkName = ids.Name()
diff --git a/common/common.go b/common/common.go
index 015b997..b7394df 100644
--- a/common/common.go
+++ b/common/common.go
@@ -2,5 +2,5 @@ package common
 
 const (
 	// SDKVersion const value for current version
-	SDKVersion = `v2.3.1`
+	SDKVersion = `v2.3.2`
 )
diff --git a/entity/check_health.go b/entity/check_health.go
new file mode 100644
index 0000000..c821d8c
--- /dev/null
+++ b/entity/check_health.go
@@ -0,0 +1,22 @@
+package entity
+
+type QuotaState int32
+
+const (
+	// QuotaStateUnknown zero value placeholder
+	QuotaStateUnknown QuotaState = 0
+	// QuotaStateReadLimited too many read tasks, read requests are limited
+	QuotaStateReadLimited QuotaState = 2
+	// QuotaStateWriteLimited too many write tasks, write requests are limited
+	QuotaStateWriteLimited QuotaState = 3
+	// QuotaStateDenyToRead too many read tasks, temporarily unable to process read requests
+	QuotaStateDenyToRead QuotaState = 4
+	// QuotaStateDenyToWrite too many write tasks, temporarily unable to process write requests
+	QuotaStateDenyToWrite QuotaState = 5
+)
+
+type MilvusState struct {
+	IsHealthy   bool
+	Reasons     []string
+	QuotaStates []QuotaState
+}
diff --git a/entity/columns.go b/entity/columns.go
index 9c1ebf7..b51a053 100644
--- a/entity/columns.go
+++ b/entity/columns.go
@@ -239,6 +239,13 @@ func FieldDataColumn(fd *schema.FieldData, begin, end int) (Column, error) {
 		}
 		return NewColumnVarChar(fd.GetFieldName(), data.StringData.GetData()[begin:end]), nil
 
+	case schema.DataType_Array:
+		data := fd.GetScalars().GetArrayData()
+		if data == nil {
+			return nil, errFieldDataTypeNotMatch
+		}
+		return parseArrayData(fd.GetFieldName(), data)
+
 	case schema.DataType_JSON:
 		data, ok := fd.GetScalars().GetData().(*schema.ScalarField_JsonData)
 		isDynamic := fd.GetIsDynamic()
@@ -297,6 +304,82 @@ func FieldDataColumn(fd *schema.FieldData, begin, end int) (Column, error) {
 	}
 }
 
+func parseArrayData(fieldName string, array *schema.ArrayArray) (Column, error) {
+	fieldDataList := array.Data
+	elementType := array.ElementType
+
+	switch elementType {
+	case schema.DataType_Bool:
+		var data [][]bool
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetBoolData().GetData())
+		}
+		return NewColumnBoolArray(fieldName, data), nil
+
+	case schema.DataType_Int8:
+		var data [][]int8
+		for _, fd := range fieldDataList {
+			raw := fd.GetIntData().Data
+			row := make([]int8, 0, len(raw))
+			for _, item := range raw {
+				row = append(row, int8(item))
+			}
+			data = append(data, row)
+		}
+		return NewColumnInt8Array(fieldName, data), nil
+
+	case schema.DataType_Int16:
+		var data [][]int16
+		for _, fd := range fieldDataList {
+			raw := fd.GetIntData().Data
+			row := make([]int16, 0, len(raw))
+			for _, item := range raw {
+				row = append(row, int16(item))
+			}
+			data = append(data, row)
+		}
+		return NewColumnInt16Array(fieldName, data), nil
+
+	case schema.DataType_Int32:
+		var data [][]int32
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetIntData().GetData())
+		}
+		return NewColumnInt32Array(fieldName, data), nil
+
+	case schema.DataType_Int64:
+		var data [][]int64
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetLongData().GetData())
+		}
+		return NewColumnInt64Array(fieldName, data), nil
+
+	case schema.DataType_Float:
+		var data [][]float32
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetFloatData().GetData())
+		}
+		return NewColumnFloatArray(fieldName, data), nil
+
+	case schema.DataType_Double:
+		var data [][]float64
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetDoubleData().GetData())
+		}
+		return NewColumnDoubleArray(fieldName, data), nil
+
+	case schema.DataType_VarChar:
+		var data [][][]byte
+		for _, fd := range fieldDataList {
+			data = append(data, fd.GetBytesData().GetData())
+		}
+		return NewColumnVarCharArray(fieldName, data), nil
+
+	default:
+		return nil, fmt.Errorf("unsupported element type %s", elementType)
+	}
+}
+
 // getIntData get int32 slice from result field data
 // also handles LongData bug (see also https://github.com/milvus-io/milvus/issues/23850)
 func getIntData(fd *schema.FieldData) (*schema.ScalarField_IntData, bool) {
diff --git a/entity/columns_array_gen.go b/entity/columns_array_gen.go
new file mode 100755
index 0000000..60eb25e
--- /dev/null
+++ b/entity/columns_array_gen.go
@@ -0,0 +1,805 @@
+// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate 
+
+package entity 
+
+import (
+	"fmt"
+
+	"github.com/cockroachdb/errors"
+	"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
+)
+
+
+// ColumnBoolArray generated columns type for Bool
+type ColumnBoolArray struct {
+	ColumnBase
+	name   string
+	values [][]bool
+}
+
+// Name returns column name
+func (c *ColumnBoolArray) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnBoolArray) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnBoolArray) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnBoolArray) Get(idx int) (interface{}, error) {
+	var r []bool // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnBoolArray) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]bool, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, bool(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_BoolData{
+				BoolData: &schemapb.BoolArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Bool,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnBoolArray) ValueByIdx(idx int) ([]bool, error) {
+	var r []bool // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnBoolArray) AppendValue(i interface{}) error {
+	v, ok := i.([]bool)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []bool, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnBoolArray) Data() [][]bool {
+	return c.values
+}
+
+// NewColumnBool auto generated constructor
+func NewColumnBoolArray(name string, values [][]bool) *ColumnBoolArray {
+	return &ColumnBoolArray {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnInt8Array generated columns type for Int8
+type ColumnInt8Array struct {
+	ColumnBase
+	name   string
+	values [][]int8
+}
+
+// Name returns column name
+func (c *ColumnInt8Array) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnInt8Array) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnInt8Array) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnInt8Array) Get(idx int) (interface{}, error) {
+	var r []int8 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnInt8Array) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]int32, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, int32(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_IntData{
+				IntData: &schemapb.IntArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Int8,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnInt8Array) ValueByIdx(idx int) ([]int8, error) {
+	var r []int8 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnInt8Array) AppendValue(i interface{}) error {
+	v, ok := i.([]int8)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []int8, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnInt8Array) Data() [][]int8 {
+	return c.values
+}
+
+// NewColumnInt8 auto generated constructor
+func NewColumnInt8Array(name string, values [][]int8) *ColumnInt8Array {
+	return &ColumnInt8Array {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnInt16Array generated columns type for Int16
+type ColumnInt16Array struct {
+	ColumnBase
+	name   string
+	values [][]int16
+}
+
+// Name returns column name
+func (c *ColumnInt16Array) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnInt16Array) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnInt16Array) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnInt16Array) Get(idx int) (interface{}, error) {
+	var r []int16 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnInt16Array) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]int32, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, int32(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_IntData{
+				IntData: &schemapb.IntArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Int16,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnInt16Array) ValueByIdx(idx int) ([]int16, error) {
+	var r []int16 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnInt16Array) AppendValue(i interface{}) error {
+	v, ok := i.([]int16)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []int16, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnInt16Array) Data() [][]int16 {
+	return c.values
+}
+
+// NewColumnInt16 auto generated constructor
+func NewColumnInt16Array(name string, values [][]int16) *ColumnInt16Array {
+	return &ColumnInt16Array {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnInt32Array generated columns type for Int32
+type ColumnInt32Array struct {
+	ColumnBase
+	name   string
+	values [][]int32
+}
+
+// Name returns column name
+func (c *ColumnInt32Array) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnInt32Array) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnInt32Array) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnInt32Array) Get(idx int) (interface{}, error) {
+	var r []int32 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnInt32Array) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]int32, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, int32(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_IntData{
+				IntData: &schemapb.IntArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Int32,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnInt32Array) ValueByIdx(idx int) ([]int32, error) {
+	var r []int32 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnInt32Array) AppendValue(i interface{}) error {
+	v, ok := i.([]int32)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []int32, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnInt32Array) Data() [][]int32 {
+	return c.values
+}
+
+// NewColumnInt32 auto generated constructor
+func NewColumnInt32Array(name string, values [][]int32) *ColumnInt32Array {
+	return &ColumnInt32Array {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnInt64Array generated columns type for Int64
+type ColumnInt64Array struct {
+	ColumnBase
+	name   string
+	values [][]int64
+}
+
+// Name returns column name
+func (c *ColumnInt64Array) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnInt64Array) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnInt64Array) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnInt64Array) Get(idx int) (interface{}, error) {
+	var r []int64 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnInt64Array) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]int64, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, int64(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_LongData{
+				LongData: &schemapb.LongArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Int64,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnInt64Array) ValueByIdx(idx int) ([]int64, error) {
+	var r []int64 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnInt64Array) AppendValue(i interface{}) error {
+	v, ok := i.([]int64)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []int64, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnInt64Array) Data() [][]int64 {
+	return c.values
+}
+
+// NewColumnInt64 auto generated constructor
+func NewColumnInt64Array(name string, values [][]int64) *ColumnInt64Array {
+	return &ColumnInt64Array {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnFloatArray generated columns type for Float
+type ColumnFloatArray struct {
+	ColumnBase
+	name   string
+	values [][]float32
+}
+
+// Name returns column name
+func (c *ColumnFloatArray) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnFloatArray) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnFloatArray) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnFloatArray) Get(idx int) (interface{}, error) {
+	var r []float32 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnFloatArray) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]float32, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, float32(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_FloatData{
+				FloatData: &schemapb.FloatArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Float,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnFloatArray) ValueByIdx(idx int) ([]float32, error) {
+	var r []float32 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnFloatArray) AppendValue(i interface{}) error {
+	v, ok := i.([]float32)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []float32, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnFloatArray) Data() [][]float32 {
+	return c.values
+}
+
+// NewColumnFloat auto generated constructor
+func NewColumnFloatArray(name string, values [][]float32) *ColumnFloatArray {
+	return &ColumnFloatArray {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnDoubleArray generated columns type for Double
+type ColumnDoubleArray struct {
+	ColumnBase
+	name   string
+	values [][]float64
+}
+
+// Name returns column name
+func (c *ColumnDoubleArray) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnDoubleArray) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnDoubleArray) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnDoubleArray) Get(idx int) (interface{}, error) {
+	var r []float64 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnDoubleArray) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]float64, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, float64(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_DoubleData{
+				DoubleData: &schemapb.DoubleArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_Double,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnDoubleArray) ValueByIdx(idx int) ([]float64, error) {
+	var r []float64 // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnDoubleArray) AppendValue(i interface{}) error {
+	v, ok := i.([]float64)
+	if !ok {
+		return fmt.Errorf("invalid type, expected []float64, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnDoubleArray) Data() [][]float64 {
+	return c.values
+}
+
+// NewColumnDouble auto generated constructor
+func NewColumnDoubleArray(name string, values [][]float64) *ColumnDoubleArray {
+	return &ColumnDoubleArray {
+		name: name,
+		values: values,
+	}
+}
+
+// ColumnVarCharArray generated columns type for VarChar
+type ColumnVarCharArray struct {
+	ColumnBase
+	name   string
+	values [][][]byte
+}
+
+// Name returns column name
+func (c *ColumnVarCharArray) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *ColumnVarCharArray) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *ColumnVarCharArray) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *ColumnVarCharArray) Get(idx int) (interface{}, error) {
+	var r [][]byte // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *ColumnVarCharArray) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([][]byte, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, []byte(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_BytesData{
+				BytesData: &schemapb.BytesArray{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_VarChar,
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *ColumnVarCharArray) ValueByIdx(idx int) ([][]byte, error) {
+	var r [][]byte // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *ColumnVarCharArray) AppendValue(i interface{}) error {
+	v, ok := i.([][]byte)
+	if !ok {
+		return fmt.Errorf("invalid type, expected [][]byte, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *ColumnVarCharArray) Data() [][][]byte {
+	return c.values
+}
+
+// NewColumnVarChar auto generated constructor
+func NewColumnVarCharArray(name string, values [][][]byte) *ColumnVarCharArray {
+	return &ColumnVarCharArray {
+		name: name,
+		values: values,
+	}
+}
+
diff --git a/entity/genarray/gen_array.go b/entity/genarray/gen_array.go
new file mode 100644
index 0000000..bd011ff
--- /dev/null
+++ b/entity/genarray/gen_array.go
@@ -0,0 +1,171 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"text/template"
+
+	"github.com/milvus-io/milvus-sdk-go/v2/entity"
+)
+
+var arrayColumnTmpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT
+// This file is generated by go generate 
+
+package entity 
+
+import (
+	"fmt"
+
+	"github.com/cockroachdb/errors"
+	"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
+)
+
+{{ range .Types }}{{with .}}
+// Column{{.TypeName}}Array generated columns type for {{.TypeName}}
+type Column{{.TypeName}}Array struct {
+	ColumnBase
+	name   string
+	values [][]{{.TypeDef}}
+}
+
+// Name returns column name
+func (c *Column{{.TypeName}}Array) Name() string {
+	return c.name
+}
+
+// Type returns column FieldType
+func (c *Column{{.TypeName}}Array) Type() FieldType {
+	return FieldTypeArray
+}
+
+// Len returns column values length
+func (c *Column{{.TypeName}}Array) Len() int {
+	return len(c.values)
+}
+
+// Get returns value at index as interface{}.
+func (c *Column{{.TypeName}}Array) Get(idx int) (interface{}, error) {
+	var r []{{.TypeDef}} // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// FieldData return column data mapped to schemapb.FieldData
+func (c *Column{{.TypeName}}Array) FieldData() *schemapb.FieldData {
+	fd := &schemapb.FieldData{
+		Type:      schemapb.DataType_Array,
+		FieldName: c.name,
+	}
+
+	data := make([]*schemapb.ScalarField, 0, c.Len())
+	for _, arr := range c.values {
+		converted := make([]{{.PbType}}, 0, c.Len())
+		for i := 0; i < len(arr); i++ {
+			converted = append(converted, {{.PbType}}(arr[i]))
+		}
+		data = append(data, &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_{{.PbName}}Data{
+				{{.PbName}}Data: &schemapb.{{.PbName}}Array{
+					Data: converted,
+				},
+			},
+		})
+	}
+	fd.Field = &schemapb.FieldData_Scalars{
+		Scalars: &schemapb.ScalarField{
+			Data: &schemapb.ScalarField_ArrayData{
+				ArrayData: &schemapb.ArrayArray{
+					Data:        data,
+					ElementType: schemapb.DataType_{{.TypeName}},
+				},
+			},
+		},
+	}
+	return fd
+}
+
+// ValueByIdx returns value of the provided index
+// error occurs when index out of range
+func (c *Column{{.TypeName}}Array) ValueByIdx(idx int) ([]{{.TypeDef}}, error) {
+	var r []{{.TypeDef}} // use default value
+	if idx < 0 || idx >= c.Len() {
+		return r, errors.New("index out of range")
+	}
+	return c.values[idx], nil
+}
+
+// AppendValue append value into column
+func(c *Column{{.TypeName}}Array) AppendValue(i interface{}) error {
+	v, ok := i.([]{{.TypeDef}})
+	if !ok {
+		return fmt.Errorf("invalid type, expected []{{.TypeDef}}, got %T", i)
+	}
+	c.values = append(c.values, v)
+
+	return nil
+}
+
+// Data returns column data
+func (c *Column{{.TypeName}}Array) Data() [][]{{.TypeDef}} {
+	return c.values
+}
+
+// NewColumn{{.TypeName}} auto generated constructor
+func NewColumn{{.TypeName}}Array(name string, values [][]{{.TypeDef}}) *Column{{.TypeName}}Array {
+	return &Column{{.TypeName}}Array {
+		name: name,
+		values: values,
+	}
+}
+{{end}}{{end}}
+`))
+
+func main() {
+	arrElementTypes := []entity.FieldType{
+		entity.FieldTypeBool,
+		entity.FieldTypeInt8,
+		entity.FieldTypeInt16,
+		entity.FieldTypeInt32,
+		entity.FieldTypeInt64,
+		entity.FieldTypeFloat,
+		entity.FieldTypeDouble,
+		entity.FieldTypeVarChar,
+	}
+
+	pf := func(ft entity.FieldType) interface{} {
+		pbName, pbType := ft.PbFieldType()
+		return struct {
+			TypeName string
+			TypeDef  string
+			PbName   string
+			PbType   string
+		}{
+			TypeName: ft.Name(),
+			TypeDef:  ft.String(),
+			PbName:   pbName,
+			PbType:   pbType,
+		}
+	}
+
+	fn := func(fn string, types []entity.FieldType, tmpl *template.Template, pf func(entity.FieldType) interface{}) {
+		params := struct {
+			Types []interface{}
+		}{
+			Types: make([]interface{}, 0, len(types)),
+		}
+		for _, ft := range types {
+			params.Types = append(params.Types, pf(ft))
+		}
+		f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
+		if err != nil {
+			fmt.Println(err.Error())
+			return
+		}
+		defer f.Close()
+
+		tmpl.Execute(f, params)
+	}
+	fn("columns_array_gen.go", arrElementTypes, arrayColumnTmpl, pf)
+}
diff --git a/entity/schema.go b/entity/schema.go
index d94371b..f9dfd85 100644
--- a/entity/schema.go
+++ b/entity/schema.go
@@ -25,6 +25,9 @@ const (
 	// TypeParamMaxLength is the const for varchar type maximal length
 	TypeParamMaxLength = "max_length"
 
+	// TypeParamMaxCapacity is the const for array type max capacity
+	TypeParamMaxCapacity = `max_capacity`
+
 	// ClStrong strong consistency level
 	ClStrong ConsistencyLevel = ConsistencyLevel(common.ConsistencyLevel_Strong)
 	// ClBounded bounded consistency level with default tolerance of 5 seconds
@@ -137,6 +140,7 @@ type Field struct {
 	IndexParams    map[string]string
 	IsDynamic      bool
 	IsPartitionKey bool
+	ElementType    FieldType
 }
 
 // ProtoMessage generates corresponding FieldSchema
@@ -152,6 +156,7 @@ func (f *Field) ProtoMessage() *schema.FieldSchema {
 		IndexParams:    MapKvPairs(f.IndexParams),
 		IsDynamic:      f.IsDynamic,
 		IsPartitionKey: f.IsPartitionKey,
+		ElementType:    schema.DataType(f.ElementType),
 	}
 }
 
@@ -277,6 +282,19 @@ func (f *Field) WithMaxLength(maxLen int64) *Field {
 	return f
 }
 
+func (f *Field) WithElementType(eleType FieldType) *Field {
+	f.ElementType = eleType
+	return f
+}
+
+func (f *Field) WithMaxCapacity(maxCap int64) *Field {
+	if f.TypeParams == nil {
+		f.TypeParams = make(map[string]string)
+	}
+	f.TypeParams[TypeParamMaxCapacity] = strconv.FormatInt(maxCap, 10)
+	return f
+}
+
 // ReadProto parses FieldSchema
 func (f *Field) ReadProto(p *schema.FieldSchema) *Field {
 	f.ID = p.GetFieldID()
@@ -289,6 +307,7 @@ func (f *Field) ReadProto(p *schema.FieldSchema) *Field {
 	f.IndexParams = KvPairsMap(p.GetIndexParams())
 	f.IsDynamic = p.GetIsDynamic()
 	f.IsPartitionKey = p.GetIsPartitionKey()
+	f.ElementType = FieldType(p.GetElementType())
 
 	return f
 }
@@ -339,6 +358,8 @@ func (t FieldType) Name() string {
 		return "String"
 	case FieldTypeVarChar:
 		return "VarChar"
+	case FieldTypeArray:
+		return "Array"
 	case FieldTypeJSON:
 		return "JSON"
 	case FieldTypeBinaryVector:
@@ -370,7 +391,9 @@ func (t FieldType) String() string {
 	case FieldTypeString:
 		return "string"
 	case FieldTypeVarChar:
-		return "string"
+		return "[]byte"
+	case FieldTypeArray:
+		return "Array"
 	case FieldTypeJSON:
 		return "JSON"
 	case FieldTypeBinaryVector:
@@ -402,7 +425,7 @@ func (t FieldType) PbFieldType() (string, string) {
 	case FieldTypeString:
 		return "String", "string"
 	case FieldTypeVarChar:
-		return "VarChar", "string"
+		return "Bytes", "[]byte"
 	case FieldTypeJSON:
 		return "JSON", "JSON"
 	case FieldTypeBinaryVector:
@@ -436,7 +459,8 @@ const (
 	FieldTypeString FieldType = 20
 	// FieldTypeVarChar field type varchar
 	FieldTypeVarChar FieldType = 21 // variable-length strings with a specified maximum length
-	// FieldTypeArray FieldType = 22
+	// FieldTypeArray field type Array
+	FieldTypeArray FieldType = 22
 	// FieldTypeJSON field type JSON
 	FieldTypeJSON FieldType = 23
 	// FieldTypeBinaryVector field type binary vector
diff --git a/examples/array/hello_array.go b/examples/array/hello_array.go
new file mode 100644
index 0000000..a89b511
--- /dev/null
+++ b/examples/array/hello_array.go
@@ -0,0 +1,216 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"math/rand"
+	"time"
+
+	"github.com/milvus-io/milvus-sdk-go/v2/client"
+	"github.com/milvus-io/milvus-sdk-go/v2/entity"
+)
+
+const (
+	milvusAddr     = `127.0.0.1:19530`
+	nEntities, dim = 3000, 128
+	collectionName = "hello_array"
+
+	msgFmt                         = "==== %s ====\n"
+	idCol, randomCol, embeddingCol = "ID", "random", "embeddings"
+	topK                           = 3
+)
+
+func main() {
+	ctx := context.Background()
+
+	log.Printf(msgFmt, "start connecting to Milvus")
+	c, err := client.NewClient(ctx, client.Config{
+		Address: milvusAddr,
+	})
+	if err != nil {
+		log.Fatal("failed to connect to milvus, err: ", err.Error())
+	}
+	defer c.Close()
+
+	// delete collection if exists
+	has, err := c.HasCollection(ctx, collectionName)
+	if err != nil {
+		log.Fatalf("failed to check collection exists, err: %v", err)
+	}
+	if has {
+		c.DropCollection(ctx, collectionName)
+	}
+
+	// create collection
+	log.Printf(msgFmt, fmt.Sprintf("create collection, `%s`", collectionName))
+	schema := entity.NewSchema().WithName(collectionName).WithDescription("hello_array is the simplest demo to introduce the APIs").
+		WithField(entity.NewField().WithName(idCol).WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true).WithIsAutoID(false)).
+		WithField(entity.NewField().WithName(randomCol).WithDataType(entity.FieldTypeArray).WithElementType(entity.FieldTypeDouble).WithMaxCapacity(10)).
+		WithField(entity.NewField().WithName(embeddingCol).WithDataType(entity.FieldTypeFloatVector).WithDim(dim))
+
+	if err := c.CreateCollection(ctx, schema, entity.DefaultShardNumber); err != nil { // use default shard number
+		log.Fatalf("create collection failed, err: %v", err)
+	}
+
+	// insert data
+	log.Printf(msgFmt, "start inserting random entities")
+	idList, randomList := make([]int64, 0, nEntities), make([][]float64, 0, nEntities)
+	embeddingList := make([][]float32, 0, nEntities)
+
+	rand.Seed(time.Now().UnixNano())
+
+	// generate data
+	for i := 0; i < nEntities; i++ {
+		idList = append(idList, int64(i))
+	}
+	for i := 0; i < nEntities; i++ {
+		data := make([]float64, 0, 10)
+		for j := 0; j < 10; j++ {
+			data = append(data, rand.Float64())
+		}
+		randomList = append(randomList, data)
+	}
+	for i := 0; i < nEntities; i++ {
+		vec := make([]float32, 0, dim)
+		for j := 0; j < dim; j++ {
+			vec = append(vec, rand.Float32())
+		}
+		embeddingList = append(embeddingList, vec)
+	}
+	idColData := entity.NewColumnInt64(idCol, idList)
+	randomColData := entity.NewColumnDoubleArray(randomCol, randomList)
+	embeddingColData := entity.NewColumnFloatVector(embeddingCol, dim, embeddingList)
+
+	if _, err := c.Insert(ctx, collectionName, "", idColData, randomColData, embeddingColData); err != nil {
+		log.Fatalf("failed to insert random data into `hello_array, err: %v", err)
+	}
+
+	if err := c.Flush(ctx, collectionName, false); err != nil {
+		log.Fatalf("failed to flush data, err: %v", err)
+	}
+
+	// build index
+	log.Printf(msgFmt, "start creating index IVF_FLAT")
+	idx, err := entity.NewIndexIvfFlat(entity.L2, 128)
+	if err != nil {
+		log.Fatalf("failed to create ivf flat index, err: %v", err)
+	}
+	if err := c.CreateIndex(ctx, collectionName, embeddingCol, idx, false); err != nil {
+		log.Fatalf("failed to create index, err: %v", err)
+	}
+
+	log.Printf(msgFmt, "start loading collection")
+	err = c.LoadCollection(ctx, collectionName, false)
+	if err != nil {
+		log.Fatalf("failed to load collection, err: %v", err)
+	}
+
+	log.Printf(msgFmt, "start searcching based on vector similarity")
+	vec2search := []entity.Vector{
+		entity.FloatVector(embeddingList[len(embeddingList)-2]),
+		entity.FloatVector(embeddingList[len(embeddingList)-1]),
+	}
+	begin := time.Now()
+	sp, _ := entity.NewIndexIvfFlatSearchParam(16)
+	sRet, err := c.Search(ctx, collectionName, nil, "", []string{randomCol}, vec2search,
+		embeddingCol, entity.L2, topK, sp)
+	end := time.Now()
+	if err != nil {
+		log.Fatalf("failed to search collection, err: %v", err)
+	}
+
+	log.Println("results:")
+	for _, res := range sRet {
+		printResult(&res)
+	}
+	log.Printf("\tsearch latency: %dms\n", end.Sub(begin)/time.Millisecond)
+
+	// hybrid search
+	log.Printf(msgFmt, "start hybrid searching with `random[0] > 0.5`")
+	begin = time.Now()
+	sRet2, err := c.Search(ctx, collectionName, nil, "random[0] > 0.5",
+		[]string{randomCol}, vec2search, embeddingCol, entity.L2, topK, sp)
+	end = time.Now()
+	if err != nil {
+		log.Fatalf("failed to search collection, err: %v", err)
+	}
+	log.Println("results:")
+	for _, res := range sRet2 {
+		printResult(&res)
+	}
+	log.Printf("\tsearch latency: %dms\n", end.Sub(begin)/time.Millisecond)
+
+	// delete data
+	log.Printf(msgFmt, "start deleting with expr ``")
+	pks := entity.NewColumnInt64(idCol, []int64{0, 1})
+	sRet3, err := c.QueryByPks(ctx, collectionName, nil, pks, []string{randomCol})
+	if err != nil {
+		log.Fatalf("failed to query result, err: %v", err)
+	}
+	log.Println("results:")
+	idlist := make([]int64, 0)
+	randList := make([][]float64, 0)
+
+	for _, col := range sRet3 {
+		if col.Name() == idCol {
+			idColumn := col.(*entity.ColumnInt64)
+			for i := 0; i < col.Len(); i++ {
+				val, err := idColumn.ValueByIdx(i)
+				if err != nil {
+					log.Fatal(err)
+				}
+				idlist = append(idlist, val)
+			}
+		} else {
+			randColumn := col.(*entity.ColumnDoubleArray)
+			for i := 0; i < col.Len(); i++ {
+				val, err := randColumn.ValueByIdx(i)
+				if err != nil {
+					log.Fatal(err)
+				}
+				randList = append(randList, val)
+			}
+		}
+	}
+	log.Printf("\tids: %#v, randoms: %#v\n", idlist, randList)
+
+	if err := c.DeleteByPks(ctx, collectionName, "", pks); err != nil {
+		log.Fatalf("failed to delete by pks, err: %v", err)
+	}
+	_, err = c.QueryByPks(ctx, collectionName, nil, pks, []string{randomCol}, client.WithSearchQueryConsistencyLevel(entity.ClStrong))
+	if err != nil {
+		log.Printf("failed to query result, err: %v", err)
+	}
+
+	// drop collection
+	log.Printf(msgFmt, "drop collection `hello_array`")
+	if err := c.DropCollection(ctx, collectionName); err != nil {
+		log.Fatalf("failed to drop collection, err: %v", err)
+	}
+}
+
+func printResult(sRet *client.SearchResult) {
+	randoms := make([][]float64, 0, sRet.ResultCount)
+	scores := make([]float32, 0, sRet.ResultCount)
+
+	var randCol *entity.ColumnDoubleArray
+	for _, field := range sRet.Fields {
+		fmt.Println(field.Name())
+		if field.Name() == randomCol {
+			c, ok := field.(*entity.ColumnDoubleArray)
+			if ok {
+				randCol = c
+			}
+		}
+	}
+	for i := 0; i < sRet.ResultCount; i++ {
+		val, err := randCol.ValueByIdx(i)
+		if err != nil {
+			log.Fatal(err)
+		}
+		randoms = append(randoms, val)
+		scores = append(scores, sRet.Scores[i])
+	}
+	log.Printf("\trandoms: %v, scores: %v\n", randoms, scores)
+}
diff --git a/go.mod b/go.mod
index c112438..d46d85c 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/go-faker/faker/v4 v4.1.0
 	github.com/golang/protobuf v1.5.2
 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
-	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.1
+	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.2
 	github.com/stretchr/testify v1.8.1
 	github.com/tidwall/gjson v1.14.4
 	google.golang.org/grpc v1.48.0
diff --git a/go.sum b/go.sum
index db65e64..1ff670a 100644
--- a/go.sum
+++ b/go.sum
@@ -159,6 +159,8 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i
 github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
 github.com/milvus-io/milvus-proto/go-api/v2 v2.3.1 h1:4qD1QJN6jDdote1UAZbEQoxKcH399oVod1GtiBYWQtQ=
 github.com/milvus-io/milvus-proto/go-api/v2 v2.3.1/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
+github.com/milvus-io/milvus-proto/go-api/v2 v2.3.2 h1:tBcKiEUcX6i3MaFYvMJO1F7R6fIoeLFkg1kSGE1Tvpk=
+github.com/milvus-io/milvus-proto/go-api/v2 v2.3.2/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
diff --git a/mocks/MilvusServiceServer.go b/mocks/MilvusServiceServer.go
index 28dc6bf..f7b887a 100644
--- a/mocks/MilvusServiceServer.go
+++ b/mocks/MilvusServiceServer.go
@@ -3877,6 +3877,61 @@ func (_c *MilvusServiceServer_RenameCollection_Call) RunAndReturn(run func(conte
 	return _c
 }
 
+// ReplicateMessage provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) ReplicateMessage(_a0 context.Context, _a1 *milvuspb.ReplicateMessageRequest) (*milvuspb.ReplicateMessageResponse, error) {
+	ret := _m.Called(_a0, _a1)
+
+	var r0 *milvuspb.ReplicateMessageResponse
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ReplicateMessageRequest) (*milvuspb.ReplicateMessageResponse, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ReplicateMessageRequest) *milvuspb.ReplicateMessageResponse); ok {
+		r0 = rf(_a0, _a1)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*milvuspb.ReplicateMessageResponse)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.ReplicateMessageRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_ReplicateMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplicateMessage'
+type MilvusServiceServer_ReplicateMessage_Call struct {
+	*mock.Call
+}
+
+// ReplicateMessage is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.ReplicateMessageRequest
+func (_e *MilvusServiceServer_Expecter) ReplicateMessage(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_ReplicateMessage_Call {
+	return &MilvusServiceServer_ReplicateMessage_Call{Call: _e.mock.On("ReplicateMessage", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_ReplicateMessage_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.ReplicateMessageRequest)) *MilvusServiceServer_ReplicateMessage_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.ReplicateMessageRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_ReplicateMessage_Call) Return(_a0 *milvuspb.ReplicateMessageResponse, _a1 error) *MilvusServiceServer_ReplicateMessage_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_ReplicateMessage_Call) RunAndReturn(run func(context.Context, *milvuspb.ReplicateMessageRequest) (*milvuspb.ReplicateMessageResponse, error)) *MilvusServiceServer_ReplicateMessage_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // Search provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) Search(_a0 context.Context, _a1 *milvuspb.SearchRequest) (*milvuspb.SearchResults, error) {
 	ret := _m.Called(_a0, _a1)


Test patch:
diff --git a/client/admin_test.go b/client/admin_test.go
new file mode 100644
index 0000000..ca70d1b
--- /dev/null
+++ b/client/admin_test.go
@@ -0,0 +1,57 @@
+package client
+
+import (
+	"context"
+	"testing"
+
+	"github.com/golang/protobuf/proto"
+	common "github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
+	server "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
+	"github.com/milvus-io/milvus-sdk-go/v2/entity"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCheckHealth(t *testing.T) {
+	ctx := context.Background()
+	c := testClient(ctx, t)
+	defer c.Close()
+
+	t.Run("test milvus healthy", func(t *testing.T) {
+		mockServer.SetInjection(MCheckHealth, func(ctx context.Context, message proto.Message) (proto.Message, error) {
+			resp := &server.CheckHealthResponse{
+				Status:      &common.Status{ErrorCode: common.ErrorCode_Success},
+				IsHealthy:   true,
+				Reasons:     nil,
+				QuotaStates: nil,
+			}
+			return resp, nil
+		})
+		defer mockServer.DelInjection(MCheckHealth)
+
+		resp, err := c.CheckHealth(ctx)
+		assert.Nil(t, err)
+		assert.True(t, resp.IsHealthy)
+		assert.Empty(t, resp.Reasons)
+		assert.Empty(t, resp.QuotaStates)
+	})
+
+	t.Run("test milvus unhealthy", func(t *testing.T) {
+		mockServer.SetInjection(MCheckHealth, func(ctx context.Context, message proto.Message) (proto.Message, error) {
+			resp := &server.CheckHealthResponse{
+				Status:      &common.Status{ErrorCode: common.ErrorCode_Success},
+				IsHealthy:   false,
+				Reasons:     []string{"some reason"},
+				QuotaStates: []server.QuotaState{server.QuotaState_DenyToRead, server.QuotaState_DenyToWrite},
+			}
+			return resp, nil
+		})
+		defer mockServer.DelInjection(MCheckHealth)
+
+		resp, err := c.CheckHealth(ctx)
+		assert.Nil(t, err)
+		assert.False(t, resp.IsHealthy)
+		assert.ElementsMatch(t, resp.Reasons, []string{"some reason"})
+		assert.ElementsMatch(t, resp.QuotaStates, []entity.QuotaState{entity.QuotaStateDenyToRead, entity.QuotaStateDenyToWrite})
+	})
+
+}
diff --git a/client/client_mock_test.go b/client/client_mock_test.go
index 0b3cdbd..cb0c1bd 100644
--- a/client/client_mock_test.go
+++ b/client/client_mock_test.go
@@ -924,6 +924,10 @@ func (m *MockServer) AllocTimestamp(_ context.Context, _ *milvuspb.AllocTimestam
 	panic("not implemented")
 }
 
+func (m *MockServer) ReplicateMessage(_ context.Context, _ *milvuspb.ReplicateMessageRequest) (*milvuspb.ReplicateMessageResponse, error) {
+	panic("not implemented")
+}
+
 func (m *MockServer) Connect(_ context.Context, _ *milvuspb.ConnectRequest) (*milvuspb.ConnectResponse, error) {
 	return &milvuspb.ConnectResponse{
 		Status:     &commonpb.Status{ErrorCode: commonpb.ErrorCode_Success},
diff --git a/client/data_test.go b/client/data_test.go
index 0e787b6..aff3bb9 100644
--- a/client/data_test.go
+++ b/client/data_test.go
@@ -1178,3 +1178,42 @@ func TestVector2PlaceHolder(t *testing.T) {
 		}
 	})
 }
+
+type WildcardSuite struct {
+	suite.Suite
+
+	schema *entity.Schema
+}
+
+func (s *WildcardSuite) SetupTest() {
+	s.schema = entity.NewSchema().
+		WithField(entity.NewField().WithName("pk").WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)).
+		WithField(entity.NewField().WithName("attr").WithDataType(entity.FieldTypeInt64)).
+		WithField(entity.NewField().WithName("$meta").WithDataType(entity.FieldTypeJSON).WithIsDynamic(true)).
+		WithField(entity.NewField().WithName("vector").WithDataType(entity.FieldTypeFloatVector).WithDim(128))
+}
+
+func (s *WildcardSuite) TestExpandWildcard() {
+	type testCase struct {
+		tag    string
+		input  []string
+		expect []string
+	}
+
+	cases := []testCase{
+		{tag: "normal", input: []string{"pk", "attr"}, expect: []string{"pk", "attr"}},
+		{tag: "with_wildcard", input: []string{"*"}, expect: []string{"pk", "attr", "$meta", "vector"}},
+		{tag: "wildcard_dynamic", input: []string{"*", "a"}, expect: []string{"pk", "attr", "$meta", "vector", "a"}},
+	}
+
+	for _, tc := range cases {
+		s.Run(tc.tag, func() {
+			output := expandWildcard(s.schema, tc.input)
+			s.ElementsMatch(tc.expect, output)
+		})
+	}
+}
+
+func TestExpandWildcard(t *testing.T) {
+	suite.Run(t, new(WildcardSuite))
+}
diff --git a/entity/columns_varchar_test.go b/entity/columns_varchar_test.go
index 46a8835..4913554 100644
--- a/entity/columns_varchar_test.go
+++ b/entity/columns_varchar_test.go
@@ -21,10 +21,10 @@ func TestColumnVarChar(t *testing.T) {
 	t.Run("test meta", func(t *testing.T) {
 		ft := FieldTypeVarChar
 		assert.Equal(t, "VarChar", ft.Name())
-		assert.Equal(t, "string", ft.String())
+		assert.Equal(t, "[]byte", ft.String())
 		pbName, pbType := ft.PbFieldType()
-		assert.Equal(t, "VarChar", pbName)
-		assert.Equal(t, "string", pbType)
+		assert.Equal(t, "Bytes", pbName)
+		assert.Equal(t, "[]byte", pbType)
 	})
 
 	t.Run("test column attribute", func(t *testing.T) {
diff --git a/entity/schema_test.go b/entity/schema_test.go
index a73b5d5..07d07de 100644
--- a/entity/schema_test.go
+++ b/entity/schema_test.go
@@ -25,6 +25,7 @@ func TestFieldSchema(t *testing.T) {
 		NewField().WithName("int_field").WithDataType(FieldTypeInt64).WithIsAutoID(true).WithIsPrimaryKey(true).WithDescription("int_field desc"),
 		NewField().WithName("string_field").WithDataType(FieldTypeString).WithIsAutoID(false).WithIsPrimaryKey(true).WithIsDynamic(false).WithTypeParams("max_len", "32").WithDescription("string_field desc"),
 		NewField().WithName("partition_key").WithDataType(FieldTypeInt32).WithIsPartitionKey(true),
+		NewField().WithName("array_field").WithDataType(FieldTypeArray).WithElementType(FieldTypeBool).WithMaxCapacity(128),
 		/*
 			NewField().WithName("default_value_bool").WithDataType(FieldTypeBool).WithDefaultValueBool(true),
 			NewField().WithName("default_value_int").WithDataType(FieldTypeInt32).WithDefaultValueInt(1),
@@ -45,6 +46,7 @@ func TestFieldSchema(t *testing.T) {
 		assert.Equal(t, field.IsDynamic, fieldSchema.GetIsDynamic())
 		assert.Equal(t, field.Description, fieldSchema.GetDescription())
 		assert.Equal(t, field.TypeParams, KvPairsMap(fieldSchema.GetTypeParams()))
+		assert.EqualValues(t, field.ElementType, fieldSchema.GetElementType())
 		// marshal & unmarshal, still equals
 		nf := &Field{}
 		nf = nf.ReadProto(fieldSchema)
@@ -57,6 +59,7 @@ func TestFieldSchema(t *testing.T) {
 		assert.Equal(t, field.IsDynamic, nf.IsDynamic)
 		assert.Equal(t, field.IsPartitionKey, nf.IsPartitionKey)
 		assert.EqualValues(t, field.TypeParams, nf.TypeParams)
+		assert.EqualValues(t, field.ElementType, nf.ElementType)
 	}
 
 	assert.NotPanics(t, func() {
diff --git a/test/testcases/search_test.go b/test/testcases/search_test.go
index ffaddc2..7f4ea91 100644
--- a/test/testcases/search_test.go
+++ b/test/testcases/search_test.go
@@ -1099,8 +1099,7 @@ func TestSearchScannAllMetricsWithRawData(t *testing.T) {
 				sp,
 			)
 			common.CheckErr(t, errSearch, true)
-			// TODO output_fields include * ???
-			common.CheckOutputFields(t, resSearch[0].Fields, []string{"*", common.DefaultIntFieldName, common.DefaultFloatFieldName,
+			common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName,
 				common.DefaultJSONFieldName, common.DefaultFloatVecFieldName})
 			common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
 		}
@@ -1148,8 +1147,7 @@ func TestRangeSearchScannL2(t *testing.T) {
 	// verify error nil, output all fields, range score
 	common.CheckErr(t, errSearch, true)
 	common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
-	// TODO output_fields include * ??? https://github.com/milvus-io/milvus-sdk-go/issues/596
-	common.CheckOutputFields(t, resSearch[0].Fields, []string{"*", common.DefaultIntFieldName, common.DefaultFloatFieldName,
+	common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName,
 		common.DefaultJSONFieldName, common.DefaultFloatVecFieldName})
 	for _, s := range resSearch[0].Scores {
 		require.GreaterOrEqual(t, s, float32(15.0))
@@ -1208,8 +1206,7 @@ func TestRangeSearchScannIPCosine(t *testing.T) {
 		// verify error nil, output all fields, range score
 		common.CheckErr(t, errSearch, true)
 		common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
-		// TODO output_fields include * ??? https://github.com/milvus-io/milvus-sdk-go/issues/596
-		common.CheckOutputFields(t, resSearch[0].Fields, []string{"*", common.DefaultIntFieldName, common.DefaultFloatFieldName,
+		common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName,
 			common.DefaultJSONFieldName, common.DefaultFloatVecFieldName})
 		for _, s := range resSearch[0].Scores {
 			require.GreaterOrEqual(t, s, float32(0))
@@ -1270,8 +1267,7 @@ func TestRangeSearchScannBinary(t *testing.T) {
 		// verify error nil, output all fields, range score
 		common.CheckErr(t, errSearch, true)
 		common.CheckSearchResult(t, resSearch, 1, common.DefaultTopK)
-		// TODO output_fields include * ??? https://github.com/milvus-io/milvus-sdk-go/issues/596
-		common.CheckOutputFields(t, resSearch[0].Fields, []string{"*", common.DefaultIntFieldName, common.DefaultFloatFieldName, common.DefaultBinaryVecFieldName})
+		common.CheckOutputFields(t, resSearch[0].Fields, []string{common.DefaultIntFieldName, common.DefaultFloatFieldName, common.DefaultBinaryVecFieldName})
 		for _, s := range resSearch[0].Scores {
 			require.GreaterOrEqual(t, s, float32(0))
 			require.Less(t, s, float32(100))