Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Geospatial Data Type and GIS Function Support for milvus #37417

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions client/column/columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ func FieldDataColumn(fd *schemapb.FieldData, begin, end int) (Column, error) {
}
return NewColumnJSONBytes(fd.GetFieldName(), data.JsonData.GetData()[begin:end]).WithIsDynamic(isDynamic), nil

case schemapb.DataType_Geometry:
data, ok := fd.GetScalars().GetData().(*schemapb.ScalarField_GeometryData)
if !ok {
return nil, errFieldDataTypeNotMatch
}
if end < 0 {
return NewColumnGeometryBytes(fd.GetFieldName(), data.GeometryData.GetData()[begin:]), nil
}
return NewColumnGeometryBytes(fd.GetFieldName(), data.GeometryData.GetData()[begin:end]), nil

case schemapb.DataType_FloatVector:
vectors := fd.GetVectors()
x, ok := vectors.GetData().(*schemapb.VectorField_FloatVector)
Expand Down Expand Up @@ -524,6 +534,8 @@ func DefaultValueColumn(name string, dataType entity.FieldType) (Column, error)
return NewColumnVarChar(name, nil), nil
case entity.FieldTypeJSON:
return NewColumnJSONBytes(name, nil), nil
case entity.FieldTypeGeometry:
return NewColumnGeometryBytes(name, nil), nil

default:
return nil, fmt.Errorf("default value unsupported data type %s", dataType)
Expand Down
118 changes: 118 additions & 0 deletions client/column/geometry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package column

import (
"fmt"

"github.com/cockroachdb/errors"

"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/client/v2/entity"
)

type ColumnGeometryBytes struct {
ColumnBase
name string
values [][]byte
}

// Name returns column name.
func (c *ColumnGeometryBytes) Name() string {
return c.name
}

// Type returns column entity.FieldType.
func (c *ColumnGeometryBytes) Type() entity.FieldType {
return entity.FieldTypeGeometry
}

// Len returns column values length.
func (c *ColumnGeometryBytes) Len() int {
return len(c.values)
}

func (c *ColumnGeometryBytes) Slice(start, end int) Column {
l := c.Len()
if start > l {
start = l
}
if end == -1 || end > l {
end = l
}
return &ColumnGeometryBytes{
ColumnBase: c.ColumnBase,
name: c.name,
values: c.values[start:end],
}
}

// Get returns value at index as interface{}.
func (c *ColumnGeometryBytes) Get(idx int) (interface{}, error) {
if idx < 0 || idx > c.Len() {
return nil, errors.New("index out of range")
}
return c.values[idx], nil
}

func (c *ColumnGeometryBytes) GetAsString(idx int) (string, error) {
bs, err := c.ValueByIdx(idx)
if err != nil {
return "", err
}
return string(bs), nil
}

// FieldData return column data mapped to schemapb.FieldData.
func (c *ColumnGeometryBytes) FieldData() *schemapb.FieldData {
fd := &schemapb.FieldData{
Type: schemapb.DataType_Geometry,
FieldName: c.name,
}

fd.Field = &schemapb.FieldData_Scalars{
Scalars: &schemapb.ScalarField{
Data: &schemapb.ScalarField_GeometryData{
GeometryData: &schemapb.GeometryArray{
Data: c.values,
},
},
},
}

return fd
}

// ValueByIdx returns value of the provided index.
func (c *ColumnGeometryBytes) ValueByIdx(idx int) ([]byte, error) {
if idx < 0 || idx >= c.Len() {
return nil, errors.New("index out of range")
}
return c.values[idx], nil
}

// AppendValue append value into column.
func (c *ColumnGeometryBytes) AppendValue(i interface{}) error {
var v []byte
switch raw := i.(type) {
case []byte:
v = raw
case string:
v = []byte(raw)
default:
return fmt.Errorf("expect geometry compatible type([]byte, struct, map), got %T", i)
}
c.values = append(c.values, v)

return nil
}

// Data returns column data.
func (c *ColumnGeometryBytes) Data() [][]byte {
return c.values
}

func NewColumnGeometryBytes(name string, values [][]byte) *ColumnGeometryBytes {
return &ColumnGeometryBytes{
name: name,
values: values,
}
}
82 changes: 82 additions & 0 deletions client/column/geometry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package column

import (
"fmt"
"math/rand"
"testing"
"time"

"github.com/stretchr/testify/suite"

"github.com/milvus-io/milvus/client/v2/entity"
)

type ColumnGeometryBytesSuite struct {
suite.Suite
}

func (s *ColumnGeometryBytesSuite) SetupSuite() {
rand.Seed(time.Now().UnixNano())
}

