diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java |
Publish
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java')
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java new file mode 100644 index 00000000000..5770665e3a1 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java @@ -0,0 +1,227 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.query.profile.config; + +import com.yahoo.component.ComponentId; +import com.yahoo.component.ComponentSpecification; +import com.yahoo.config.subscription.ConfigSubscriber; +import com.yahoo.search.query.profile.DimensionValues; +import com.yahoo.search.query.profile.QueryProfile; +import com.yahoo.search.query.profile.QueryProfileRegistry; +import com.yahoo.search.query.profile.types.FieldDescription; +import com.yahoo.search.query.profile.types.FieldType; +import com.yahoo.search.query.profile.types.QueryProfileType; +import com.yahoo.search.query.profile.types.QueryProfileTypeRegistry; +import com.yahoo.text.BooleanParser; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author bratseth + */ +public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber<QueryProfilesConfig> { + + private final ConfigSubscriber subscriber = new ConfigSubscriber(); + + private volatile QueryProfileRegistry currentRegistry; + + public QueryProfileConfigurer(String configId) { + subscriber.subscribe(this, QueryProfilesConfig.class, configId); + } + + /** Returns the registry created by the last occurring call to configure */ + public QueryProfileRegistry getCurrentRegistry() { return currentRegistry; } + + private void setCurrentRegistry(QueryProfileRegistry registry) { + this.currentRegistry=registry; + } + + public void configure(QueryProfilesConfig config) { + QueryProfileRegistry registry = createFromConfig(config); + setCurrentRegistry(registry); + } + + public static QueryProfileRegistry createFromConfig(QueryProfilesConfig config) { + QueryProfileRegistry registry=new QueryProfileRegistry(); + + // Pass 1: Create all profiles and profile types + for (QueryProfilesConfig.Queryprofiletype profileTypeConfig : config.queryprofiletype()) { + createProfileType(profileTypeConfig,registry.getTypeRegistry()); + } + for (QueryProfilesConfig.Queryprofile profileConfig : config.queryprofile()) { + createProfile(profileConfig,registry); + } + + // Pass 2: Resolve references and add content + for (QueryProfilesConfig.Queryprofiletype profileTypeConfig : config.queryprofiletype()) { + fillProfileType(profileTypeConfig,registry.getTypeRegistry()); + } + + // To ensure topological sorting, using DPS. This will _NOT_ detect cycles (but it will not fail if they + // exist either) + Set<ComponentId> filled = new HashSet<>(); + for (QueryProfilesConfig.Queryprofile profileConfig : config.queryprofile()) { + fillProfile(profileConfig, config, registry, filled); + } + + registry.freeze(); + return registry; + } + + /** Stop subscribing from this configurer */ + public void shutdown() { + subscriber.close(); + } + + private static void createProfile(QueryProfilesConfig.Queryprofile config,QueryProfileRegistry registry) { + QueryProfile profile=new QueryProfile(config.id()); + try { + String typeId=config.type(); + if (typeId!=null && !typeId.isEmpty()) + profile.setType(registry.getType(typeId)); + + if (config.dimensions().size()>0) { + String[] dimensions=new String[config.dimensions().size()]; + for (int i=0; i<config.dimensions().size(); i++) + dimensions[i]=config.dimensions().get(i); + profile.setDimensions(dimensions); + } + + registry.register(profile); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid " + profile,e); + } + } + + private static void createProfileType(QueryProfilesConfig.Queryprofiletype config, QueryProfileTypeRegistry registry) { + QueryProfileType type=new QueryProfileType(config.id()); + type.setStrict(config.strict()); + type.setMatchAsPath(config.matchaspath()); + registry.register(type); + } + + private static void fillProfile(QueryProfilesConfig.Queryprofile config, + QueryProfilesConfig queryProfilesConfig, + QueryProfileRegistry registry, + Set<ComponentId> filled) { + QueryProfile profile=registry.getComponent(new ComponentSpecification(config.id()).toId()); + if (filled.contains(profile.getId())) return; + filled.add(profile.getId()); + try { + for (String inheritedId : config.inherit()) { + QueryProfile inherited=registry.getComponent(inheritedId); + if (inherited==null) + throw new IllegalArgumentException("Inherited query profile '" + inheritedId + "' in " + profile + " was not found"); + fillProfile(inherited, queryProfilesConfig, registry, filled); + profile.addInherited(inherited); + } + + for (QueryProfilesConfig.Queryprofile.Reference referenceConfig : config.reference()) { + QueryProfile referenced=registry.getComponent(referenceConfig.value()); + if (referenced==null) + throw new IllegalArgumentException("Query profile '" + referenceConfig.value() + "' referenced as '" + + referenceConfig.name() + "' in " + profile + " was not found"); + profile.set(referenceConfig.name(),referenced, registry); + if (referenceConfig.overridable()!=null && !referenceConfig.overridable().isEmpty()) + profile.setOverridable(referenceConfig.name(),BooleanParser.parseBoolean(referenceConfig.overridable()),null); + } + + for (QueryProfilesConfig.Queryprofile.Property propertyConfig : config.property()) { + profile.set(propertyConfig.name(),propertyConfig.value(), registry); + if (propertyConfig.overridable()!=null && !propertyConfig.overridable().isEmpty()) + profile.setOverridable(propertyConfig.name(),BooleanParser.parseBoolean(propertyConfig.overridable()),null); + } + + for (QueryProfilesConfig.Queryprofile.Queryprofilevariant variantConfig : config.queryprofilevariant()) { + String[] forDimensionValueArray=new String[variantConfig.fordimensionvalues().size()]; + for (int i=0; i<variantConfig.fordimensionvalues().size(); i++) { + forDimensionValueArray[i]=variantConfig.fordimensionvalues().get(i).trim(); + if ("*".equals(forDimensionValueArray[i])) + forDimensionValueArray[i]=null; + } + DimensionValues forDimensionValues=DimensionValues.createFrom(forDimensionValueArray); + + for (String inheritedId : variantConfig.inherit()) { + QueryProfile inherited=registry.getComponent(inheritedId); + if (inherited==null) + throw new IllegalArgumentException("Inherited query profile '" + inheritedId + "' in " + profile + + " for '" + forDimensionValues + "' was not found"); + fillProfile(inherited, queryProfilesConfig, registry, filled); + profile.addInherited(inherited, forDimensionValues); + } + + for (QueryProfilesConfig.Queryprofile.Queryprofilevariant.Reference referenceConfig : variantConfig.reference()) { + QueryProfile referenced=registry.getComponent(referenceConfig.value()); + if (referenced==null) + throw new IllegalArgumentException("Query profile '" + referenceConfig.value() + "' referenced as '" + + referenceConfig.name() + "' in " + profile + " for '" + forDimensionValues + "' was not found"); + profile.set(referenceConfig.name(), referenced, forDimensionValues, registry); + } + + for (QueryProfilesConfig.Queryprofile.Queryprofilevariant.Property propertyConfig : variantConfig.property()) { + profile.set(propertyConfig.name(), propertyConfig.value(), forDimensionValues, registry); + } + + } + + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid " + profile,e); + } + } + + /** Fill a given profile by locating its config */ + private static void fillProfile(QueryProfile inherited, + QueryProfilesConfig queryProfilesConfig, + QueryProfileRegistry registry, + Set<ComponentId> visited) { + for (QueryProfilesConfig.Queryprofile inheritedConfig : queryProfilesConfig.queryprofile()) { + if (inherited.getId().stringValue().equals(inheritedConfig.id())) { + fillProfile(inheritedConfig, queryProfilesConfig, registry, visited); + } + } + } + + private static void fillProfileType(QueryProfilesConfig.Queryprofiletype config,QueryProfileTypeRegistry registry) { + QueryProfileType type=registry.getComponent(new ComponentSpecification(config.id()).toId()); + try { + + for (String inheritedId : config.inherit()) { + QueryProfileType inherited=registry.getComponent(inheritedId); + if (inherited==null) + throw new IllegalArgumentException("Inherited query profile type '" + inheritedId + "' in " + type + " was not found"); + else + type.inherited().add(inherited); + + } + + for (QueryProfilesConfig.Queryprofiletype.Field fieldConfig : config.field()) + instantiateFieldDescription(fieldConfig,type,registry); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid " + type,e); + } + } + + private static void instantiateFieldDescription(QueryProfilesConfig.Queryprofiletype.Field fieldConfig, + QueryProfileType type, + QueryProfileTypeRegistry registry) { + try { + FieldType fieldType=FieldType.fromString(fieldConfig.type(),registry); + FieldDescription field=new FieldDescription( + fieldConfig.name(), + fieldType, + fieldConfig.alias(), + fieldConfig.mandatory(), + fieldConfig.overridable() + ); + type.addField(field, registry); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid field '" + fieldConfig.name() + "' in " + type,e); + } + } + + +} |