github.com/weaviate/weaviate@v1.24.6/entities/moduletools/vectorizable_props_comparator.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 moduletools 13 14 import ( 15 "sort" 16 17 "github.com/weaviate/weaviate/entities/models" 18 "github.com/weaviate/weaviate/entities/schema" 19 ) 20 21 type PropsComparatorFactory func() (VectorizablePropsComparator, error) 22 23 type VectorizablePropsComparator interface { 24 PropsIterator() VectorizablePropsIterator 25 IsChanged(propName string) bool 26 PrevVector() []float32 27 PrevVectorForName(targetVector string) []float32 28 } 29 30 func NewVectorizablePropsComparator(propsSchema []*models.Property, 31 nextProps, prevProps models.PropertySchema, prevVector []float32, 32 prevVectors models.Vectors, 33 ) VectorizablePropsComparator { 34 props, propsMap := extractVectorizablePropNames(propsSchema) 35 return &vectorizablePropsComparator{ 36 prevProps: notNilPropsMap(prevProps), 37 nextProps: notNilPropsMap(nextProps), 38 vectorizableProps: props, 39 vectorizablePropsMap: propsMap, 40 prevVector: prevVector, 41 prevVectors: prevVectors, 42 } 43 } 44 45 type vectorizablePropsComparator struct { 46 prevProps map[string]interface{} 47 nextProps map[string]interface{} 48 vectorizableProps []string 49 vectorizablePropsMap map[string]struct{} 50 prevVector []float32 51 prevVectors models.Vectors 52 } 53 54 func (c *vectorizablePropsComparator) PropsIterator() VectorizablePropsIterator { 55 return &vectorizablePropsIterator{pos: 0, vectorizable: c.vectorizableProps, props: c.nextProps} 56 } 57 58 func (c *vectorizablePropsComparator) IsChanged(propName string) bool { 59 // not vectorizable prop -> not changed 60 if _, ok := c.vectorizablePropsMap[propName]; !ok { 61 return false 62 } 63 64 prevVal := c.prevProps[propName] 65 nextVal := c.nextProps[propName] 66 67 // both nil / missing / empty array -> not changed 68 switch typedPrevVal := prevVal.(type) { 69 case nil: 70 if nextVal == nil { 71 return false 72 } 73 if arr, ok := nextVal.([]string); ok && len(arr) == 0 { 74 return false 75 } 76 return true 77 78 case string: 79 if typedNextVal, ok := nextVal.(string); ok { 80 return typedNextVal != typedPrevVal 81 } 82 return true 83 84 case []string: 85 switch typedNextVal := nextVal.(type) { 86 case nil: 87 return len(typedPrevVal) != 0 88 case []string: 89 if len(typedNextVal) != len(typedPrevVal) { 90 return true 91 } 92 for i := range typedNextVal { 93 if typedNextVal[i] != typedPrevVal[i] { 94 return true 95 } 96 } 97 return false 98 default: 99 return true 100 } 101 102 // unmarshalled empty array might be []interface{} instead of []string 103 case []interface{}: 104 switch typedNextVal := nextVal.(type) { 105 case nil: 106 return len(typedPrevVal) != 0 107 case []string: 108 return len(typedPrevVal) != 0 || len(typedNextVal) != 0 109 default: 110 return true 111 } 112 113 default: 114 // fallback (vectorizable types should be string/[]string) 115 return false 116 } 117 } 118 119 func (c *vectorizablePropsComparator) PrevVector() []float32 { 120 return c.prevVector 121 } 122 123 func (c *vectorizablePropsComparator) PrevVectorForName(targetVector string) []float32 { 124 if c.prevVectors != nil { 125 return c.prevVectors[targetVector] 126 } 127 return nil 128 } 129 130 func NewVectorizablePropsComparatorDummy(propsSchema []*models.Property, nextProps models.PropertySchema, 131 ) VectorizablePropsComparator { 132 props, propsMap := extractVectorizablePropNames(propsSchema) 133 return &vectorizablePropsComparatorDummy{ 134 nextProps: notNilPropsMap(nextProps), 135 vectorizableProps: props, 136 vectorizablePropsMap: propsMap, 137 } 138 } 139 140 type vectorizablePropsComparatorDummy struct { 141 nextProps map[string]interface{} 142 vectorizableProps []string 143 vectorizablePropsMap map[string]struct{} 144 } 145 146 func (c *vectorizablePropsComparatorDummy) PropsIterator() VectorizablePropsIterator { 147 return &vectorizablePropsIterator{pos: 0, vectorizable: c.vectorizableProps, props: c.nextProps} 148 } 149 150 func (c *vectorizablePropsComparatorDummy) IsChanged(propName string) bool { 151 // not vectorizable prop -> not changed 152 if _, ok := c.vectorizablePropsMap[propName]; !ok { 153 return false 154 } 155 156 switch typedNextVal := c.nextProps[propName].(type) { 157 case nil: 158 return false 159 160 case string: 161 return true 162 163 case []string: 164 return len(typedNextVal) != 0 165 166 default: 167 // fallback (vectorizable types should be string/[]string) 168 return false 169 } 170 } 171 172 func (c *vectorizablePropsComparatorDummy) PrevVector() []float32 { 173 return nil 174 } 175 176 func (c *vectorizablePropsComparatorDummy) PrevVectorForName(targetVector string) []float32 { 177 return nil 178 } 179 180 type VectorizablePropsIterator interface { 181 Next() (propName string, propValue interface{}, ok bool) 182 } 183 184 type vectorizablePropsIterator struct { 185 pos int 186 vectorizable []string 187 props map[string]interface{} 188 } 189 190 func (it *vectorizablePropsIterator) Next() (propName string, propValue interface{}, ok bool) { 191 if it.pos >= len(it.vectorizable) { 192 return "", nil, false 193 } 194 195 propName = it.vectorizable[it.pos] 196 it.pos++ 197 return propName, it.props[propName], true 198 } 199 200 func notNilPropsMap(props models.PropertySchema) map[string]interface{} { 201 if props != nil { 202 if propsMap, ok := props.(map[string]interface{}); ok { 203 return propsMap 204 } 205 } 206 return map[string]interface{}{} 207 } 208 209 func extractVectorizablePropNames(propsSchema []*models.Property) ([]string, map[string]struct{}) { 210 props := make([]string, 0, len(propsSchema)) 211 propsMap := make(map[string]struct{}) 212 213 for _, propSchema := range propsSchema { 214 if isVectorizableType(propSchema) { 215 props = append(props, propSchema.Name) 216 propsMap[propSchema.Name] = struct{}{} 217 } 218 } 219 sort.Strings(props) 220 221 return props, propsMap 222 } 223 224 func isVectorizableType(propSchema *models.Property) bool { 225 switch pdt, _ := schema.AsPrimitive(propSchema.DataType); pdt { 226 case schema.DataTypeText, schema.DataTypeTextArray, schema.DataTypeBlob: 227 return true 228 default: 229 return false 230 } 231 }