summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2019-10-28 20:21:00 +0100
committerGitHub <noreply@github.com>2019-10-28 20:21:00 +0100
commit6b5b636501fb8b553e8c5fbf72eefa42a54f8012 (patch)
tree35bb80f446a3fe6321aa6d7d3555699724f044a7
parentea50378f8348b474f42d099794ac914517dc141f (diff)
parent6376e0d4c2a6da939e68be55195e95369e0c3e20 (diff)
Merge pull request #11136 from vespa-engine/bratseth/query-profile-value-sources
Bratseth/query profile value sources
-rw-r--r--container-search/abi-spec.json21
-rw-r--r--container-search/src/main/java/com/yahoo/search/Query.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/AllReferencesQueryProfileVisitor.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/AllTypesQueryProfileVisitor.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/AllUnoverridableQueryProfileVisitor.java15
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/AllValuesQueryProfileVisitor.java35
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/BackedOverridableQueryProfile.java26
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/DimensionValues.java35
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/FieldDescriptionQueryProfileVisitor.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/OverridableQueryProfile.java16
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/PrefixQueryProfileVisitor.java12
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java95
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileCompiler.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariant.java51
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVariants.java193
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileVisitor.java31
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/SingleValueQueryProfileVisitor.java32
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/compiled/CompiledQueryProfile.java37
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/compiled/DimensionalValue.java12
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/compiled/ValueWithSource.java48
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileXMLReader.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileTestCase.java34
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsCloneTestCase.java3
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/test/QueryProfileVariantsTestCase.java28
-rw-r--r--container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java4
-rw-r--r--container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java23
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" =&gt; "a.d-value","e" =&gt; "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&lt;QueryProfile&gt; */
- 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));
}
}