func (s *ColumnGeometryBytesSuite) TestAttrMethods() {
columnName := fmt.Sprintf("column_Geometrybs_%d", rand.Int())
columnLen := 8 + rand.Intn(10)

v := make([][]byte, columnLen)
column := NewColumnGeometryBytes(columnName, v)

s.Run("test_meta", func() {
ft := entity.FieldTypeGeometry
s.Equal("Geometry", ft.Name())
s.Equal("Geometry", ft.String())
pbName, pbType := ft.PbFieldType()
s.Equal("Geometry", pbName)
s.Equal("Geometry", pbType)
})

s.Run("test_column_attribute", func() {
s.Equal(columnName, column.Name())
s.Equal(entity.FieldTypeGeometry, column.Type())
s.Equal(columnLen, column.Len())
s.EqualValues(v, column.Data())
})

s.Run("test_column_field_data", func() {
fd := column.FieldData()
s.NotNil(fd)
s.Equal(fd.GetFieldName(), columnName)
})

s.Run("test_column_valuer_by_idx", func() {
_, err := column.ValueByIdx(-1)
s.Error(err)
_, err = column.ValueByIdx(columnLen)
s.Error(err)
for i := 0; i < columnLen; i++ {
v, err := column.ValueByIdx(i)
s.NoError(err)
s.Equal(column.values[i], v)
}
})

s.Run("test_append_value", func() {
item := make([]byte, 10)
err := column.AppendValue(item)
s.NoError(err)
s.Equal(columnLen+1, column.Len())
val, err := column.ValueByIdx(columnLen)
s.NoError(err)
s.Equal(item, val)

err = column.AppendValue("POINT (30.123 -10.456)")
s.NoError(err)

err = column.AppendValue(1)
s.Error(err)
})
}

func TestColumnGeometryBytes(t *testing.T) {
suite.Run(t, new(ColumnGeometryBytesSuite))
}
8 changes: 8 additions & 0 deletions client/entity/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func (t FieldType) Name() string {
return "Array"
case FieldTypeJSON:
return "JSON"
case FieldTypeGeometry:
return "Geometry"
case FieldTypeBinaryVector:
return "BinaryVector"
case FieldTypeFloatVector:
Expand Down Expand Up @@ -92,6 +94,8 @@ func (t FieldType) String() string {
return "Array"
case FieldTypeJSON:
return "JSON"
case FieldTypeGeometry:
return "Geometry"
case FieldTypeBinaryVector:
return "[]byte"
case FieldTypeFloatVector:
Expand Down Expand Up @@ -128,6 +132,8 @@ func (t FieldType) PbFieldType() (string, string) {
return "VarChar", "string"
case FieldTypeJSON:
return "JSON", "JSON"
case FieldTypeGeometry:
return "Geometry", "Geometry"
case FieldTypeBinaryVector:
return "[]byte", ""
case FieldTypeFloatVector:
Expand Down Expand Up @@ -167,6 +173,8 @@ const (
FieldTypeArray FieldType = 22
// FieldTypeJSON field type JSON
FieldTypeJSON FieldType = 23
// FieldTypeGeometry field type Geometry
FieldTypeGeometry FieldType = 24
// FieldTypeBinaryVector field type binary vector
FieldTypeBinaryVector FieldType = 100
// FieldTypeFloatVector field type float vector
Expand Down
16 changes: 16 additions & 0 deletions client/milvusclient/client_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ func (s *MockSuiteBase) getJSONBytesFieldData(name string, data [][]byte, isDyna
}
}

func (s *MockSuiteBase) getGeometryBytesFieldData(name string, data [][]byte) *schemapb.FieldData {
return &schemapb.FieldData{
Type: schemapb.DataType_Geometry,
FieldName: name,
Field: &schemapb.FieldData_Scalars{
Scalars: &schemapb.ScalarField{
Data: &schemapb.ScalarField_GeometryData{
GeometryData: &schemapb.GeometryArray{
Data: data,
},
},
},
},
}
}

func (s *MockSuiteBase) getFloatVectorFieldData(name string, dim int64, data []float32) *schemapb.FieldData {
return &schemapb.FieldData{
Type: schemapb.DataType_FloatVector,
Expand Down
4 changes: 4 additions & 0 deletions client/row/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ func AnyToColumns(rows []interface{}, schemas ...*entity.Schema) ([]column.Colum
data := make([][]byte, 0, rowsLen)
col := column.NewColumnJSONBytes(field.Name, data)
nameColumns[field.Name] = col
case entity.FieldTypeGeometry:
data := make([][]byte, 0, rowsLen)
col := column.NewColumnGeometryBytes(field.Name, data)
nameColumns[field.Name] = col
case entity.FieldTypeArray:
col := NewArrayColumn(field)
if col == nil {
Expand Down
Loading
Loading