diff options
author | Jon Bratseth <bratseth@oath.com> | 2019-10-28 20:21:00 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-28 20:21:00 +0100 |
commit | 6b5b636501fb8b553e8c5fbf72eefa42a54f8012 (patch) | |
tree | 35bb80f446a3fe6321aa6d7d3555699724f044a7 | |
parent | ea50378f8348b474f42d099794ac914517dc141f (diff) | |
parent | 6376e0d4c2a6da939e68be55195e95369e0c3e20 (diff) |
Merge pull request #11136 from vespa-engine/bratseth/query-profile-value-sources
Bratseth/query profile value sources
27 files changed, 537 insertions, 266 deletions
diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json index dcac62b38c6..c6d378bd64b 100644 --- a/container-search/abi-spec.json +++ b/container-search/abi-spec.json @@ -5526,6 +5526,7 @@ ], "methods": [ "public void <init>(com.yahoo.search.query.profile.QueryProfile)", + "public java.lang.String getSource()", "public synchronized void freeze()", "protected java.lang.Object localLookup(java.lang.String, com.yahoo.search.query.profile.DimensionBinding)", "protected java.lang.Boolean isLocalInstanceOverridable(java.lang.String)", @@ -5654,6 +5655,7 @@ ], "methods": [ "protected void <init>()", + "protected void <init>(java.lang.String)", "protected java.lang.Object checkAndConvertAssignment(java.lang.String, java.lang.Object, com.yahoo.search.query.profile.QueryProfileRegistry)", "protected com.yahoo.search.query.profile.QueryProfile createSubProfile(java.lang.String, com.yahoo.search.query.profile.DimensionBinding)", "public com.yahoo.search.query.profile.OverridableQueryProfile clone()", @@ -5676,6 +5678,8 @@ "methods": [ "public void <init>(com.yahoo.component.ComponentId)", "public void <init>(java.lang.String)", + "public void <init>(com.yahoo.component.ComponentId, java.lang.String)", + "public java.lang.String getSource()", "public com.yahoo.search.query.profile.types.QueryProfileType getType()", "public void setType(com.yahoo.search.query.profile.types.QueryProfileType)", "public com.yahoo.search.query.profile.QueryProfileVariants getVariants()", @@ -6007,6 +6011,7 @@ "public final java.util.Map listValues(java.lang.String, java.util.Map)", "public final java.util.Map listValues(com.yahoo.processing.request.CompoundName, java.util.Map)", "public java.util.Map listValues(com.yahoo.processing.request.CompoundName, java.util.Map, com.yahoo.processing.request.Properties)", + "public java.util.Map listValuesWithSources(com.yahoo.processing.request.CompoundName, java.util.Map, com.yahoo.processing.request.Properties)", "public final java.lang.Object get(java.lang.String)", "public final java.lang.Object get(java.lang.String, java.util.Map)", "public final java.lang.Object get(java.lang.String, java.util.Map, com.yahoo.processing.request.Properties)", @@ -6090,6 +6095,22 @@ ], "fields": [] }, + "com.yahoo.search.query.profile.compiled.ValueWithSource": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public" + ], + "methods": [ + "public void <init>(java.lang.Object, java.lang.String, com.yahoo.search.query.profile.DimensionValues)", + "public java.lang.Object value()", + "public java.lang.String source()", + "public com.yahoo.search.query.profile.compiled.ValueWithSource withValue(java.lang.Object)", + "public java.util.Optional variant()", + "public java.lang.String toString()" + ], + "fields": [] + }, "com.yahoo.search.query.profile.types.FieldDescription": { "superClass": "java.lang.Object", "interfaces": [ diff --git a/container-search/src/main/java/com/yahoo/search/Query.java b/container-search/src/main/java/com/yahoo/search/Query.java index 84827a46572..3dabf9bc649 100644 --- a/container-search/src/main/java/com/yahoo/search/Query.java +++ b/container-search/src/main/java/com/yahoo/search/Query.java @@ -482,14 +482,14 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { resolvedValue = requestProperty.getValue(); b.append(requestProperty.getKey()); - b.append("="); + b.append(": "); b.append(resolvedValue); // (may be null) b.append(" ("); if (profile != null && ! profile.isOverridable(new CompoundName(requestProperty.getKey()), requestProperties())) - b.append("value from query profile - unoverridable, ignoring request value"); + b.append("from query profile - unoverridable, ignoring request value"); else - b.append("value from request"); + b.append("from request"); b.append(")\n"); mentioned.add(requestProperty.getKey()); } @@ -504,9 +504,9 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { } private void appendQueryProfileProperties(CompiledQueryProfile profile, Set<String> mentioned, StringBuilder b) { - for (Map.Entry<String,Object> property : profile.listValues(CompoundName.empty, requestProperties(), properties()).entrySet()) { + for (var property : profile.listValuesWithSources(CompoundName.empty, requestProperties(), properties()).entrySet()) { if ( ! mentioned.contains(property.getKey())) - b.append(property.getKey()).append("=").append(property.getValue()).append(" (value from query profile)\n"); + b.append(property.getKey()).append(": ").append(property.getValue()).append("\n"); } } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/AllReferencesQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/AllReferencesQueryProfileVisitor.java index d2c2017a49a..eda8bf78b68 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/AllReferencesQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/AllReferencesQueryProfileVisitor.java @@ -24,10 +24,16 @@ final class AllReferencesQueryProfileVisitor extends PrefixQueryProfileVisitor { } @Override - public void onValue(String name, Object value, DimensionBinding binding, QueryProfile owner) {} + public void onValue(String name, Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) {} @Override - public void onQueryProfileInsidePrefix(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { + public void onQueryProfileInsidePrefix(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { references.add(currentPrefix); } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/AllTypesQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/AllTypesQueryProfileVisitor.java index 4b83b716635..6bf17d70c70 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/AllTypesQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/AllTypesQueryProfileVisitor.java @@ -22,11 +22,17 @@ final class AllTypesQueryProfileVisitor extends PrefixQueryProfileVisitor { } @Override - public void onValue(String name, Object value, DimensionBinding binding, QueryProfile owner) {} + public void onValue(String name, Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) {} @Override - public void onQueryProfileInsidePrefix(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { + public void onQueryProfileInsidePrefix(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { if (profile.getType() != null) addReachableTypes(currentPrefix, profile.getType()); } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/AllUnoverridableQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/AllUnoverridableQueryProfileVisitor.java index 3b297834ddd..4bae6823500 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/AllUnoverridableQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/AllUnoverridableQueryProfileVisitor.java @@ -19,16 +19,25 @@ final class AllUnoverridableQueryProfileVisitor extends PrefixQueryProfileVisito } @Override - public void onValue(String name, Object value, DimensionBinding binding, QueryProfile owner) { + public void onValue(String name, Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { addUnoverridable(name, currentPrefix.append(name), binding, owner); } @Override - public void onQueryProfileInsidePrefix(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { + public void onQueryProfileInsidePrefix(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { addUnoverridable(currentPrefix.last(), currentPrefix, binding, owner); } - private void addUnoverridable(String localName, CompoundName fullName, DimensionBinding binding, QueryProfile owner) { + private void addUnoverridable(String localName, + CompoundName fullName, + DimensionBinding binding, + QueryProfile owner) { if (owner == null) return; Boolean isOverridable = owner.isLocalOverridable(localName, binding); diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/AllValuesQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/AllValuesQueryProfileVisitor.java index e56dabc71d7..f27500085e1 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/AllValuesQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/AllValuesQueryProfileVisitor.java @@ -2,6 +2,7 @@ package com.yahoo.search.query.profile; import com.yahoo.processing.request.CompoundName; +import com.yahoo.search.query.profile.compiled.ValueWithSource; import java.util.Collections; import java.util.HashMap; @@ -12,7 +13,7 @@ import java.util.Map; */ final class AllValuesQueryProfileVisitor extends PrefixQueryProfileVisitor { - private Map<String,Object> values=new HashMap<>(); + private Map<String, ValueWithSource> values = new HashMap<>(); /* Lists all values starting at prefix */ public AllValuesQueryProfileVisitor(CompoundName prefix) { @@ -20,25 +21,43 @@ final class AllValuesQueryProfileVisitor extends PrefixQueryProfileVisitor { } @Override - public void onValue(String localName, Object value, DimensionBinding binding, QueryProfile owner) { - putValue(localName, value, values); + public void onValue(String localName, + Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { + putValue(localName, value, owner, variant); } @Override - public void onQueryProfileInsidePrefix(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { - putValue("", profile.getValue(), values); + public void onQueryProfileInsidePrefix(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { + putValue("", profile.getValue(), owner, variant); } - private final void putValue(String key, Object value, Map<String, Object> values) { + private void putValue(String key, Object value, QueryProfile owner, DimensionValues variant) { if (value == null) return; CompoundName fullName = currentPrefix.append(key); if (fullName.isEmpty()) return; // Avoid putting a non-leaf (subtree) root in the list if (values.containsKey(fullName.toString())) return; // The first value encountered has priority - values.put(fullName.toString(), value); + + values.put(fullName.toString(), new ValueWithSource(value, + owner == null ? "anonymous" : owner.getSource(), + variant)); } /** Returns the values resulting from this visiting */ - public Map<String, Object> getResult() { return values; } + public Map<String, Object> values() { + Map<String, Object> values = new HashMap<>(); + for (var entry : this.values.entrySet()) + values.put(entry.getKey(), entry.getValue().value()); + return values; + } + + /** Returns the values with source resulting from this visiting */ + public Map<String, ValueWithSource> valuesWithSource() { return Collections.unmodifiableMap(values); } /** Returns false - we are not done until we have seen all */ public boolean isDone() { return false; } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/BackedOverridableQueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/BackedOverridableQueryProfile.java index 8c720b516a9..99f1e26b221 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/BackedOverridableQueryProfile.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/BackedOverridableQueryProfile.java @@ -33,10 +33,13 @@ public class BackedOverridableQueryProfile extends OverridableQueryProfile imple public BackedOverridableQueryProfile(QueryProfile backingProfile) { Validator.ensureNotNull("An overridable query profile must be backed by a real query profile",backingProfile); setType(backingProfile.getType()); - this.backingProfile=backingProfile; + this.backingProfile = backingProfile; } @Override + public String getSource() { return backingProfile.getSource(); } + + @Override public synchronized void freeze() { super.freeze(); backingProfile.freeze(); @@ -44,21 +47,23 @@ public class BackedOverridableQueryProfile extends OverridableQueryProfile imple @Override protected Object localLookup(String localName, DimensionBinding dimensionBinding) { - Object valueInThis=super.localLookup(localName,dimensionBinding); - if (valueInThis!=null) return valueInThis; - return backingProfile.localLookup(localName,dimensionBinding); + Object valueInThis = super.localLookup(localName, dimensionBinding); + if (valueInThis != null) return valueInThis; + return backingProfile.localLookup(localName, dimensionBinding); } protected Boolean isLocalInstanceOverridable(String localName) { - Boolean valueInThis=super.isLocalInstanceOverridable(localName); - if (valueInThis!=null) return valueInThis; + Boolean valueInThis = super.isLocalInstanceOverridable(localName); + if (valueInThis != null) return valueInThis; return backingProfile.isLocalInstanceOverridable(localName); } @Override - protected QueryProfile createSubProfile(String name,DimensionBinding dimensionBinding) { - Object backing=backingProfile.lookup(new CompoundName(name),true,dimensionBinding.createFor(backingProfile.getDimensions())); - if (backing!=null && backing instanceof QueryProfile) + protected QueryProfile createSubProfile(String name, DimensionBinding dimensionBinding) { + Object backing = backingProfile.lookup(new CompoundName(name), + true, + dimensionBinding.createFor(backingProfile.getDimensions())); + if (backing instanceof QueryProfile) return new BackedOverridableQueryProfile((QueryProfile)backing); else return new OverridableQueryProfile(); // Nothing is set in this branch, so nothing to override, but need override checking @@ -67,8 +72,7 @@ public class BackedOverridableQueryProfile extends OverridableQueryProfile imple /** Returns a clone of this which can be independently overridden, but which refers to the same backing profile */ @Override public BackedOverridableQueryProfile clone() { - BackedOverridableQueryProfile clone=(BackedOverridableQueryProfile)super.clone(); - return clone; + return (BackedOverridableQueryProfile)super.clone(); } /** Returns the query profile backing this */ diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/DimensionValues.java b/container-search/src/main/java/com/yahoo/search/query/profile/DimensionValues.java index 1a36f4917d9..9eb50c0f72e 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/DimensionValues.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/DimensionValues.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * An immutable set of dimension values. @@ -32,20 +33,20 @@ public class DimensionValues implements Comparable<DimensionValues> { * The input array is copied by this. */ private DimensionValues(String[] values) { - if (values==null) throw new NullPointerException("Dimension values cannot be null"); - this.values=Arrays.copyOf(values,values.length); + if (values == null) throw new NullPointerException("Dimension values cannot be null"); + this.values=Arrays.copyOf(values, values.length); } /** Returns true if this is has the same value every place it has a value as the givenValues. */ public boolean matches(DimensionValues givenValues) { - for (int i=0; i<this.size() || i<givenValues.size() ; i++) - if ( ! matches(this.get(i),givenValues.get(i))) + for (int i = 0; i < this.size() || i < givenValues.size() ; i++) + if ( ! matches(this.get(i), givenValues.get(i))) return false; return true; } - private final boolean matches(String conditionString,String checkString) { - if (conditionString==null) return true; + private final boolean matches(String conditionString, String checkString) { + if (conditionString == null) return true; return conditionString.equals(checkString); } @@ -61,10 +62,10 @@ public class DimensionValues implements Comparable<DimensionValues> { */ @Override public int compareTo(DimensionValues other) { - for (int i=0; i<this.size() || i<other.size(); i++) { - if (get(i)!=null && other.get(i)==null) + for (int i=0; i < this.size() || i < other.size(); i++) { + if (get(i) != null && other.get(i) == null) return -1; - if (get(i)==null && other.get(i)!=null) + if (get(i) == null && other.get(i) != null) return 1; } return 0; @@ -77,12 +78,12 @@ public class DimensionValues implements Comparable<DimensionValues> { @Override public boolean equals(Object o) { - if (this==o) return true; + if (this == o) return true; if ( ! (o instanceof DimensionValues)) return false; - DimensionValues other=(DimensionValues)o; - for (int i=0; i<this.size() || i<other.size(); i++) { - if (get(i)==null) { - if (other.get(i)!=null) return false; + DimensionValues other = (DimensionValues)o; + for (int i = 0; i < this.size() || i < other.size(); i++) { + if (get(i) == null) { + if (other.get(i) != null) return false; } else { if ( ! get(i).equals(other.get(i))) return false; @@ -104,7 +105,9 @@ public class DimensionValues implements Comparable<DimensionValues> { } @Override - public String toString() { return Arrays.toString(values); } + public String toString() { + return "[" + Arrays.stream(values).map(value -> value == null ? "*" : value).collect(Collectors.joining(", ")) + "]"; + } public boolean isEmpty() { return this==empty; @@ -112,7 +115,7 @@ public class DimensionValues implements Comparable<DimensionValues> { private static boolean containsAllNulls(String[] values) { for (String value : values) - if (value!=null) return false; + if (value != null) return false; return true; } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/FieldDescriptionQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/FieldDescriptionQueryProfileVisitor.java index 8a71b04c3b2..1d0bd2dbf53 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/FieldDescriptionQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/FieldDescriptionQueryProfileVisitor.java @@ -46,14 +46,21 @@ final class FieldDescriptionQueryProfileVisitor extends QueryProfileVisitor { } @Override - public void onValue(String name,Object value, DimensionBinding binding, QueryProfile owner) { + public void onValue(String name, + Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { } @Override - public void onQueryProfile(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { + public void onQueryProfile(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { if (enteringContent) return; // not at leaf query profile if (profile.getType() == null) return; - result = profile.getType().getField(name.get(name.size()-1)); + result = profile.getType().getField(name.get(name.size() - 1)); } @Override diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/OverridableQueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/OverridableQueryProfile.java index a275e3697a2..37940b813dc 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/OverridableQueryProfile.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/OverridableQueryProfile.java @@ -17,28 +17,32 @@ public class OverridableQueryProfile extends QueryProfile { /** Creates an unbacked overridable query profile */ protected OverridableQueryProfile() { - super(ComponentId.createAnonymousComponentId(simpleClassName)); + this(""); + } + + protected OverridableQueryProfile(String sourceName) { + super(ComponentId.createAnonymousComponentId(simpleClassName), sourceName); } @Override protected Object checkAndConvertAssignment(String localName, Object inputValue, QueryProfileRegistry registry) { - Object value=super.checkAndConvertAssignment(localName, inputValue, registry); - if (value!=null && value.getClass() == QueryProfile.class) { // We are assigning a query profile - make it overridable + Object value = super.checkAndConvertAssignment(localName, inputValue, registry); + if (value != null && value.getClass() == QueryProfile.class) { // We are assigning a query profile - make it overridable return new BackedOverridableQueryProfile((QueryProfile)value); } return value; } @Override - protected QueryProfile createSubProfile(String name,DimensionBinding binding) { - return new OverridableQueryProfile(); // Nothing is set in this branch, so nothing to override, but need override checking + protected QueryProfile createSubProfile(String name, DimensionBinding binding) { + return new OverridableQueryProfile(getSource()); // Nothing is set in this branch, so nothing to override, but need override checking } /** Returns a clone of this which can be independently overridden */ @Override public OverridableQueryProfile clone() { if (isFrozen()) return this; - OverridableQueryProfile clone=(OverridableQueryProfile)super.clone(); + OverridableQueryProfile clone = (OverridableQueryProfile)super.clone(); clone.initId(ComponentId.createAnonymousComponentId(simpleClassName)); return clone; } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/PrefixQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/PrefixQueryProfileVisitor.java index e47b4bc2bb4..690a48f8124 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/PrefixQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/PrefixQueryProfileVisitor.java @@ -25,12 +25,18 @@ abstract class PrefixQueryProfileVisitor extends QueryProfileVisitor { } @Override - public final void onQueryProfile(QueryProfile profile, DimensionBinding binding, QueryProfile owner) { + public final void onQueryProfile(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { if (prefixComponentIndex < prefix.size()) return; // Not in the prefix yet - onQueryProfileInsidePrefix(profile, binding, owner); + onQueryProfileInsidePrefix(profile, binding, owner, variant); } - protected abstract void onQueryProfileInsidePrefix(QueryProfile profile, DimensionBinding binding, QueryProfile owner); + protected abstract void onQueryProfileInsidePrefix(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant); @Override public final boolean enter(String name) { 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 f5f6b2d2550..e9ccdd22f98 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 @@ -42,6 +42,9 @@ import java.util.regex.Pattern; */ public class QueryProfile extends FreezableSimpleComponent implements Cloneable { + /** The name of the source of this (a file) */ + private final String source; + /** Defines the permissible content of this, or null if any content is permissible */ private QueryProfileType type = null; @@ -64,7 +67,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * Field override settings: fieldName→OverrideValue. These overrides the override * setting in the type (if any) of this field). If there are no query profile level settings, this is null. */ - private Map<String,Boolean> overridable = null; + private Map<String, Boolean> overridable = null; /** * Creates a new query profile from an id. @@ -72,9 +75,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * At that point it becomes readable but unmodifiable, which it stays until it goes out of reference. */ public QueryProfile(ComponentId id) { - super(id); - if ( ! id.isAnonymous()) - validateName(id.getName()); + this(id, id.stringValue()); } /** Convenience shorthand for new QueryProfile(new ComponentId(idString)) */ @@ -82,10 +83,19 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable this(new ComponentId(idString)); } + public QueryProfile(ComponentId id, String sourceName) { + super(id); + this.source = sourceName; + if ( ! id.isAnonymous()) + validateName(id.getName()); + } + // ----------------- Public API ------------------------------------------------------------------------------- // ----------------- Setters and getters + public String getSource() { return source; } + /** Returns the type of this or null if it has no type */ public QueryProfileType getType() { return type; } @@ -234,11 +244,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * will return {"d" => "a.d-value","e" => "a.e-value"} */ public Map<String, Object> listValues(CompoundName prefix, Map<String, String> context, Properties substitution) { - DimensionBinding dimensionBinding = DimensionBinding.createFrom(getDimensions(),context); - - AllValuesQueryProfileVisitor visitor = new AllValuesQueryProfileVisitor(prefix); - accept(visitor,dimensionBinding, null); - Map<String,Object> values = visitor.getResult(); + Map<String, Object> values = visitValues(prefix, context).values(); if (substitution == null) return values; for (Map.Entry<String, Object> entry : values.entrySet()) { @@ -250,6 +256,14 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable return values; } + AllValuesQueryProfileVisitor visitValues(CompoundName prefix, Map<String, String> context) { + DimensionBinding dimensionBinding = DimensionBinding.createFrom(getDimensions(), context); + + AllValuesQueryProfileVisitor visitor = new AllValuesQueryProfileVisitor(prefix); + accept(visitor, dimensionBinding, null); + return visitor; + } + /** * Lists types reachable from this, indexed by the prefix having that type. * If this is itself typed, this' type will be included with an empty prefix @@ -507,17 +521,25 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable return overridable.get(localName); } - protected Object lookup(CompoundName name, boolean allowQueryProfileResult, DimensionBinding dimensionBinding) { - SingleValueQueryProfileVisitor visitor = new SingleValueQueryProfileVisitor(name.asList(), allowQueryProfileResult); + protected Object lookup(CompoundName name, + boolean allowQueryProfileResult, + DimensionBinding dimensionBinding) { + SingleValueQueryProfileVisitor visitor = new SingleValueQueryProfileVisitor(name.asList(), + allowQueryProfileResult); accept(visitor, dimensionBinding, null); return visitor.getResult(); } - protected final void accept(QueryProfileVisitor visitor,DimensionBinding dimensionBinding, QueryProfile owner) { + protected final void accept(QueryProfileVisitor visitor, + DimensionBinding dimensionBinding, + QueryProfile owner) { acceptAndEnter("", visitor, dimensionBinding, owner); } - void acceptAndEnter(String key, QueryProfileVisitor visitor,DimensionBinding dimensionBinding, QueryProfile owner) { + void acceptAndEnter(String key, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding, + QueryProfile owner) { boolean allowContent = visitor.enter(key); accept(allowContent, visitor, dimensionBinding, owner); if (allowContent) @@ -531,11 +553,14 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * @param visitor the visitor * @param dimensionBinding the dimension binding to use */ - final void accept(boolean allowContent,QueryProfileVisitor visitor, DimensionBinding dimensionBinding, QueryProfile owner) { - visitor.onQueryProfile(this, dimensionBinding, owner); + final void accept(boolean allowContent, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding, + QueryProfile owner) { + visitor.onQueryProfile(this, dimensionBinding, owner, null); if (visitor.isDone()) return; - visitVariants(allowContent,visitor,dimensionBinding); + visitVariants(allowContent, visitor, dimensionBinding); if (visitor.isDone()) return; if (allowContent) { @@ -547,31 +572,37 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable visitInherited(allowContent, visitor, dimensionBinding, owner); } - protected void visitVariants(boolean allowContent,QueryProfileVisitor visitor,DimensionBinding dimensionBinding) { + protected void visitVariants(boolean allowContent, QueryProfileVisitor visitor, DimensionBinding dimensionBinding) { if (getVariants() != null) getVariants().accept(allowContent, getType(), visitor, dimensionBinding); } - protected void visitInherited(boolean allowContent,QueryProfileVisitor visitor,DimensionBinding dimensionBinding, QueryProfile owner) { + protected void visitInherited(boolean allowContent, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding, + QueryProfile owner) { if (inherited == null) return; for (QueryProfile inheritedProfile : inherited) { - inheritedProfile.accept(allowContent, visitor, dimensionBinding.createFor(inheritedProfile.getDimensions()), owner); + inheritedProfile.accept(allowContent, + visitor, + dimensionBinding.createFor(inheritedProfile.getDimensions()), + owner); if (visitor.isDone()) return; } } - private void visitContent(QueryProfileVisitor visitor,DimensionBinding dimensionBinding) { + private void visitContent(QueryProfileVisitor visitor, DimensionBinding dimensionBinding) { String contentKey = visitor.getLocalKey(); // Visit this' content if (contentKey != null) { // Get only the content of the current key if (type != null) contentKey = type.unalias(contentKey); - visitor.acceptValue(contentKey, getContent(contentKey), dimensionBinding, this); + visitor.acceptValue(contentKey, getContent(contentKey), dimensionBinding, this, null); } else { // get all content in this for (Map.Entry<String,Object> entry : getContent().entrySet()) { - visitor.acceptValue(entry.getKey(), entry.getValue(), dimensionBinding, this); + visitor.acceptValue(entry.getKey(), entry.getValue(), dimensionBinding, this, null); if (visitor.isDone()) return; } } @@ -702,9 +733,8 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable * Looks up all inherited profiles and adds any that matches this name. * This default implementation returns an empty profile. */ - protected QueryProfile createSubProfile(String name,DimensionBinding dimensionBinding) { - QueryProfile queryProfile = new QueryProfile(ComponentId.createAnonymousComponentId(name)); - return queryProfile; + protected QueryProfile createSubProfile(String name, DimensionBinding dimensionBinding) { + return new QueryProfile(ComponentId.createAnonymousComponentId(name), source); } /** Do a variant-aware content lookup in this */ @@ -742,7 +772,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable ensureNotFrozen(); if (name.isCompound()) { QueryProfile parent = getQueryProfileExact(name.first(), true, dimensionBinding); - parent.setNode(name.rest(), value,parentType, dimensionBinding.createFor(parent.getDimensions()), registry); + parent.setNode(name.rest(), value, parentType, dimensionBinding.createFor(parent.getDimensions()), registry); } else { setLocalNode(name.toString(), value,parentType, dimensionBinding, registry); @@ -775,19 +805,18 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable */ private QueryProfile getQueryProfileExact(String localName, boolean create, DimensionBinding dimensionBinding) { Object node = localExactLookup(localName, dimensionBinding); - if (node != null && node instanceof QueryProfile) { - return (QueryProfile)node; - } - if (!create) return null; + if (node instanceof QueryProfile) return (QueryProfile)node; + + if ( ! create) return null; - QueryProfile queryProfile=createSubProfile(localName,dimensionBinding); + QueryProfile queryProfile = createSubProfile(localName,dimensionBinding); if (type != null) { - Class<?> legalClass=type.getValueClass(localName); + Class<?> legalClass = type.getValueClass(localName); if (legalClass == null || ! legalClass.isInstance(queryProfile)) throw new RuntimeException("'" + localName + "' is not a legal query profile reference name in " + this); queryProfile.setType(type.getType(localName)); } - localPut(localName,queryProfile,dimensionBinding); + localPut(localName, queryProfile, dimensionBinding); return queryProfile; } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileCompiler.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileCompiler.java index 588071459f0..3cc7570576b 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileCompiler.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileCompiler.java @@ -5,6 +5,7 @@ import com.yahoo.processing.request.CompoundName; import com.yahoo.search.query.profile.compiled.CompiledQueryProfile; import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry; import com.yahoo.search.query.profile.compiled.DimensionalMap; +import com.yahoo.search.query.profile.compiled.ValueWithSource; import com.yahoo.search.query.profile.types.QueryProfileType; import java.util.HashSet; @@ -31,7 +32,7 @@ public class QueryProfileCompiler { public static CompiledQueryProfile compile(QueryProfile in, CompiledQueryProfileRegistry registry) { try { - DimensionalMap.Builder<CompoundName, Object> values = new DimensionalMap.Builder<>(); + DimensionalMap.Builder<CompoundName, ValueWithSource> values = new DimensionalMap.Builder<>(); DimensionalMap.Builder<CompoundName, QueryProfileType> types = new DimensionalMap.Builder<>(); DimensionalMap.Builder<CompoundName, Object> references = new DimensionalMap.Builder<>(); DimensionalMap.Builder<CompoundName, Object> unoverridables = new DimensionalMap.Builder<>(); @@ -42,7 +43,7 @@ public class QueryProfileCompiler { log.fine(() -> "Compiling " + in.toString() + " having " + variants.size() + " variants"); for (DimensionBindingForPath variant : variants) { log.finer(() -> " Compiling variant " + variant); - for (Map.Entry<String, Object> entry : in.listValues(variant.path(), variant.binding().getContext(), null).entrySet()) { + for (Map.Entry<String, ValueWithSource> entry : in.visitValues(variant.path(), variant.binding().getContext()).valuesWithSource().entrySet()) { values.put(variant.path().append(entry.getKey()), variant.binding(), entry.getValue()); } for (Map.Entry<CompoundName, QueryProfileType> entry : in.listTypes(variant.path(), variant.binding().getContext()).entrySet()) 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 17940c00926..3f70ff98373 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 @@ -14,18 +14,18 @@ import java.util.*; */ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVariant> { - private List<QueryProfile> inherited=null; + private List<QueryProfile> inherited = null; private DimensionValues dimensionValues; - private Map<String,Object> values; + private Map<String, Object> values; - private boolean frozen=false; + private boolean frozen = false; private QueryProfile owner; public QueryProfileVariant(DimensionValues dimensionValues, QueryProfile owner) { - this.dimensionValues=dimensionValues; + this.dimensionValues = dimensionValues; this.owner = owner; } @@ -36,11 +36,11 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa * if this is not frozen. */ public Map<String,Object> values() { - if (values==null) { + if (values == null) { if (frozen) return Collections.emptyMap(); else - values=new HashMap<>(); + values = new HashMap<>(); } return values; } @@ -50,18 +50,18 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa * if this is not frozen. */ public List<QueryProfile> inherited() { - if (inherited==null) { + if (inherited == null) { if (frozen) return Collections.emptyList(); else - inherited=new ArrayList<>(); + inherited = new ArrayList<>(); } return inherited; } public void set(String key, Object newValue) { - if (values==null) - values=new HashMap<>(); + if (values == null) + values = new HashMap<>(); Object oldValue = values.get(key); @@ -76,8 +76,8 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa } public void inherit(QueryProfile profile) { - if (inherited==null) - inherited=new ArrayList<>(1); + if (inherited == null) + inherited = new ArrayList<>(1); inherited.add(profile); } @@ -98,20 +98,23 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa } /** Accepts a visitor to the values of this */ - public void accept(boolean allowContent,QueryProfileType type,QueryProfileVisitor visitor, DimensionBinding dimensionBinding) { + public void accept(boolean allowContent, + QueryProfileType type, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding) { // Visit this if (allowContent) { - String key=visitor.getLocalKey(); - if (key!=null) { - if (type!=null) + String key = visitor.getLocalKey(); + if (key != null) { + if (type != null) type.unalias(key); - visitor.acceptValue(key, values().get(key), dimensionBinding, owner); + visitor.acceptValue(key, values().get(key), dimensionBinding, owner, dimensionValues); if (visitor.isDone()) return; } else { - for (Map.Entry<String,Object> entry : values().entrySet()) { - visitor.acceptValue(entry.getKey(), entry.getValue(), dimensionBinding, owner); + for (Map.Entry<String, Object> entry : values().entrySet()) { + visitor.acceptValue(entry.getKey(), entry.getValue(), dimensionBinding, owner, dimensionValues); if (visitor.isDone()) return; } } @@ -120,7 +123,7 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa // Visit inherited for (QueryProfile profile : inherited()) { if (visitor.visitInherited()) { - profile.accept(allowContent,visitor,dimensionBinding.createFor(profile.getDimensions()), owner); + profile.accept(allowContent, visitor, dimensionBinding.createFor(profile.getDimensions()), owner); } if (visitor.isDone()) return; } @@ -138,11 +141,11 @@ public class QueryProfileVariant implements Cloneable, Comparable<QueryProfileVa public QueryProfileVariant clone() { if (frozen) return this; try { - QueryProfileVariant clone=(QueryProfileVariant)super.clone(); - if (this.inherited!=null) - clone.inherited=new ArrayList<>(this.inherited); // TODO: Deep clone is more correct, but probably does not matter in practice + QueryProfileVariant clone = (QueryProfileVariant)super.clone(); + if (this.inherited != null) + clone.inherited = new ArrayList<>(this.inherited); // TODO: Deep clone is more correct, but probably does not matter in practice - clone.values=CopyOnWriteContent.deepClone(this.values); + clone.values = CopyOnWriteContent.deepClone(this.values); return clone; } 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 50db98d54d4..8dedda800ea 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 @@ -24,19 +24,19 @@ import java.util.*; */ public class QueryProfileVariants implements Freezable, Cloneable { - private boolean frozen=false; + 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(); + private FieldValues inheritedProfiles =new FieldValues(); /** * Field and inherited profiles sorted by specificity used for all-value visiting. * This is the same as how the source data looks (apart from the sorting). */ - private List<QueryProfileVariant> variants=new ArrayList<>(); + private List<QueryProfileVariant> variants = new ArrayList<>(); /** * The names of the dimensions (which are possible properties in the context given on lookup) of this. @@ -94,54 +94,66 @@ public class QueryProfileVariants implements Freezable, Cloneable { } /** Visits the most specific match to the dimension binding of each variable (or the one named by the visitor) */ - void accept(boolean allowContent,QueryProfileType type,QueryProfileVisitor visitor,DimensionBinding dimensionBinding) { - String contentName=null; + void accept(boolean allowContent, + QueryProfileType type, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding) { + String contentName = null; if (allowContent) - contentName=visitor.getLocalKey(); + contentName = visitor.getLocalKey(); - if (contentName!=null) { - if (type!=null) - contentName=type.unalias(contentName); - acceptSingleValue(contentName,allowContent,visitor,dimensionBinding); // Special cased for performance + if (contentName != null) { + if (type != null) + contentName = type.unalias(contentName); + acceptSingleValue(contentName, allowContent, visitor, dimensionBinding); // Special cased for performance } else { - acceptAllValues(allowContent,visitor,type,dimensionBinding); + acceptAllValues(allowContent, visitor, type, dimensionBinding); } } - // PERF: 90% - void acceptSingleValue(String name,boolean allowContent,QueryProfileVisitor visitor,DimensionBinding dimensionBinding) { - FieldValues fieldValues=fieldValuesByName.get(name); - if (fieldValues==null || !allowContent) - fieldValues=new FieldValues(); + void acceptSingleValue(String name, + boolean allowContent, + QueryProfileVisitor visitor, + DimensionBinding dimensionBinding) { + FieldValues fieldValues = fieldValuesByName.get(name); + if (fieldValues == null || ! allowContent) + fieldValues = new FieldValues(); fieldValues.sort(); inheritedProfiles.sort(); - int inheritedIndex=0; - int fieldIndex=0; + int inheritedIndex = 0; + int fieldIndex = 0; // Go through both the fields and the inherited profiles at the same time and try the single must specific pick // from either of the lists at each step - while(fieldIndex<fieldValues.size() || inheritedIndex<inheritedProfiles.size()) { // PERF: 8% - fieldValues.size() + while(fieldIndex < fieldValues.size() || inheritedIndex < inheritedProfiles.size()) { // Get the next most specific from field and inherited - FieldValue fieldValue=fieldValues.getIfExists(fieldIndex); // PERF: 11% - getIfExists - FieldValue inheritedProfileValue=inheritedProfiles.getIfExists(inheritedIndex); // PERF: 11% - getIfExists + FieldValue fieldValue = fieldValues.getIfExists(fieldIndex); + FieldValue inheritedProfileValue = inheritedProfiles.getIfExists(inheritedIndex); // Try the most specific first, then the other - if (inheritedProfileValue==null || (fieldValue!=null && fieldValue.compareTo(inheritedProfileValue)<=0)) { // Field is most specific, or both are equally specific - if (fieldValue.matches(dimensionBinding.getValues())) { // PERF: 42% - matches, together with the other matches - visitor.acceptValue(name, fieldValue.getValue(), dimensionBinding, owner); + if (inheritedProfileValue == null || (fieldValue != null && fieldValue.compareTo(inheritedProfileValue) <= 0)) { // Field is most specific, or both are equally specific + if (fieldValue.matches(dimensionBinding.getValues())) { + visitor.acceptValue(name, + fieldValue.getValue(), + dimensionBinding, + owner, + fieldValue.getDimensionValues()); } if (visitor.isDone()) return; fieldIndex++; } - else if (inheritedProfileValue!=null) { // Inherited is most specific at this point - if (inheritedProfileValue.matches(dimensionBinding.getValues())) { // PERF: 42% - matches, together with the other matches + else if (inheritedProfileValue != null) { // Inherited is most specific at this point + if (inheritedProfileValue.matches(dimensionBinding.getValues())) { @SuppressWarnings("unchecked") - List<QueryProfile> inheritedProfileList=(List<QueryProfile>)inheritedProfileValue.getValue(); + List<QueryProfile> inheritedProfileList = (List<QueryProfile>)inheritedProfileValue.getValue(); for (QueryProfile inheritedProfile : inheritedProfileList) { if (visitor.visitInherited()) { - inheritedProfile.accept(allowContent,visitor,dimensionBinding.createFor(inheritedProfile.getDimensions()), owner); + inheritedProfile.accept(allowContent, + visitor, + dimensionBinding.createFor(inheritedProfile.getDimensions()), + owner); } if (visitor.isDone()) return; } @@ -152,12 +164,15 @@ public class QueryProfileVariants implements Freezable, Cloneable { } } - void acceptAllValues(boolean allowContent,QueryProfileVisitor visitor, QueryProfileType type,DimensionBinding dimensionBinding) { - if (!frozen) + void acceptAllValues(boolean allowContent, + QueryProfileVisitor visitor, + QueryProfileType type, + DimensionBinding dimensionBinding) { + if ( ! frozen) Collections.sort(variants); for (QueryProfileVariant variant : variants) { if (variant.matches(dimensionBinding.getValues())) - variant.accept(allowContent,type,visitor,dimensionBinding); + variant.accept(allowContent, type, visitor, dimensionBinding); if (visitor.isDone()) return; } } @@ -169,15 +184,15 @@ public class QueryProfileVariants implements Freezable, Cloneable { * @param dimensionBinding the dimension bindings to use in this */ public Object get(String name, QueryProfileType type, boolean allowQueryProfileResult, DimensionBinding dimensionBinding) { - SingleValueQueryProfileVisitor visitor=new SingleValueQueryProfileVisitor(Collections.singletonList(name),allowQueryProfileResult); + SingleValueQueryProfileVisitor visitor = new SingleValueQueryProfileVisitor(Collections.singletonList(name),allowQueryProfileResult); visitor.enter(""); - accept(true,type,visitor,dimensionBinding); + accept(true, type, visitor, dimensionBinding); visitor.leave(""); return visitor.getResult(); } /** Inherits a particular profile in a variant of this */ - public void inherit(QueryProfile profile,DimensionValues dimensionValues) { + public void inherit(QueryProfile profile, DimensionValues dimensionValues) { ensureNotFrozen(); // Update variant @@ -185,10 +200,10 @@ public class QueryProfileVariants implements Freezable, Cloneable { // Update per-variable optimized structure @SuppressWarnings("unchecked") - List<QueryProfile> inheritedAtDimensionValues=(List<QueryProfile>)inheritedProfiles.getExact(dimensionValues); - if (inheritedAtDimensionValues==null) { - inheritedAtDimensionValues=new ArrayList<>(); - inheritedProfiles.put(dimensionValues,inheritedAtDimensionValues); + List<QueryProfile> inheritedAtDimensionValues = (List<QueryProfile>)inheritedProfiles.getExact(dimensionValues); + if (inheritedAtDimensionValues == null) { + inheritedAtDimensionValues = new ArrayList<>(); + inheritedProfiles.put(dimensionValues, inheritedAtDimensionValues); } inheritedAtDimensionValues.add(profile); } @@ -197,33 +212,25 @@ public class QueryProfileVariants implements Freezable, Cloneable { * Sets a value to this * * @param fieldName the name of the field to set. This cannot be a compound (dotted) name - * @param binding the dimension values for which this value applies. - * The dimensions must be canonicalized, and ownership is transferred to this. - * @param value the value to set - */ - /** - * Sets a value to this - * - * @param fieldName the name of the field to set. This cannot be a compound (dotted) name * @param dimensionValues the dimension values for which this value applies * @param value the value to set */ - public void set(String fieldName,DimensionValues dimensionValues,Object value) { + public void set(String fieldName, DimensionValues dimensionValues, Object value) { ensureNotFrozen(); // Update variant - getVariant(dimensionValues,true).set(fieldName,value); + getVariant(dimensionValues, true).set(fieldName, value); // Update per-variable optimized structure - FieldValues fieldValues=fieldValuesByName.get(fieldName); - if (fieldValues==null) { - fieldValues=new FieldValues(); - fieldValuesByName.put(fieldName,fieldValues); + FieldValues fieldValues = fieldValuesByName.get(fieldName); + if (fieldValues == null) { + fieldValues = new FieldValues(); + fieldValuesByName.put(fieldName, fieldValues); } - Object combinedValue=QueryProfile.combineValues(value,fieldValues.getExact(dimensionValues)); - if (combinedValue!=null) - fieldValues.put(dimensionValues,combinedValue); + Object combinedValue = QueryProfile.combineValues(value, fieldValues.getExact(dimensionValues)); + if (combinedValue != null) + fieldValues.put(dimensionValues, combinedValue); } /** @@ -236,7 +243,7 @@ public class QueryProfileVariants implements Freezable, Cloneable { public List<String> getDimensions() { return dimensions; } /** Returns the map of field values of this indexed by field name. */ - public Map<String,FieldValues> getFieldValues() { return fieldValuesByName; } + public Map<String, FieldValues> getFieldValues() { return fieldValuesByName; } /** Returns the profiles inherited from various variants of this */ public FieldValues getInherited() { return inheritedProfiles; } @@ -253,16 +260,16 @@ public class QueryProfileVariants implements Freezable, Cloneable { public QueryProfileVariants clone() { try { if (frozen) return this; - QueryProfileVariants clone=(QueryProfileVariants)super.clone(); - clone.inheritedProfiles=inheritedProfiles.clone(); + QueryProfileVariants clone = (QueryProfileVariants)super.clone(); + clone.inheritedProfiles = inheritedProfiles.clone(); - clone.variants=new ArrayList<>(); + clone.variants = new ArrayList<>(); for (QueryProfileVariant variant : variants) clone.variants.add(variant.clone()); - clone.fieldValuesByName=new HashMap<>(); - for (Map.Entry<String,FieldValues> entry : fieldValuesByName.entrySet()) - clone.fieldValuesByName.put(entry.getKey(),entry.getValue().clone(entry.getKey(),clone.variants)); + clone.fieldValuesByName = new HashMap<>(); + for (Map.Entry<String, FieldValues> entry : fieldValuesByName.entrySet()) + clone.fieldValuesByName.put(entry.getKey(), entry.getValue().clone(entry.getKey(), clone.variants)); return clone; } @@ -285,14 +292,14 @@ public class QueryProfileVariants implements Freezable, Cloneable { * @param create whether or not to create the variant if missing * @return the profile variant, or null if not found and create is false */ - public QueryProfileVariant getVariant(DimensionValues dimensionValues,boolean create) { + public QueryProfileVariant getVariant(DimensionValues dimensionValues, boolean create) { for (QueryProfileVariant profileVariant : variants) if (profileVariant.getDimensionValues().equals(dimensionValues)) return profileVariant; // Not found - if (!create) return null; - QueryProfileVariant variant=new QueryProfileVariant(dimensionValues, owner); + if ( ! create) return null; + QueryProfileVariant variant = new QueryProfileVariant(dimensionValues, owner); variants.add(variant); return variant; } @@ -301,7 +308,7 @@ public class QueryProfileVariants implements Freezable, Cloneable { private List<FieldValue> resolutionList=null; - private boolean frozen=false; + private boolean frozen = false; @Override public void freeze() { @@ -317,20 +324,20 @@ public class QueryProfileVariants implements Freezable, Cloneable { return frozen; } - public void put(DimensionValues dimensionValues,Object value) { + public void put(DimensionValues dimensionValues, Object value) { ensureNotFrozen(); - if (resolutionList==null) resolutionList=new ArrayList<>(); - FieldValue fieldValue=getExactFieldValue(dimensionValues); - if (fieldValue!=null) // Replace + if (resolutionList == null) resolutionList = new ArrayList<>(); + FieldValue fieldValue = getExactFieldValue(dimensionValues); + if (fieldValue != null) // Replace fieldValue.setValue(value); else - resolutionList.add(new FieldValue(dimensionValues,value)); + resolutionList.add(new FieldValue(dimensionValues, value)); } /** Returns the value having exactly the given dimensions, or null if none */ public Object getExact(DimensionValues dimensionValues) { - FieldValue value=getExactFieldValue(dimensionValues); - if (value==null) return null; + FieldValue value = getExactFieldValue(dimensionValues); + if (value == null) return null; return value.getValue(); } @@ -344,24 +351,24 @@ public class QueryProfileVariants implements Freezable, Cloneable { /** Returns the field values (values for various dimensions) for this field as a read-only list (never null) */ public List<FieldValue> asList() { - if (resolutionList==null) return Collections.emptyList(); + if (resolutionList == null) return Collections.emptyList(); return resolutionList; } public FieldValue getIfExists(int index) { - if (index>=size()) return null; + if (index >= size()) return null; return resolutionList.get(index); } public void sort() { if (frozen) return ; // sorted already - if (resolutionList!=null) + if (resolutionList != null) Collections.sort(resolutionList); } /** Same as asList().size() */ public int size() { - if (resolutionList==null) return 0; + if (resolutionList == null) return 0; return resolutionList.size(); } @@ -375,12 +382,12 @@ public class QueryProfileVariants implements Freezable, Cloneable { public FieldValues clone(String fieldName,List<QueryProfileVariant> clonedVariants) { try { if (frozen) return this; - FieldValues clone=(FieldValues)super.clone(); + FieldValues clone = (FieldValues)super.clone(); - if (resolutionList!=null) { - clone.resolutionList=new ArrayList<>(resolutionList.size()); + if (resolutionList != null) { + clone.resolutionList = new ArrayList<>(resolutionList.size()); for (FieldValue value : resolutionList) - clone.resolutionList.add(value.clone(fieldName,clonedVariants)); + clone.resolutionList.add(value.clone(fieldName, clonedVariants)); } return clone; @@ -394,10 +401,10 @@ public class QueryProfileVariants implements Freezable, Cloneable { public FieldValues clone() { try { if (frozen) return this; - FieldValues clone=(FieldValues)super.clone(); + FieldValues clone = (FieldValues)super.clone(); - if (resolutionList!=null) { - clone.resolutionList=new ArrayList<>(resolutionList.size()); + if (resolutionList != null) { + clone.resolutionList = new ArrayList<>(resolutionList.size()); for (FieldValue value : resolutionList) clone.resolutionList.add(value.clone()); } @@ -416,9 +423,9 @@ public class QueryProfileVariants implements Freezable, Cloneable { private DimensionValues dimensionValues; private Object value; - public FieldValue(DimensionValues dimensionValues,Object value) { - this.dimensionValues=dimensionValues; - this.value=value; + public FieldValue(DimensionValues dimensionValues, Object value) { + this.dimensionValues = dimensionValues; + this.value = value; } /** @@ -453,9 +460,9 @@ public class QueryProfileVariants implements Freezable, Cloneable { /** Clone by filling in the value from the given variants */ public FieldValue clone(String fieldName,List<QueryProfileVariant> clonedVariants) { try { - FieldValue clone=(FieldValue)super.clone(); + FieldValue clone = (FieldValue)super.clone(); if (this.value instanceof QueryProfile) - clone.value=lookupInVariants(fieldName,dimensionValues,clonedVariants); + clone.value = lookupInVariants(fieldName, dimensionValues, clonedVariants); // Otherwise the value is immutable, so keep it as-is return clone; } @@ -466,8 +473,8 @@ public class QueryProfileVariants implements Freezable, Cloneable { public FieldValue clone() { try { - FieldValue clone=(FieldValue)super.clone(); - clone.value=QueryProfile.cloneIfNecessary(this.value); + FieldValue clone = (FieldValue)super.clone(); + clone.value = QueryProfile.cloneIfNecessary(this.value); return clone; } catch (CloneNotSupportedException e) { @@ -475,7 +482,7 @@ public class QueryProfileVariants implements Freezable, Cloneable { } } - private Object lookupInVariants(String fieldName,DimensionValues dimensionValues,List<QueryProfileVariant> variants) { + private Object lookupInVariants(String fieldName, DimensionValues dimensionValues, List<QueryProfileVariant> variants) { for (QueryProfileVariant variant : variants) { if ( ! variant.getDimensionValues().equals(dimensionValues)) continue; return variant.values().get(fieldName); diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVisitor.java index 5494e8f931d..f6ffeb777a5 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVisitor.java @@ -48,8 +48,13 @@ abstract class QueryProfileVisitor { * @param value the value * @param binding the binding this holds for * @param owner the query profile having this value, or null only when profile is the root profile + * @param variant the variant having this value, or null if it is not in a variant */ - public abstract void onValue(String localName, Object value, DimensionBinding binding, QueryProfile owner); + public abstract void onValue(String localName, + Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant); /** * Called when a query profile is encountered. @@ -57,8 +62,12 @@ abstract class QueryProfileVisitor { * @param profile the query profile reference encountered * @param binding the binding this holds for * @param owner the profile making this reference, or null only when profile is the root profile + * @param variant the variant having this value, or null if it is not in a variant */ - public abstract void onQueryProfile(QueryProfile profile, DimensionBinding binding, QueryProfile owner); + public abstract void onQueryProfile(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant); /** Returns whether this visitor is done visiting what it needed to visit at this point */ public abstract boolean isDone(); @@ -72,15 +81,23 @@ abstract class QueryProfileVisitor { */ public abstract String getLocalKey(); - /** Calls onValue or onQueryProfile on this and visits the content if it's a profile */ - final void acceptValue(String key, Object value, DimensionBinding dimensionBinding, QueryProfile owner) { - if (value==null) return; + /** + * Calls onValue or onQueryProfile on this and visits the content if it's a profile + * + * @param variant the variant having this value, or null if it is not in a variant + */ + final void acceptValue(String key, + Object value, + DimensionBinding dimensionBinding, + QueryProfile owner, + DimensionValues variant) { + if (value == null) return; if (value instanceof QueryProfile) { - QueryProfile queryProfileValue=(QueryProfile)value; + QueryProfile queryProfileValue = (QueryProfile)value; queryProfileValue.acceptAndEnter(key, this, dimensionBinding.createFor(queryProfileValue.getDimensions()), owner); } else { - onValue(key, value, dimensionBinding, owner); + onValue(key, value, dimensionBinding, owner, variant); } } diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/SingleValueQueryProfileVisitor.java b/container-search/src/main/java/com/yahoo/search/query/profile/SingleValueQueryProfileVisitor.java index 3bee56f7276..a0734f56e9a 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/SingleValueQueryProfileVisitor.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/SingleValueQueryProfileVisitor.java @@ -15,19 +15,19 @@ import java.util.List; final class SingleValueQueryProfileVisitor extends QueryProfileVisitor { /** The value found, or null if none */ - private Object value=null; + private Object value = null; private final List<String> name; - private int nameIndex=-1; + private int nameIndex = -1; private final boolean allowQueryProfileResult; - private boolean enteringContent=true; + private boolean enteringContent = true; - public SingleValueQueryProfileVisitor(List<String> name,boolean allowQueryProfileResult) { - this.name=name; - this.allowQueryProfileResult=allowQueryProfileResult; + public SingleValueQueryProfileVisitor(List<String> name, boolean allowQueryProfileResult) { + this.name = name; + this.allowQueryProfileResult = allowQueryProfileResult; } @Override @@ -37,12 +37,12 @@ final class SingleValueQueryProfileVisitor extends QueryProfileVisitor { @Override public boolean enter(String name) { - if (nameIndex+1<this.name.size()) { + if (nameIndex+1 < this.name.size()) { nameIndex++; - enteringContent=true; + enteringContent = true; } else { - enteringContent=false; + enteringContent = false; } return enteringContent; } @@ -53,13 +53,19 @@ final class SingleValueQueryProfileVisitor extends QueryProfileVisitor { } @Override - public void onValue(String key,Object value, DimensionBinding binding, QueryProfile owner) { - if (nameIndex==name.size()-1) - this.value=value; + public void onValue(String key,Object value, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { + if (nameIndex == name.size()-1) + this.value = value; } @Override - public void onQueryProfile(QueryProfile profile,DimensionBinding binding, QueryProfile owner) { + public void onQueryProfile(QueryProfile profile, + DimensionBinding binding, + QueryProfile owner, + DimensionValues variant) { if (enteringContent) return; // still waiting for content if (allowQueryProfileResult) this.value = profile; diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/CompiledQueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/CompiledQueryProfile.java index ea85a2be242..644d366e7d0 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/CompiledQueryProfile.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/CompiledQueryProfile.java @@ -12,7 +12,6 @@ import com.yahoo.search.query.profile.types.QueryProfileType; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,7 +30,7 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable private final QueryProfileType type; /** The values of this */ - private final DimensionalMap<CompoundName, Object> entries; + private final DimensionalMap<CompoundName, ValueWithSource> entries; /** Keys which have a type in this */ private final DimensionalMap<CompoundName, QueryProfileType> types; @@ -47,7 +46,7 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable */ public CompiledQueryProfile(ComponentId id, QueryProfileType type, - DimensionalMap<CompoundName, Object> entries, + DimensionalMap<CompoundName, ValueWithSource> entries, DimensionalMap<CompoundName, QueryProfileType> types, DimensionalMap<CompoundName, Object> references, DimensionalMap<CompoundName, Object> unoverridables, @@ -105,6 +104,7 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable */ public final Map<String, Object> listValues(CompoundName prefix) { return listValues(prefix, Collections.<String,String>emptyMap()); } public final Map<String, Object> listValues(String prefix) { return listValues(new CompoundName(prefix)); } + /** * Return all objects that start with the given prefix path. Use "" to list all. * <p> @@ -114,6 +114,7 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable public final Map<String, Object> listValues(String prefix, Map<String, String> context) { return listValues(new CompoundName(prefix), context); } + /** * Return all objects that start with the given prefix path. Use "" to list all. * <p> @@ -123,6 +124,7 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable public final Map<String, Object> listValues(CompoundName prefix, Map<String, String> context) { return listValues(prefix, context, null); } + /** * Adds all objects that start with the given path prefix to the given value map. Use "" to list all. * <p> @@ -131,11 +133,14 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable */ public Map<String, Object> listValues(CompoundName prefix, Map<String, String> context, Properties substitution) { Map<String, Object> values = new HashMap<>(); - for (Map.Entry<CompoundName, DimensionalValue<Object>> entry : entries.entrySet()) { + for (Map.Entry<CompoundName, DimensionalValue<ValueWithSource>> entry : entries.entrySet()) { if ( entry.getKey().size() <= prefix.size()) continue; if ( ! entry.getKey().hasPrefix(prefix)) continue; - Object value = entry.getValue().get(context); + ValueWithSource valueWithSource = entry.getValue().get(context); + if (valueWithSource == null) continue; + + Object value = valueWithSource.value(); if (value == null) continue; value = substitute(value, context, substitution); @@ -145,6 +150,24 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable return values; } + public Map<String, ValueWithSource> listValuesWithSources(CompoundName prefix, + Map<String, String> context, + Properties substitution) { + Map<String, ValueWithSource> values = new HashMap<>(); + for (Map.Entry<CompoundName, DimensionalValue<ValueWithSource>> entry : entries.entrySet()) { + if ( entry.getKey().size() <= prefix.size()) continue; + if ( ! entry.getKey().hasPrefix(prefix)) continue; + + ValueWithSource valueWithSource = entry.getValue().get(context); + if (valueWithSource == null) continue; + + valueWithSource = valueWithSource.withValue(substitute(valueWithSource.value(), context, substitution)); + CompoundName suffixName = entry.getKey().rest(prefix.size()); + values.put(suffixName.toString(), valueWithSource); + } + return values; + } + public final Object get(String name) { return get(name, Collections.emptyMap()); } @@ -155,7 +178,9 @@ public class CompiledQueryProfile extends AbstractComponent implements Cloneable return get(new CompoundName(name), context, substitution); } public final Object get(CompoundName name, Map<String, String> context, Properties substitution) { - return substitute(entries.get(name, context), context, substitution); + ValueWithSource value = entries.get(name, context); + if (value == null) return null; + return substitute(value.value(), context, substitution); } private Object substitute(Object value, Map<String, String> context, Properties substitution) { diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/DimensionalValue.java b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/DimensionalValue.java index 50d0a2de46f..b5481059ac0 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/DimensionalValue.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/DimensionalValue.java @@ -168,12 +168,14 @@ public class DimensionalValue<VALUE> { return value; } + // TODO: Move this @SuppressWarnings("unchecked") private VALUE substituteIfRelative(VALUE value, DimensionBinding variant, Map<CompoundName, DimensionalValue.Builder<VALUE>> entries) { - if (value instanceof SubstituteString) { - SubstituteString substitute = (SubstituteString)value; + if (value instanceof ValueWithSource && ((ValueWithSource)value).value() instanceof SubstituteString) { + ValueWithSource valueWithSource = (ValueWithSource)value; + SubstituteString substitute = (SubstituteString)valueWithSource.value(); if (substitute.hasRelative()) { List<SubstituteString.Component> resolvedComponents = new ArrayList<>(substitute.components().size()); for (SubstituteString.Component component : substitute.components()) { @@ -184,14 +186,14 @@ public class DimensionalValue<VALUE> { throw new IllegalArgumentException("Could not resolve local substitution '" + relativeComponent.fieldName() + "' in variant " + variant); - String resolved = substituteValues.valueFor(variant).toString(); - resolvedComponents.add(new SubstituteString.StringComponent(resolved)); + ValueWithSource resolved = (ValueWithSource)substituteValues.valueFor(variant); + resolvedComponents.add(new SubstituteString.StringComponent(resolved.value().toString())); } else { resolvedComponents.add(component); } } - return (VALUE)new SubstituteString(resolvedComponents, substitute.stringValue()); + return (VALUE)valueWithSource.withValue(new SubstituteString(resolvedComponents, substitute.stringValue())); } } return value; diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/ValueWithSource.java b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/ValueWithSource.java new file mode 100644 index 00000000000..925d20903c6 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/ValueWithSource.java @@ -0,0 +1,48 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.query.profile.compiled; + +import com.yahoo.search.query.profile.DimensionValues; + +import java.util.Optional; + +/** + * A value in a query profile with information about its source. + * + * @author bratseth + */ +public class ValueWithSource { + + private final Object value; + + /** The source of the query profile having a value */ + private final String source; + + /** The dimension values specifying a variant in that profile, or null if it is not in a variant */ + private final DimensionValues variant; + + public ValueWithSource(Object value, String source, DimensionValues variant) { + this.value = value; + this.source = source; + this.variant = variant; + } + + public Object value() { return value; } + + public String source() { return source; } + + public ValueWithSource withValue(Object value) { + return new ValueWithSource(value, source, variant); + } + + /** Returns the variant having this value, or empty if it's not in a variant */ + public Optional<DimensionValues> variant() { return Optional.ofNullable(variant); } + + @Override + public String toString() { + return value + + " (from query profile '" + source + "'" + + ( variant != null ? " variant " + variant : "") + + ")"; + } + +} 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 1af78982b9c..d3c232f84c5 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 @@ -74,7 +74,7 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber } private static void createProfile(QueryProfilesConfig.Queryprofile config, QueryProfileRegistry registry) { - QueryProfile profile = new QueryProfile(config.id()); + QueryProfile profile = new QueryProfile(new ComponentId(config.id()), config.id()); try { String typeId = config.type(); if (typeId != null && ! typeId.isEmpty()) 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 210b4899c58..33f07a58195 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 @@ -135,7 +135,7 @@ public class QueryProfileXMLReader { ComponentId id = new ComponentId(idString); validateFileNameToId(reader.getName(), id, "query profile"); - QueryProfile queryProfile = new QueryProfile(id); + QueryProfile queryProfile = new QueryProfile(id, reader.getName()); String typeId = root.getAttribute("type"); if (typeId != null && ! typeId.equals("")) { QueryProfileType type = registry.getType(typeId); 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 3c276157f72..46efb736918 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 @@ -3,16 +3,19 @@ package com.yahoo.search.query.profile.test; import com.yahoo.jdisc.http.HttpRequest.Method; 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.QueryProfile; import com.yahoo.search.query.profile.QueryProfileProperties; import com.yahoo.search.query.profile.QueryProfileRegistry; import com.yahoo.search.query.profile.compiled.CompiledQueryProfile; +import com.yahoo.search.query.profile.compiled.ValueWithSource; import com.yahoo.yolean.trace.TraceNode; import org.junit.Test; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -500,9 +503,32 @@ public class QueryProfileTestCase { QueryProfile p = new QueryProfile("test"); p.set("a","a-value", null); p.set("a.b","a.b-value", null); - Map<String,Object> values = p.compile(null).listValues("a"); - assertEquals(1,values.size()); - assertEquals("a.b-value",values.get("b")); + Map<String, Object> values = p.compile(null).listValues("a"); + assertEquals(1, values.size()); + assertEquals("a.b-value", values.get("b")); + } + + @Test + public void testListingSources() { + QueryProfile p = new QueryProfile("test"); + p.set("a","a-value", null); + p.set("a.b","a.b-value", null); + + { + Map<String, ValueWithSource> values = p.compile(null).listValuesWithSources(new CompoundName(""), new HashMap<>(), null); + assertEquals(2, values.size()); + assertEquals("a-value", values.get("a").value()); + assertEquals("test", values.get("a").source()); + assertEquals("a.b-value", values.get("a.b").value()); + assertEquals("test", values.get("a.b").source()); + } + + { + Map<String, ValueWithSource> values = p.compile(null).listValuesWithSources(new CompoundName("a"), new HashMap<>(), null); + assertEquals(1, values.size()); + assertEquals("a.b-value", values.get("b").value()); + assertEquals("test", values.get("b").source()); + } } @Test @@ -601,7 +627,7 @@ public class QueryProfileTestCase { Query query = new Query("?foo=value&tracelevel=4", cProfile); assertEquals("value", query.properties().get("property")); - assertTrue(traceContains("foo=value", query)); + assertTrue(traceContains("foo: value", query)); } // NB: NOT RECURSIVE diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsCloneTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsCloneTestCase.java index 84326d9370d..aa1d1c243a0 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsCloneTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsCloneTestCase.java @@ -18,9 +18,6 @@ import static org.junit.Assert.assertEquals; */ public class QueryProfileVariantsCloneTestCase { - /** - * Test for Ticket 4882480. - */ @Test public void test_that_interior_and_leaf_values_on_a_path_are_preserved_when_cloning() { Map<String, String> dimensionBinding = createDimensionBinding("location", "norway"); diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsTestCase.java index b4112b17c92..73b455c147b 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsTestCase.java @@ -3,6 +3,7 @@ package com.yahoo.search.query.profile.test; import com.yahoo.jdisc.http.HttpRequest.Method; import com.yahoo.container.jdisc.HttpRequest; +import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.query.Properties; import com.yahoo.search.query.profile.BackedOverridableQueryProfile; @@ -11,6 +12,7 @@ import com.yahoo.search.query.profile.QueryProfileProperties; import com.yahoo.search.query.profile.QueryProfileRegistry; import com.yahoo.search.query.profile.compiled.CompiledQueryProfile; import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry; +import com.yahoo.search.query.profile.compiled.ValueWithSource; import com.yahoo.yolean.trace.TraceNode; import org.junit.Test; @@ -93,6 +95,32 @@ public class QueryProfileVariantsTestCase { assertEquals("default_value", new Query("?", cTest).properties().get("feed.main.streams")); assertEquals("variant_value", new Query("?x=x1&y=y1&z=z1", cTest).properties().get("feed.main.streams")); + + { + Map<String, ValueWithSource> values = cRegistry.findQueryProfile("test") + .listValuesWithSources(new CompoundName(""), + new HashMap<>(), + null); + assertEquals(1, values.size()); + assertEquals("default_value", values.get("feed.main.streams").value()); + assertEquals("referenced", values.get("feed.main.streams").source()); + assertTrue(values.get("feed.main.streams").variant().isEmpty()); + } + + { + Map<String, ValueWithSource> values = cRegistry.findQueryProfile("test") + .listValuesWithSources(new CompoundName(""), + toMap("x=x1", "y=y1", "z=z1"), + null); + assertEquals(2, values.size()); + assertEquals("variant_value", values.get("feed.main.streams").value()); + assertEquals("referenced", values.get("feed.main.streams").source()); + assertEquals("[x1, *, z1]", values.get("feed.main.streams").variant().get().toString()); + + assertEquals("otherValue", values.get("other").value()); + assertEquals("parent", values.get("other").source()); + assertEquals("[x1, y1]", values.get("other").variant().get().toString()); + } } @Test diff --git a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java index 1a68f14af06..a83a0e84bbf 100644 --- a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java @@ -362,7 +362,7 @@ public class JsonRendererTestCase { + " \"message\": \"No query profile is used\"" + " }," + " {" - + " \"message\": \"Resolved properties:\\ntracelevel=10 (value from request)\\nquery=a (value from request)\\n\"" + + " \"message\": \"Resolved properties:\\ntracelevel: 10 (from request)\\nquery: a (from request)\\n\"" + " }," + " {" + " \"children\": [" @@ -395,7 +395,7 @@ public class JsonRendererTestCase { Map<String, Object> subtrace = (Map<String, Object>) children1.get(2); List<Object> children2 = (List<Object>) subtrace.get("children"); Map<String, Object> traceElement = (Map<String, Object>) children2.get(0); - traceElement.put("timestamp", Integer.valueOf(42)); + traceElement.put("timestamp", 42); } assertEquals(exp, gen); } 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 fb628156aab..8c6c4e31808 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 @@ -93,7 +93,6 @@ public class QueryTestCase { and.addItem(new WordItem(token.getTokenString(), "body")); } query.getModel().getQueryTree().setRoot(and); - System.out.println(query); } // TODO: YQL work in progress (jon) @@ -380,8 +379,6 @@ public class QueryTestCase { Query q = new Query(QueryTestCase.httpEncode("?query=a:>5&a=b&traceLevel=5&sources=a,b&u=12&foo.bar2=wiz2&c.d=foo&queryProfile=test"),testProfile.compile(null)); String trace = q.getContext(false).getTrace().toString(); String[] traceLines = trace.split("\n"); - for (String line : traceLines) - System.out.println(line); } @Test @@ -515,12 +512,12 @@ public class QueryTestCase { Query q = new Query(QueryTestCase.httpEncode("?query=a:>5&a=b&traceLevel=5&sources=a,b&u=12&foo.bar2=wiz2&c.d=foo&queryProfile=test"),testProfile.compile(null)); String trace = q.getContext(false).getTrace().toString(); String[] traceLines = trace.split("\n"); - assertTrue(contains("query=a:>5 (value from request)", traceLines)); - assertTrue(contains("traceLevel=5 (value from request)", traceLines)); - assertTrue(contains("a=b (value from request)", traceLines)); - assertTrue(contains("sources=[a, b] (value from request)", traceLines)); - assertTrue(contains("d=e (value from query profile)", traceLines)); - assertTrue(contains("u=11 (value from query profile - unoverridable, ignoring request value)", traceLines)); + assertTrue(contains("query: a:>5 (from request)", traceLines)); + assertTrue(contains("traceLevel: 5 (from request)", traceLines)); + assertTrue(contains("a: b (from request)", traceLines)); + assertTrue(contains("sources: [a, b] (from request)", traceLines)); + assertTrue(contains("d: e (from query profile 'test')", traceLines)); + assertTrue(contains("u: 11 (from query profile - unoverridable, ignoring request value)", traceLines)); } @Test @@ -547,8 +544,8 @@ public class QueryTestCase { Query q = new Query(QueryTestCase.httpEncode("?query=dvd&a.b=foo&tracelevel=9"), defaultProfile.compile(null)); String trace = q.getContext(false).getTrace().toString(); String[] traceLines = trace.split("\n"); - assertTrue(contains("query=dvd (value from request)", traceLines)); - assertTrue(contains("a.b=foo (value from request)", traceLines)); + assertTrue(contains("query: dvd (from request)", traceLines)); + assertTrue(contains("a.b: foo (from request)", traceLines)); } @Test @@ -574,7 +571,7 @@ public class QueryTestCase { assertEquals("a.b-x1-value", propertyList.get("a.b")); String trace = q.getContext(false).getTrace().toString(); String[] traceLines = trace.split("\n"); - assertTrue(contains("a.b=a.b-x1-value (value from query profile)", traceLines)); + assertTrue(contains("a.b: a.b-x1-value (from query profile 'default' variant [x1])", traceLines)); } { @@ -590,7 +587,7 @@ public class QueryTestCase { assertEquals("a.b-x2-value", propertyList.get("a.b")); String trace = q.getContext(false).getTrace().toString(); String[] traceLines = trace.split("\n"); - assertTrue(contains("a.b=a.b-x2-value (value from query profile)", traceLines)); + assertTrue(contains("a.b: a.b-x2-value (from query profile 'default' variant [x2])", traceLines)); } } |