mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-07 09:38:39 +08:00
fix: Fix a bug that bulkimport cannot handle empty struct list (#45693)
issue: https://github.com/milvus-io/milvus/issues/42148 Signed-off-by: yhmo <yihua.mo@zilliz.com>
This commit is contained in:
parent
7078f403f1
commit
a545ebc702
@ -189,6 +189,15 @@ func (r *rowParser) reconstructArrayForStructArray(structName string, subFieldsM
|
|||||||
flatStructs[fieldName] = append(flatStructs[fieldName], value)
|
flatStructs[fieldName] = append(flatStructs[fieldName], value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct list can be empty, len(structs) can be zero
|
||||||
|
// fill flatStructs with empty list for each sub field if len(structs) is zero
|
||||||
|
if len(structs) == 0 {
|
||||||
|
for subFieldName := range subFieldsMap {
|
||||||
|
flatStructs[subFieldName] = make([]any, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return flatStructs, nil
|
return flatStructs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@ type rowParser struct {
|
|||||||
dynamicField *schemapb.FieldSchema
|
dynamicField *schemapb.FieldSchema
|
||||||
functionOutputFields map[string]int64
|
functionOutputFields map[string]int64
|
||||||
|
|
||||||
structArrays map[string]interface{}
|
structArrays map[string][]string
|
||||||
allowInsertAutoID bool
|
allowInsertAutoID bool
|
||||||
|
|
||||||
timezone string
|
timezone string
|
||||||
@ -89,10 +89,14 @@ func NewRowParser(schema *schemapb.CollectionSchema) (RowParser, error) {
|
|||||||
)
|
)
|
||||||
allowInsertAutoID, _ := pkgcommon.IsAllowInsertAutoID(schema.GetProperties()...)
|
allowInsertAutoID, _ := pkgcommon.IsAllowInsertAutoID(schema.GetProperties()...)
|
||||||
|
|
||||||
sturctArrays := lo.SliceToMap(
|
structArrays := lo.SliceToMap(
|
||||||
schema.GetStructArrayFields(),
|
schema.GetStructArrayFields(),
|
||||||
func(sa *schemapb.StructArrayFieldSchema) (string, interface{}) {
|
func(sa *schemapb.StructArrayFieldSchema) (string, []string) {
|
||||||
return sa.GetName(), nil
|
subFieldNames := lo.Map(sa.Fields, func(field *schemapb.FieldSchema, _ int) string {
|
||||||
|
fieldName, _ := typeutil.ExtractStructFieldName(field.GetName())
|
||||||
|
return fieldName
|
||||||
|
})
|
||||||
|
return sa.GetName(), subFieldNames
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -103,7 +107,7 @@ func NewRowParser(schema *schemapb.CollectionSchema) (RowParser, error) {
|
|||||||
pkField: pkField,
|
pkField: pkField,
|
||||||
dynamicField: dynamicField,
|
dynamicField: dynamicField,
|
||||||
functionOutputFields: functionOutputFields,
|
functionOutputFields: functionOutputFields,
|
||||||
structArrays: sturctArrays,
|
structArrays: structArrays,
|
||||||
allowInsertAutoID: allowInsertAutoID,
|
allowInsertAutoID: allowInsertAutoID,
|
||||||
timezone: common.GetSchemaTimezone(schema),
|
timezone: common.GetSchemaTimezone(schema),
|
||||||
}, nil
|
}, nil
|
||||||
@ -221,12 +225,20 @@ func (r *rowParser) Parse(raw any) (Row, error) {
|
|||||||
return nil, merr.WrapErrImportFailed(fmt.Sprintf("the field '%s' is output by function, no need to provide", key))
|
return nil, merr.WrapErrImportFailed(fmt.Sprintf("the field '%s' is output by function, no need to provide", key))
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.structArrays[key]; ok {
|
if subFieldNames, ok := r.structArrays[key]; ok {
|
||||||
values, err := reconstructArrayForStructArray(value)
|
values, err := reconstructArrayForStructArray(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a struct list can be empty, the values could be an empty map
|
||||||
|
// make an empty list for each sub field
|
||||||
|
if len(values) == 0 {
|
||||||
|
for i := 0; i < len(subFieldNames); i++ {
|
||||||
|
values[subFieldNames[i]] = make([]any, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for subKey, subValue := range values {
|
for subKey, subValue := range values {
|
||||||
// Pass struct name for sub-fields
|
// Pass struct name for sub-fields
|
||||||
if err := handleField(key, subKey, subValue); err != nil {
|
if err := handleField(key, subKey, subValue); err != nil {
|
||||||
|
|||||||
@ -103,10 +103,7 @@ func (r *StructFieldReader) Next(count int64) (any, any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *StructFieldReader) toScalarField(data []interface{}) (*schemapb.ScalarField, error) {
|
func (r *StructFieldReader) toScalarField(data []interface{}) (*schemapb.ScalarField, error) {
|
||||||
if len(data) == 0 {
|
// struct list can be empty, len(data) can be zero, build an empty ScalarField if len(data) is zero
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.field.GetElementType() {
|
switch r.field.GetElementType() {
|
||||||
case schemapb.DataType_Bool:
|
case schemapb.DataType_Bool:
|
||||||
boolData := make([]bool, len(data))
|
boolData := make([]bool, len(data))
|
||||||
@ -320,7 +317,9 @@ func (r *StructFieldReader) readArrayOfVectorField(chunked *arrow.Chunked) (any,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(allVectors) > 0 {
|
// struct list could be empty, len(allVectors) can be zero
|
||||||
|
// build an empty VectorField if len(allVectors) is zero
|
||||||
|
if len(allVectors) >= 0 {
|
||||||
vectorField := &schemapb.VectorField{
|
vectorField := &schemapb.VectorField{
|
||||||
Dim: int64(r.dim),
|
Dim: int64(r.dim),
|
||||||
Data: &schemapb.VectorField_FloatVector{
|
Data: &schemapb.VectorField_FloatVector{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user