diff options
author | Jon Bratseth <bratseth@gmail.com> | 2020-11-10 23:32:31 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2020-11-10 23:32:31 +0100 |
commit | 094be744d6706e02c7299ac1c92b49a0b13a24c5 (patch) | |
tree | 297d1df9650694c26fc11aceff5444ed445e9096 /container-search | |
parent | 0c68b00b2d3a9ddc191ed1733ba2f8699d1c3dc1 (diff) |
Support setting specific variants unoverridable
Diffstat (limited to 'container-search')
14 files changed, 126 insertions, 31 deletions
diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json index 113760b85cb..45e6c46c33b 100644 --- a/container-search/abi-spec.json +++ b/container-search/abi-spec.json @@ -5869,6 +5869,8 @@ "public java.util.Map values()", "public java.util.List inherited()", "public java.lang.Object set(java.lang.String, java.lang.Object)", + "public void setOverridable(java.lang.String, boolean)", + "public java.lang.Boolean isOverridable(java.lang.String)", "public void inherit(com.yahoo.search.query.profile.QueryProfile)", "public int compareTo(com.yahoo.search.query.profile.QueryProfileVariant)", "public boolean matches(com.yahoo.search.query.profile.DimensionValues)", @@ -5948,6 +5950,8 @@ "public java.lang.Object get(java.lang.String, com.yahoo.search.query.profile.types.QueryProfileType, boolean, com.yahoo.search.query.profile.DimensionBinding)", "public void inherit(com.yahoo.search.query.profile.QueryProfile, com.yahoo.search.query.profile.DimensionValues)", "public void set(java.lang.String, com.yahoo.search.query.profile.DimensionValues, java.lang.Object)", + "public void setOverridable(java.lang.String, boolean, com.yahoo.search.query.profile.DimensionValues)", + "public java.lang.Boolean isOverridable(java.lang.String, com.yahoo.search.query.profile.DimensionValues)", "public java.util.List getDimensions()", "public java.util.Map getFieldValues()", "public com.yahoo.search.query.profile.QueryProfileVariants$FieldValues getInherited()", diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java index d0a42e8a1f9..be4a683d9d2 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java @@ -147,7 +147,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * Returns the content fields declared in this (i.e not including those inherited) as a read-only map. * @throws IllegalStateException if this is frozen */ - public Map<String,Object> declaredContent() { + public Map<String, Object> declaredContent() { ensureNotFrozen(); return content.unmodifiableMap(); } @@ -203,6 +203,14 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable } /** + * Sets the overridability of a field in this profile, + * this overrides the corresponding setting in the type (if any) + */ + public final void setOverridable(String fieldName, boolean overridable, DimensionValues dimensionValues) { + setOverridable(new CompoundName(fieldName), overridable, DimensionBinding.createFrom(getDimensions(), dimensionValues)); + } + + /** * Return all objects that start with the given prefix path using no context. Use "" to list all. * <p> * For example, if {a.d => "a.d-value" ,a.e => "a.e-value", b.d => "b.d-value", then calling listValues("a") @@ -234,7 +242,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * For example, if {a.d => "a.d-value" ,a.e => "a.e-value", b.d => "b.d-value", then calling listValues("a") * will return {"d" => "a.d-value","e" => "a.e-value"} */ - public final Map<String, Object> listValues(CompoundName prefix, Map<String,String> context) { + public final Map<String, Object> listValues(CompoundName prefix, Map<String, String> context) { return listValues(prefix, context, null); } @@ -341,11 +349,11 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * @throws IllegalArgumentException if the given name is illegal given the types of this or any nested query profile * @throws IllegalStateException if this query profile is frozen */ - public final void set(CompoundName name, Object value, Map<String,String> context, QueryProfileRegistry registry) { + public final void set(CompoundName name, Object value, Map<String, String> context, QueryProfileRegistry registry) { set(name, value, DimensionBinding.createFrom(getDimensions(), context), registry); } - public final void set(String name, Object value, Map<String,String> context, QueryProfileRegistry registry) { + public final void set(String name, Object value, Map<String, String> context, QueryProfileRegistry registry) { set(new CompoundName(name), value, DimensionBinding.createFrom(getDimensions(), context), registry); } @@ -479,9 +487,14 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable */ Boolean isLocalOverridable(String localName, DimensionBinding binding) { if (localLookup(localName, binding) == null) return null; // Not set + if ( ! binding.isNull() && getVariants() != null) { + Boolean variantIsOverriable = getVariants().isOverridable(localName, binding.getValues()); + if (variantIsOverriable != null) + return variantIsOverriable; + } Boolean isLocalInstanceOverridable = isLocalInstanceOverridable(localName); if (isLocalInstanceOverridable != null) - return isLocalInstanceOverridable.booleanValue(); + return isLocalInstanceOverridable; if (type != null) return type.isOverridable(localName); return true; } @@ -731,9 +744,14 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable */ private void setOverridable(CompoundName fieldName, boolean overridable, DimensionBinding dimensionBinding) { QueryProfile parent = lookupParentExact(fieldName, true, dimensionBinding); - if (parent.overridable == null) - parent.overridable = new HashMap<>(); - parent.overridable.put(fieldName.last(), overridable); + if (dimensionBinding.isNull()) { + if (parent.overridable == null) + parent.overridable = new HashMap<>(); + parent.overridable.put(fieldName.last(), overridable); + } + else { + variants.setOverridable(fieldName.last(), overridable, dimensionBinding.getValues()); + } } /** Sets a value to a (possibly non-local) node. */ diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariant.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariant.java index a33ee33b652..f6c43eab8a0 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariant.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariant.java @@ -20,6 +20,8 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa private Map<String, Object> values; + private final Map<String, Boolean> overridable = new HashMap<>(); + private boolean frozen = false; private final QueryProfile owner; @@ -71,6 +73,14 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa return combinedOrNull; } + public void setOverridable(String key, boolean overridable) { + this.overridable.put(key, overridable); + } + + public Boolean isOverridable(String key) { + return overridable.get(key); + } + public void inherit(QueryProfile profile) { if (inherited == null) inherited = new ArrayList<>(1); diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariants.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariants.java index 062b9d8c6e4..431947b0816 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariants.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariants.java @@ -27,7 +27,7 @@ public class QueryProfileVariants implements Freezable, Cloneable { private boolean frozen = false; /** Properties indexed by name, to support fast lookup of single values */ - private Map<String,FieldValues> fieldValuesByName = new HashMap<>(); + private Map<String, FieldValues> fieldValuesByName = new HashMap<>(); /** The inherited profiles for various dimensions settings - a set of fieldvalues of List<QueryProfile> */ private FieldValues inheritedProfiles = new FieldValues(); @@ -233,6 +233,19 @@ public class QueryProfileVariants implements Freezable, Cloneable { } /** + * Makes a value unoverridable in a given context. + */ + public void setOverridable(String fieldName, boolean overridable, DimensionValues dimensionValues) { + getVariant(dimensionValues, true).setOverridable(fieldName, overridable); + } + + public Boolean isOverridable(String fieldName, DimensionValues dimensionValues) { + QueryProfileVariant variant = getVariant(dimensionValues, false); + if (variant == null) return null; + return variant.isOverridable(fieldName); + } + + /** * Returns the dimensions over which the virtual profiles in this may return different values. * Each dimension is a name for which a key-value may be supplied in the context properties * on lookup time to influence the value returned. 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 index d3c232f84c5..423348454d0 100644 --- 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 @@ -121,16 +121,20 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber 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"); + 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); + profile.setOverridable(referenceConfig.name(), + BooleanParser.parseBoolean(referenceConfig.overridable()), + DimensionValues.empty); } 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); + profile.setOverridable(propertyConfig.name(), + BooleanParser.parseBoolean(propertyConfig.overridable()), + DimensionValues.empty); } for (QueryProfilesConfig.Queryprofile.Queryprofilevariant variantConfig : config.queryprofilevariant()) { @@ -152,15 +156,24 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber } for (QueryProfilesConfig.Queryprofile.Queryprofilevariant.Reference referenceConfig : variantConfig.reference()) { - QueryProfile referenced=registry.getComponent(referenceConfig.value()); + 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"); + referenceConfig.name() + "' in " + profile + + " for '" + forDimensionValues + "' was not found"); profile.set(referenceConfig.name(), referenced, forDimensionValues, registry); + if ( ! referenceConfig.overridable().isEmpty()) + profile.setOverridable(referenceConfig.name(), + Boolean.parseBoolean(referenceConfig.overridable()), + forDimensionValues); } for (QueryProfilesConfig.Queryprofile.Queryprofilevariant.Property propertyConfig : variantConfig.property()) { profile.set(propertyConfig.name(), propertyConfig.value(), forDimensionValues, registry); + if ( ! propertyConfig.overridable().isEmpty()) + profile.setOverridable(propertyConfig.name(), + Boolean.parseBoolean(propertyConfig.overridable()), + forDimensionValues); } } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileXMLReader.java b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileXMLReader.java index db6d0560c5f..a64f2087d1f 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileXMLReader.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileXMLReader.java @@ -41,7 +41,7 @@ public class QueryProfileXMLReader { try { File dir = new File(directory); if ( ! dir.isDirectory() ) throw new IllegalArgumentException("Could not read query profiles: '" + - directory + "' is not a valid directory."); + directory + "' is not a valid directory."); for (File file : sortFiles(dir)) { if ( ! file.getName().endsWith(".xml")) continue; @@ -235,7 +235,7 @@ public class QueryProfileXMLReader { QueryProfile profile = registry.getComponent(new ComponentSpecification(element.getAttribute("id")).toId()); try { readInherited(element, profile, registry,null, profile.toString()); - readFields(element, profile, registry,null, profile.toString()); + readFields(element, profile, registry,DimensionValues.empty, profile.toString()); readVariants(element, profile, registry); } catch (RuntimeException e) { @@ -268,10 +268,9 @@ public class QueryProfileXMLReader { if (name == null || name.equals("")) throw new IllegalArgumentException("A field in " + sourceDescription + " has no 'name' attribute"); try { - Boolean overridable = getBooleanAttribute("overridable",null,field); + Boolean overridable = getBooleanAttribute("overridable", null, field); if (overridable != null) - profile.setOverridable(name, overridable, null); - + profile.setOverridable(name, overridable, dimensionValues.asContext(profile.getDimensions())); Object fieldValue = readFieldValue(field, name, sourceDescription, registry); if (fieldValue instanceof QueryProfile) references.add(new KeyValue(name, fieldValue)); @@ -358,8 +357,8 @@ public class QueryProfileXMLReader { private static class KeyValue { - private String key; - private Object value; + private final String key; + private final Object value; public KeyValue(String key, Object value) { this.key = key; diff --git a/container-search/src/main/resources/configdefinitions/search.query.profile.config.query-profiles.def b/container-search/src/main/resources/configdefinitions/search.query.profile.config.query-profiles.def index 3c6d11e2944..d05f5aaefa2 100644 --- a/container-search/src/main/resources/configdefinitions/search.query.profile.config.query-profiles.def +++ b/container-search/src/main/resources/configdefinitions/search.query.profile.config.query-profiles.def @@ -52,10 +52,14 @@ queryprofile[].queryprofilevariant[].inherit[] string queryprofile[].queryprofilevariant[].property[].name string # Content of profile variant queryprofile[].queryprofilevariant[].property[].value string +# Whether the is overridable: "true", "false" or "" +queryprofile[].queryprofilevariant[].property[].overridable string default="" # Content of profile variant queryprofile[].queryprofilevariant[].reference[].name string # Content of profile variant queryprofile[].queryprofilevariant[].reference[].value string +# Whether the is overridable: "true", "false" or "" +queryprofile[].queryprofilevariant[].reference[].overridable string default="" # A query profile type defines the values of instance query profiles. # The id follows the same rules as for query profiles diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java index 445073ced3a..253c6bd8792 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java @@ -219,6 +219,19 @@ public class XmlReadingTestCase { } @Test + public void testQueryProfileVariantsWithOverridableFalse() { + QueryProfileXMLReader reader = new QueryProfileXMLReader(); + CompiledQueryProfileRegistry registry = reader.read("src/test/java/com/yahoo/search/query/profile/config/test/variants/").compile(); + CompiledQueryProfile profile = registry.findQueryProfile("default"); + + assertEquals("a.b.c-value", new Query("?d1=d1v", profile).properties().get("a.b.c")); + assertEquals("a.b.c-variant-value", new Query("?d1=d1v&d2=d2v", profile).properties().get("a.b.c")); + + assertTrue(profile.isOverridable(new CompoundName("a.b.c"), Map.of("d1", "d1v"))); + assertFalse(profile.isOverridable(new CompoundName("a.b.c"), Map.of("d1", "d1v", "d2", "d2v"))); + } + + @Test public void testNewsFE1() { CompiledQueryProfileRegistry registry=new QueryProfileXMLReader().read("src/test/java/com/yahoo/search/query/profile/config/test/newsfe").compile(); diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/default.xml b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/default.xml new file mode 100644 index 00000000000..95ee7d3d484 --- /dev/null +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/default.xml @@ -0,0 +1,4 @@ +<query-profile id="default"> + <dimensions>d1</dimensions> + <field name="a.b"><ref>main</ref></field> +</query-profile> diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/inherited.xml b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/inherited.xml new file mode 100644 index 00000000000..1c1102ab5db --- /dev/null +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/inherited.xml @@ -0,0 +1,10 @@ +<query-profile id="inherited"> + <dimensions>d2</dimensions> + + <field name="c">a.b.c-value</field> + + <query-profile for="d2v"> + <field name="c" overridable="false">a.b.c-variant-value</field> + </query-profile> + +</query-profile> diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/main.xml b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/main.xml new file mode 100644 index 00000000000..efad3c8dd5c --- /dev/null +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/variants/main.xml @@ -0,0 +1,4 @@ +<query-profile id="main"> + <dimensions>d1</dimensions> + <query-profile for="d1v" inherits="inherited" /> +</query-profile> diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileTestCase.java index eb1584efe84..5598ae65990 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileTestCase.java @@ -6,6 +6,7 @@ import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.processing.request.CompoundName; import com.yahoo.processing.request.Properties; import com.yahoo.search.Query; +import com.yahoo.search.query.profile.DimensionValues; import com.yahoo.search.query.profile.QueryProfile; import com.yahoo.search.query.profile.QueryProfileProperties; import com.yahoo.search.query.profile.QueryProfileRegistry; @@ -331,7 +332,7 @@ public class QueryProfileTestCase { public void testInstanceOverridable() { QueryProfile profile = new QueryProfile("root/unoverridableIndex"); profile.set("model.defaultIndex","default", null); - profile.setOverridable("model.defaultIndex", false,null); + profile.setOverridable("model.defaultIndex", false, DimensionValues.empty); assertFalse(profile.isDeclaredOverridable("model.defaultIndex",null)); @@ -351,7 +352,7 @@ public class QueryProfileTestCase { QueryProfile profile = new QueryProfile("root/unoverridableIndex"); profile.setDimensions(new String[] {"x"}); profile.set("model.defaultIndex","default", null); - profile.setOverridable("model.defaultIndex",false,null); + profile.setOverridable("model.defaultIndex", false, DimensionValues.empty); assertFalse(profile.isDeclaredOverridable("model.defaultIndex",null)); @@ -370,7 +371,7 @@ public class QueryProfileTestCase { QueryProfile profile=new QueryProfile("test"); profile.setDimensions(new String[] {"x"}); profile.set("a","original", null); - profile.setOverridable("a",false,null); + profile.setOverridable("a", false, DimensionValues.empty); assertFalse(profile.isDeclaredOverridable("a",null)); @@ -380,12 +381,12 @@ public class QueryProfileTestCase { @Test public void testSimpleInstanceOverridableWithVariants2() { - QueryProfile profile=new QueryProfile("test"); + QueryProfile profile = new QueryProfile("test"); profile.setDimensions(new String[] {"x"}); - profile.set("a","original",new String[] {"x1"}, null); - profile.setOverridable("a",false,null); + profile.set("a", "original", new String[] {"x1"}, null); + profile.setOverridable("a", false, DimensionValues.empty); - assertFalse(profile.isDeclaredOverridable("a",null)); + assertFalse(profile.isDeclaredOverridable("a", null)); Query query = new Query(HttpRequest.createTestRequest("?x=x1&a=overridden", Method.GET), profile.compile(null)); assertEquals("original",query.properties().get("a")); diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/OverrideTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/OverrideTestCase.java index aa6049a45ec..c0f1dfeca0b 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/OverrideTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/OverrideTestCase.java @@ -5,6 +5,7 @@ import com.yahoo.jdisc.http.HttpRequest.Method; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.component.ComponentId; import com.yahoo.search.Query; +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.compiled.CompiledQueryProfileRegistry; @@ -168,7 +169,7 @@ public class OverrideTestCase { QueryProfile test = new QueryProfile("test"); test.setType(type); test.set("myInteger", 1, registry); - test.setOverridable("myInteger", false, null); + test.setOverridable("myInteger", false, DimensionValues.empty); registry.register(test); QueryProfile profile=new QueryProfile("profile"); diff --git a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java index a42a2ee55aa..8d93ee3ad5d 100644 --- a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java @@ -32,6 +32,7 @@ import com.yahoo.search.Searcher; import com.yahoo.search.grouping.GroupingQueryParser; import com.yahoo.search.query.QueryTree; import com.yahoo.search.query.SessionId; +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.compiled.CompiledQueryProfileRegistry; @@ -427,7 +428,7 @@ public class QueryTestCase { @Test public void testQueryProfileInSubstitution() { QueryProfile testProfile = new QueryProfile("test"); - testProfile.setOverridable("u", false, null); + testProfile.setOverridable("u", false, DimensionValues.empty); testProfile.set("d","e", null); testProfile.set("u","11", null); testProfile.set("foo.bar", "wiz", null); @@ -560,7 +561,7 @@ public class QueryTestCase { @Test public void testQueryPropertyResolveTracing() { QueryProfile testProfile = new QueryProfile("test"); - testProfile.setOverridable("u", false, null); + testProfile.setOverridable("u", false, DimensionValues.empty); testProfile.set("d","e", null); testProfile.set("u","11", null); testProfile.set("foo.bar", "wiz", null); |