github.com/weaviate/weaviate@v1.24.6/usecases/modules/module_config_init_and_validate.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 modules 13 14 import ( 15 "context" 16 "fmt" 17 18 "github.com/pkg/errors" 19 "github.com/weaviate/weaviate/entities/models" 20 "github.com/weaviate/weaviate/entities/modulecapabilities" 21 "github.com/weaviate/weaviate/entities/schema" 22 ) 23 24 // SetClassDefaults sets the module-specific defaults for the class itself, but 25 // also for each prop 26 func (p *Provider) SetClassDefaults(class *models.Class) { 27 if !hasTargetVectors(class) { 28 p.setClassDefaults(class, class.Vectorizer, "", func(vectorizerConfig map[string]interface{}) { 29 if class.ModuleConfig == nil { 30 class.ModuleConfig = map[string]interface{}{} 31 } 32 class.ModuleConfig.(map[string]interface{})[class.Vectorizer] = vectorizerConfig 33 }) 34 return 35 } 36 37 for targetVector, vectorConfig := range class.VectorConfig { 38 if moduleConfig, ok := vectorConfig.Vectorizer.(map[string]interface{}); ok && len(moduleConfig) == 1 { 39 for vectorizer := range moduleConfig { 40 p.setClassDefaults(class, vectorizer, targetVector, func(vectorizerConfig map[string]interface{}) { 41 moduleConfig[vectorizer] = vectorizerConfig 42 }) 43 } 44 } 45 } 46 } 47 48 func (p *Provider) setClassDefaults(class *models.Class, vectorizer string, 49 targetVector string, storeFn func(vectorizerConfig map[string]interface{}), 50 ) { 51 if vectorizer == "none" { 52 // the class does not use a vectorizer, nothing to do for us 53 return 54 } 55 56 mod := p.GetByName(vectorizer) 57 cc, ok := mod.(modulecapabilities.ClassConfigurator) 58 if !ok { 59 // the module exists, but is not a class configurator, nothing to do for us 60 return 61 } 62 63 cfg := NewClassBasedModuleConfig(class, vectorizer, "", targetVector) 64 65 p.setPerClassConfigDefaults(cfg, cc, storeFn) 66 for _, prop := range class.Properties { 67 p.setSinglePropertyConfigDefaults(prop, vectorizer, cc) 68 } 69 } 70 71 func (p *Provider) setPerClassConfigDefaults(cfg *ClassBasedModuleConfig, 72 cc modulecapabilities.ClassConfigurator, 73 storeFn func(vectorizerConfig map[string]interface{}), 74 ) { 75 modDefaults := cc.ClassConfigDefaults() 76 userSpecified := cfg.Class() 77 mergedConfig := map[string]interface{}{} 78 79 for key, value := range modDefaults { 80 mergedConfig[key] = value 81 } 82 for key, value := range userSpecified { 83 mergedConfig[key] = value 84 } 85 86 if len(mergedConfig) > 0 { 87 storeFn(mergedConfig) 88 } 89 } 90 91 // SetSinglePropertyDefaults can be used when a property is added later, e.g. 92 // as part of merging in a ref prop after a class has already been created 93 func (p *Provider) SetSinglePropertyDefaults(class *models.Class, 94 prop *models.Property, 95 ) { 96 if !hasTargetVectors(class) { 97 p.setSinglePropertyDefaults(prop, class.Vectorizer) 98 return 99 } 100 101 for _, vectorConfig := range class.VectorConfig { 102 if moduleConfig, ok := vectorConfig.Vectorizer.(map[string]interface{}); ok && len(moduleConfig) == 1 { 103 for vectorizer := range moduleConfig { 104 p.setSinglePropertyDefaults(prop, vectorizer) 105 } 106 } 107 } 108 } 109 110 func (p *Provider) setSinglePropertyDefaults(prop *models.Property, vectorizer string) { 111 if vectorizer == "none" { 112 // the class does not use a vectorizer, nothing to do for us 113 return 114 } 115 116 mod := p.GetByName(vectorizer) 117 cc, ok := mod.(modulecapabilities.ClassConfigurator) 118 if !ok { 119 // the module exists, but is not a class configurator, nothing to do for us 120 return 121 } 122 123 p.setSinglePropertyConfigDefaults(prop, vectorizer, cc) 124 } 125 126 func (p *Provider) setSinglePropertyConfigDefaults(prop *models.Property, 127 vectorizer string, cc modulecapabilities.ClassConfigurator, 128 ) { 129 dt, _ := schema.GetValueDataTypeFromString(prop.DataType[0]) 130 modDefaults := cc.PropertyConfigDefaults(dt) 131 userSpecified := map[string]interface{}{} 132 mergedConfig := map[string]interface{}{} 133 134 if prop.ModuleConfig != nil { 135 if vectorizerConfig, ok := prop.ModuleConfig.(map[string]interface{})[vectorizer]; ok { 136 if mcvm, ok := vectorizerConfig.(map[string]interface{}); ok { 137 userSpecified = mcvm 138 } 139 } 140 } 141 142 for key, value := range modDefaults { 143 mergedConfig[key] = value 144 } 145 for key, value := range userSpecified { 146 mergedConfig[key] = value 147 } 148 149 if len(mergedConfig) > 0 { 150 if prop.ModuleConfig == nil { 151 prop.ModuleConfig = map[string]interface{}{} 152 } 153 prop.ModuleConfig.(map[string]interface{})[vectorizer] = mergedConfig 154 } 155 } 156 157 func (p *Provider) ValidateClass(ctx context.Context, class *models.Class) error { 158 switch len(class.VectorConfig) { 159 case 0: 160 // legacy configuration 161 if class.Vectorizer == "none" { 162 // the class does not use a vectorizer, nothing to do for us 163 return nil 164 } 165 if err := p.validateClassesModuleConfig(ctx, class, class.ModuleConfig); err != nil { 166 return err 167 } 168 return nil 169 default: 170 // named vectors configuration 171 for targetVector, vectorConfig := range class.VectorConfig { 172 if len(targetVector) > schema.TargetVectorNameMaxLength { 173 return errors.Errorf("class.VectorConfig target vector name %q is not valid. "+ 174 "Target vector name should not be longer than %d characters.", 175 targetVector, schema.TargetVectorNameMaxLength) 176 } 177 if !p.targetVectorNameValidator.MatchString(targetVector) { 178 return errors.Errorf("class.VectorConfig target vector name %q is not valid, "+ 179 "in Weaviate target vector names are restricted to valid GraphQL names, "+ 180 "which must be “/%s/”.", targetVector, schema.TargetVectorNameRegex) 181 } 182 vectorizer, ok := vectorConfig.Vectorizer.(map[string]interface{}) 183 if !ok { 184 return errors.Errorf("class.VectorConfig.Vectorizer must be an object, got %T", vectorConfig.Vectorizer) 185 } 186 if len(vectorizer) != 1 { 187 return errors.Errorf("class.VectorConfig.Vectorizer must consist only 1 configuration, got: %v", len(vectorizer)) 188 } 189 for modName := range vectorizer { 190 if modName == "none" { 191 // the class does not use a vectorizer, nothing to do for us 192 continue 193 } 194 if mod := p.GetByName(modName); mod == nil { 195 return errors.Errorf("class.VectorConfig.Vectorizer module with name %s doesn't exist", modName) 196 } 197 if err := p.validateClassModuleConfig(ctx, class, modName, targetVector); err != nil { 198 return err 199 } 200 } 201 } 202 // check module config configuration in case that there are other none vectorizer modules defined 203 if err := p.validateClassesModuleConfigNoneVectorizers(ctx, class, "", class.ModuleConfig); err != nil { 204 return err 205 } 206 return nil 207 } 208 } 209 210 func (p *Provider) validateClassesModuleConfigNoneVectorizers(ctx context.Context, 211 class *models.Class, targetVector string, moduleConfig interface{}, 212 ) error { 213 modConfig, ok := moduleConfig.(map[string]interface{}) 214 if !ok { 215 return nil 216 } 217 for modName := range modConfig { 218 mod := p.GetByName(modName) 219 if !p.isVectorizerModule(mod.Type()) { 220 if err := p.validateClassModuleConfig(ctx, class, modName, ""); err != nil { 221 return err 222 } 223 } 224 } 225 return nil 226 } 227 228 func (p *Provider) validateClassesModuleConfig(ctx context.Context, 229 class *models.Class, moduleConfig interface{}, 230 ) error { 231 modConfig, ok := moduleConfig.(map[string]interface{}) 232 if !ok { 233 return nil 234 } 235 configuredVectorizers := make([]string, 0, len(modConfig)) 236 for modName := range modConfig { 237 if err := p.validateClassModuleConfig(ctx, class, modName, ""); err != nil { 238 return err 239 } 240 if err := p.ValidateVectorizer(modName); err == nil { 241 configuredVectorizers = append(configuredVectorizers, modName) 242 } 243 } 244 if len(configuredVectorizers) > 1 { 245 return fmt.Errorf("multiple vectorizers configured in class's moduleConfig: %v. class.vectorizer is set to %q", 246 configuredVectorizers, class.Vectorizer) 247 } 248 return nil 249 } 250 251 func (p *Provider) validateClassModuleConfig(ctx context.Context, 252 class *models.Class, moduleName, targetVector string, 253 ) error { 254 mod := p.GetByName(moduleName) 255 cc, ok := mod.(modulecapabilities.ClassConfigurator) 256 if !ok { 257 // the module exists, but is not a class configurator, nothing to do for us 258 return nil 259 } 260 261 cfg := NewClassBasedModuleConfig(class, moduleName, "", targetVector) 262 err := cc.ValidateClass(ctx, class, cfg) 263 if err != nil { 264 return errors.Wrapf(err, "module '%s'", moduleName) 265 } 266 return nil 267 } 268 269 func hasTargetVectors(class *models.Class) bool { 270 return len(class.VectorConfig) > 0 271 }