github.com/weaviate/weaviate@v1.24.6/adapters/handlers/grpc/v1/batch_parse_request.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package v1 13 14 import ( 15 "fmt" 16 17 "github.com/go-openapi/strfmt" 18 "github.com/google/uuid" 19 "github.com/weaviate/weaviate/usecases/byteops" 20 21 "github.com/weaviate/weaviate/entities/models" 22 "github.com/weaviate/weaviate/entities/schema" 23 pb "github.com/weaviate/weaviate/grpc/generated/protocol/v1" 24 ) 25 26 const BEACON_START = "weaviate://localhost/" 27 28 func sliceToInterface[T any](values []T) []interface{} { 29 tmpArray := make([]interface{}, len(values)) 30 for k := range values { 31 tmpArray[k] = values[k] 32 } 33 return tmpArray 34 } 35 36 func batchFromProto(req *pb.BatchObjectsRequest, scheme schema.Schema) ([]*models.Object, map[int]int, map[int]error) { 37 objectsBatch := req.Objects 38 objs := make([]*models.Object, 0, len(objectsBatch)) 39 objOriginalIndex := make(map[int]int) 40 objectErrors := make(map[int]error, len(objectsBatch)) 41 42 insertCounter := 0 43 for i, obj := range objectsBatch { 44 class := scheme.GetClass(schema.ClassName(obj.Collection)) 45 var props map[string]interface{} 46 if obj.Properties != nil { 47 props = extractPrimitiveProperties(&pb.ObjectPropertiesValue{ 48 NonRefProperties: obj.Properties.NonRefProperties, 49 BooleanArrayProperties: obj.Properties.BooleanArrayProperties, 50 NumberArrayProperties: obj.Properties.NumberArrayProperties, 51 TextArrayProperties: obj.Properties.TextArrayProperties, 52 IntArrayProperties: obj.Properties.IntArrayProperties, 53 ObjectProperties: obj.Properties.ObjectProperties, 54 ObjectArrayProperties: obj.Properties.ObjectArrayProperties, 55 EmptyListProps: obj.Properties.EmptyListProps, 56 }) 57 if err := extractSingleRefTarget(class, obj.Properties.SingleTargetRefProps, props); err != nil { 58 objectErrors[i] = err 59 continue 60 } 61 if err := extractMultiRefTarget(class, obj.Properties.MultiTargetRefProps, props); err != nil { 62 objectErrors[i] = err 63 continue 64 } 65 } 66 67 _, err := uuid.Parse(obj.Uuid) 68 if err != nil { 69 objectErrors[i] = err 70 continue 71 } 72 73 var vector []float32 = nil 74 // bytes vector has precedent for being more efficient 75 if len(obj.VectorBytes) > 0 { 76 vector = byteops.Float32FromByteVector(obj.VectorBytes) 77 } else if len(obj.Vector) > 0 { 78 vector = obj.Vector 79 } 80 81 var vectors models.Vectors = nil 82 if len(obj.Vectors) > 0 { 83 vectors = make(models.Vectors, len(obj.Vectors)) 84 for _, vec := range obj.Vectors { 85 vectors[vec.Name] = byteops.Float32FromByteVector(vec.VectorBytes) 86 } 87 } 88 89 objOriginalIndex[insertCounter] = i 90 objs = append(objs, &models.Object{ 91 Class: obj.Collection, 92 Tenant: obj.Tenant, 93 Vector: vector, 94 Properties: props, 95 ID: strfmt.UUID(obj.Uuid), 96 Vectors: vectors, 97 }) 98 insertCounter += 1 99 } 100 return objs[:insertCounter], objOriginalIndex, objectErrors 101 } 102 103 func extractSingleRefTarget(class *models.Class, properties []*pb.BatchObject_SingleTargetRefProps, props map[string]interface{}) error { 104 for _, refSingle := range properties { 105 propName := refSingle.GetPropName() 106 prop, err := schema.GetPropertyByName(class, propName) 107 if err != nil { 108 return err 109 } 110 if len(prop.DataType) > 1 { 111 return fmt.Errorf("target is a multi-target reference, need single target %v", prop.DataType) 112 } 113 toClass := prop.DataType[0] 114 beacons := make([]interface{}, len(refSingle.Uuids)) 115 for j, uuid := range refSingle.Uuids { 116 beacons[j] = map[string]interface{}{"beacon": BEACON_START + toClass + "/" + uuid} 117 } 118 props[propName] = beacons 119 } 120 return nil 121 } 122 123 func extractMultiRefTarget(class *models.Class, properties []*pb.BatchObject_MultiTargetRefProps, props map[string]interface{}) error { 124 for _, refMulti := range properties { 125 propName := refMulti.GetPropName() 126 prop, err := schema.GetPropertyByName(class, propName) 127 if err != nil { 128 return err 129 } 130 if len(prop.DataType) < 2 { 131 return fmt.Errorf("target is a single-target reference, need multi-target %v", prop.DataType) 132 } 133 beacons := make([]interface{}, len(refMulti.Uuids)) 134 for j, uid := range refMulti.Uuids { 135 beacons[j] = map[string]interface{}{"beacon": BEACON_START + refMulti.TargetCollection + "/" + uid} 136 } 137 props[propName] = beacons 138 } 139 return nil 140 } 141 142 func extractPrimitiveProperties(properties *pb.ObjectPropertiesValue) map[string]interface{} { 143 var props map[string]interface{} 144 if properties.NonRefProperties != nil { 145 props = properties.NonRefProperties.AsMap() 146 } else { 147 props = make(map[string]interface{}) 148 } 149 150 // arrays cannot be part of a GRPC map, so we need to handle each type separately 151 for j := range properties.BooleanArrayProperties { 152 props[properties.BooleanArrayProperties[j].PropName] = sliceToInterface(properties.BooleanArrayProperties[j].Values) 153 } 154 155 for j := range properties.NumberArrayProperties { 156 inputValuesBytes := properties.NumberArrayProperties[j].ValuesBytes 157 var values []float64 158 159 if len(inputValuesBytes) > 0 { 160 values = byteops.Float64FromByteVector(inputValuesBytes) 161 } else { 162 values = properties.NumberArrayProperties[j].Values 163 } 164 165 props[properties.NumberArrayProperties[j].PropName] = sliceToInterface(values) 166 } 167 168 for j := range properties.TextArrayProperties { 169 props[properties.TextArrayProperties[j].PropName] = sliceToInterface(properties.TextArrayProperties[j].Values) 170 } 171 172 for j := range properties.IntArrayProperties { 173 props[properties.IntArrayProperties[j].PropName] = sliceToInterface(properties.IntArrayProperties[j].Values) 174 } 175 176 for j := range properties.ObjectProperties { 177 props[properties.ObjectProperties[j].PropName] = extractPrimitiveProperties(properties.ObjectProperties[j].Value) 178 } 179 180 for _, prop := range properties.ObjectArrayProperties { 181 nested := make([]interface{}, len(prop.Values)) 182 for k := range prop.Values { 183 nested[k] = extractPrimitiveProperties(prop.Values[k]) 184 } 185 props[prop.PropName] = nested 186 } 187 188 for _, propName := range properties.EmptyListProps { 189 props[propName] = []interface{}{} 190 } 191 192 return props 193 }