feat: impl StructArray -- ban non-float-vector for now (#44875)

ref https://github.com/milvus-io/milvus/issues/42148

---------

Signed-off-by: SpadeA <tangchenjie1210@gmail.com>
This commit is contained in:
Spade A 2025-10-17 10:26:09 +08:00 committed by GitHub
parent 633cae9461
commit 6c8e353439
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 23 deletions

View File

@ -664,9 +664,14 @@ func ValidateFieldsInStruct(field *schemapb.FieldSchema, schema *schemapb.Collec
return fmt.Errorf("Inconsistent schema: element type of array field %s is a vector type", field.Name) return fmt.Errorf("Inconsistent schema: element type of array field %s is a vector type", field.Name)
} }
} else { } else {
if !typeutil.IsVectorType(field.GetElementType()) { // TODO(SpadeA): only support float vector now
return fmt.Errorf("Inconsistent schema: element type of array field %s is not a vector type", field.Name) if field.GetElementType() != schemapb.DataType_FloatVector {
return fmt.Errorf("Unsupported element type of array field %s, now only float vector is supported", field.Name)
} }
// if !typeutil.IsVectorType(field.GetElementType()) {
// return fmt.Errorf("Inconsistent schema: element type of array field %s is not a vector type", field.Name)
// }
err = validateDimension(field) err = validateDimension(field)
if err != nil { if err != nil {
return err return err

View File

@ -3957,7 +3957,7 @@ func TestValidateFieldsInStruct(t *testing.T) {
} }
err := ValidateFieldsInStruct(field, schema) err := ValidateFieldsInStruct(field, schema)
assert.Error(t, err) assert.Error(t, err)
assert.Contains(t, err.Error(), "element type of array field array_vector_with_scalar is not a vector type") assert.Contains(t, err.Error(), "Unsupported element type of array field array_vector_with_scalar, now only float vector is supported")
}) })
t.Run("array of vector missing dimension", func(t *testing.T) { t.Run("array of vector missing dimension", func(t *testing.T) {
@ -4037,19 +4037,19 @@ func TestValidateFieldsInStruct(t *testing.T) {
assert.Contains(t, err.Error(), "nullable is not supported for fields in struct array now") assert.Contains(t, err.Error(), "nullable is not supported for fields in struct array now")
}) })
t.Run("sparse float vector in array of vector", func(t *testing.T) { // t.Run("sparse float vector in array of vector", func(t *testing.T) {
// Note: ArrayOfVector with sparse vector element type still requires dimension // // Note: ArrayOfVector with sparse vector element type still requires dimension
// because validateDimension checks the field's DataType (ArrayOfVector), not ElementType // // because validateDimension checks the field's DataType (ArrayOfVector), not ElementType
field := &schemapb.FieldSchema{ // field := &schemapb.FieldSchema{
Name: "sparse_vector_array", // Name: "sparse_vector_array",
DataType: schemapb.DataType_ArrayOfVector, // DataType: schemapb.DataType_ArrayOfVector,
ElementType: schemapb.DataType_SparseFloatVector, // ElementType: schemapb.DataType_SparseFloatVector,
TypeParams: []*commonpb.KeyValuePair{}, // TypeParams: []*commonpb.KeyValuePair{},
} // }
err := ValidateFieldsInStruct(field, schema) // err := ValidateFieldsInStruct(field, schema)
assert.Error(t, err) // assert.Error(t, err)
assert.Contains(t, err.Error(), "dimension is not defined") // assert.Contains(t, err.Error(), "dimension is not defined")
}) // })
t.Run("array with various scalar element types", func(t *testing.T) { t.Run("array with various scalar element types", func(t *testing.T) {
validScalarTypes := []schemapb.DataType{ validScalarTypes := []schemapb.DataType{
@ -4077,9 +4077,9 @@ func TestValidateFieldsInStruct(t *testing.T) {
t.Run("array of vector with various vector types", func(t *testing.T) { t.Run("array of vector with various vector types", func(t *testing.T) {
validVectorTypes := []schemapb.DataType{ validVectorTypes := []schemapb.DataType{
schemapb.DataType_FloatVector, schemapb.DataType_FloatVector,
schemapb.DataType_BinaryVector, // schemapb.DataType_BinaryVector,
schemapb.DataType_Float16Vector, // schemapb.DataType_Float16Vector,
schemapb.DataType_BFloat16Vector, // schemapb.DataType_BFloat16Vector,
// Note: SparseFloatVector is excluded because validateDimension checks // Note: SparseFloatVector is excluded because validateDimension checks
// the field's DataType (ArrayOfVector), not ElementType, so it still requires dimension // the field's DataType (ArrayOfVector), not ElementType, so it still requires dimension
} }

View File

@ -997,13 +997,14 @@ func (w *NativePayloadWriter) addFloatVectorArrayToPayload(builder *array.ListBu
floatData := vectorField.GetFloatVector().GetData() floatData := vectorField.GetFloatVector().GetData()
numVectors := len(floatData) / int(data.Dim) dim := vectorField.GetDim()
numVectors := len(floatData) / int(dim)
for i := 0; i < numVectors; i++ { for i := 0; i < numVectors; i++ {
start := i * int(data.Dim) start := i * int(dim)
end := start + int(data.Dim) end := start + int(dim)
vectorSlice := floatData[start:end] vectorSlice := floatData[start:end]
bytes := make([]byte, data.Dim*4) bytes := make([]byte, dim*4)
for j, f := range vectorSlice { for j, f := range vectorSlice {
binary.LittleEndian.PutUint32(bytes[j*4:], math.Float32bits(f)) binary.LittleEndian.PutUint32(bytes[j*4:], math.Float32bits(f))
} }