summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-04-04 10:02:52 +0200
committerJon Bratseth <bratseth@gmail.com>2022-04-04 10:02:52 +0200
commit5973587421282738babb1be7fe1cd45acd21ddfc (patch)
tree76913364cdc05fa420ed45687e3c426d7d554d14
parent00641e5eef7d792ff376d20922f451de042539c2 (diff)
Allow inputs declarations in rank profiles
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/FeatureNames.java13
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/MapEvaluationTypeContext.java2
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java79
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java18
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/processing/RankingExpressionTypeResolver.java6
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/processing/multifieldresolver/RankProfileTypeSettingsProcessor.java15
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/search/QueryProfiles.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/ml/ConvertedModel.java4
-rw-r--r--config-model/src/main/javacc/SDParser.jj48
-rw-r--r--config-model/src/test/derived/neuralnet/neuralnet.sd56
-rw-r--r--config-model/src/test/derived/neuralnet_noqueryprofile/neuralnet.sd248
-rw-r--r--config-model/src/test/derived/neuralnet_noqueryprofile/rank-profiles.cfg174
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/FeatureNamesTestCase.java4
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/derived/NeuralNetTestCase.java18
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java6
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/CompositeNode.java2
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java10
17 files changed, 602 insertions, 109 deletions
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/FeatureNames.java b/config-model/src/main/java/com/yahoo/searchdefinition/FeatureNames.java
index 4066760d549..a226fa4812f 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/FeatureNames.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/FeatureNames.java
@@ -11,6 +11,7 @@ import java.util.Optional;
* @author bratseth
*/
public class FeatureNames {
+
public static Reference asConstantFeature(String constantName) {
return Reference.simple("constant", quoteIfNecessary(constantName));
}
@@ -36,6 +37,18 @@ public class FeatureNames {
return reference.name().equals("constant");
}
+ /** Returns true if this is a query feature */
+ public static boolean isQueryFeature(Reference reference) {
+ if ( ! isSimpleFeature(reference)) return false;
+ return reference.name().equals("query");
+ }
+
+ /** Returns true if this is an attribute feature */
+ public static boolean isAttributeFeature(Reference reference) {
+ if ( ! isSimpleFeature(reference)) return false;
+ return reference.name().equals("attribute");
+ }
+
/**
* Returns the single argument of the given feature name, without any quotes,
* or empty if it is not a valid query, attribute or constant feature name
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/MapEvaluationTypeContext.java b/config-model/src/main/java/com/yahoo/searchdefinition/MapEvaluationTypeContext.java
index 08475813317..23538deed66 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/MapEvaluationTypeContext.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/MapEvaluationTypeContext.java
@@ -86,6 +86,8 @@ public class MapEvaluationTypeContext extends FunctionReferenceContext implement
queryFeaturesNotDeclared.remove(reference);
}
+ public Map<Reference, TensorType> featureTypes() { return Collections.unmodifiableMap(featureTypes); }
+
@Override
public TensorType getType(String reference) {
throw new UnsupportedOperationException("Not able to parse general references from string form");
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java b/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java
index 0f2c1cf9a15..6ab9600f424 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java
@@ -47,7 +47,6 @@ import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -62,21 +61,19 @@ public class RankProfile implements Cloneable {
public final static String FIRST_PHASE = "firstphase";
public final static String SECOND_PHASE = "secondphase";
- /** The search definition-unique name of this rank profile */
+ /** The schema-unique name of this rank profile */
private final String name;
/** The schema owning this profile, or null if global (owned by a model) */
private final ImmutableSchema schema;
- /** The name of the rank profile inherited by this */
private final List<String> inheritedNames = new ArrayList<>();
- /** Stores the resolved inherited profiles, or null when not resolved. */
+
+ /** The resolved inherited profiles, or null when not resolved. */
private List<RankProfile> inherited;
- /** The match settings of this profile */
private MatchPhaseSettings matchPhaseSettings = null;
- /** The rank settings of this profile */
protected Set<RankSetting> rankSettings = new java.util.LinkedHashSet<>();
/** The ranking expression to be used for first phase */
@@ -117,7 +114,7 @@ public class RankProfile implements Cloneable {
// This cache must be invalidated every time modifications are done to 'functions'.
private CachedFunctions allFunctionsCached = null;
- private Map<Reference, TensorType> inputFeatures = new LinkedHashMap<>();
+ private Map<Reference, TensorType> inputs = new LinkedHashMap<>();
private Set<String> filterFields = new HashSet<>();
@@ -461,14 +458,6 @@ public class RankProfile implements Cloneable {
return attributeTypes.getTypes();
}
- public void addQueryFeatureType(String queryFeature, String queryFeatureType) {
- queryFeatureTypes.addType(queryFeature, queryFeatureType);
- }
-
- public Map<String, String> getQueryFeatureTypes() {
- return queryFeatureTypes.getTypes();
- }
-
/**
* Returns the ranking expression to use by this. This expression must not be edited.
* Returns null if no expression is set.
@@ -755,20 +744,42 @@ public class RankProfile implements Cloneable {
}
/**
- * Use for rank profiles representing a model evaluation; it will assume
- * that a input is provided with the declared type (for the purpose of
- * type resolving).
- **/
- public void addInputFeature(String name, TensorType declaredType) {
- Reference ref = Reference.fromIdentifier(name);
- if (inputFeatures.containsKey(ref)) {
- TensorType hadType = inputFeatures.get(ref);
- if (! declaredType.equals(hadType)) {
- throw new IllegalArgumentException("Tried to replace input feature "+name+" with different type: "+
- hadType+" -> "+declaredType);
+ * Adds the type of an input feature consumed by this profile.
+ * All inputs must either be declared through this or in query profile types,
+ * otherwise they are assumes to be scalars.
+ */
+ public void addInput(Reference reference, TensorType declaredType) {
+ if (inputs.containsKey(reference)) {
+ TensorType hadType = inputs().get(reference);
+ if (! declaredType.equals(hadType))
+ throw new IllegalArgumentException("Duplicate input '" + name + "' declared with both type " +
+ hadType + " and " + declaredType);
+ }
+ inputs.put(reference, declaredType);
+ }
+
+ /** Returns the inputs of this, which also includes all inputs of the parents of this. */
+ // This is less restrictive than most other constructs in allowing inputs to be defined in all parent profiles
+ // because inputs are tied closer to functions than the profile itself.
+ public Map<Reference, TensorType> inputs() {
+ if (inputs.isEmpty() && inherited().isEmpty()) return Map.of();
+ if (inherited().isEmpty()) return Collections.unmodifiableMap(inputs);
+
+ // Combine
+ Map<Reference, TensorType> allInputs = new LinkedHashMap<>();
+ for (var inheritedProfile : inherited()) {
+ for (var input : inheritedProfile.inputs().entrySet()) {
+ TensorType existingType = allInputs.get(input.getKey());
+ if (existingType != null && ! existingType.equals(input.getValue()))
+ throw new IllegalArgumentException(this + " inherits " + inheritedProfile + " which contains " +
+ input.getValue() + ", with type " + input.getValue() + "" +
+ " but this input is already defined with type " + existingType +
+ " in another profile this inherits");
+ inputs.put(input.getKey(), input.getValue());
}
}
- inputFeatures.put(ref, declaredType);
+ allInputs.putAll(inputs);
+ return Collections.unmodifiableMap(allInputs);
}
public static class MutateOperation {
@@ -902,7 +913,7 @@ public class RankProfile implements Cloneable {
clone.matchFeatures = matchFeatures != null ? new LinkedHashSet<>(this.matchFeatures) : null;
clone.rankFeatures = rankFeatures != null ? new LinkedHashSet<>(this.rankFeatures) : null;
clone.rankProperties = new LinkedHashMap<>(this.rankProperties);
- clone.inputFeatures = new LinkedHashMap<>(this.inputFeatures);
+ clone.inputs = new LinkedHashMap<>(this.inputs);
clone.functions = new LinkedHashMap<>(this.functions);
clone.allFunctionsCached = null;
clone.filterFields = new HashSet<>(this.filterFields);
@@ -933,7 +944,7 @@ public class RankProfile implements Cloneable {
checkNameCollisions(getFunctions(), getConstants());
ExpressionTransforms expressionTransforms = new ExpressionTransforms();
- Map<Reference, TensorType> featureTypes = collectFeatureTypes();
+ Map<Reference, TensorType> featureTypes = featureTypes();
// Function compiling first pass: compile inline functions without resolving other functions
Map<String, RankingExpressionFunction> inlineFunctions =
compileFunctions(this::getInlineFunctions, queryProfiles, featureTypes, importedModels, Collections.emptyMap(), expressionTransforms);
@@ -1017,16 +1028,13 @@ public class RankProfile implements Cloneable {
* referable from this rank profile.
*/
public MapEvaluationTypeContext typeContext(QueryProfileRegistry queryProfiles) {
- return typeContext(queryProfiles, collectFeatureTypes());
+ return typeContext(queryProfiles, featureTypes());
}
public MapEvaluationTypeContext typeContext() { return typeContext(new QueryProfileRegistry()); }
- private Map<Reference, TensorType> collectFeatureTypes() {
- Map<Reference, TensorType> featureTypes = new HashMap<>();
- // Add input features
- inputFeatures.forEach((k, v) -> featureTypes.put(k, v));
- // Add attributes
+ private Map<Reference, TensorType> featureTypes() {
+ Map<Reference, TensorType> featureTypes = new HashMap<>(inputs());
allFields().forEach(field -> addAttributeFeatureTypes(field, featureTypes));
allImportedFields().forEach(field -> addAttributeFeatureTypes(field, featureTypes));
return featureTypes;
@@ -1046,6 +1054,7 @@ public class RankProfile implements Cloneable {
TensorType type = field.getType().asTensorType();
Optional<Reference> feature = Reference.simple(field.getName());
if ( feature.isEmpty() || ! feature.get().name().equals("query")) continue;
+ if (featureTypes.containsKey(feature)) continue; // Explicit feature types (from inputs) overrides
TensorType existingType = context.getType(feature.get());
if ( ! Objects.equals(existingType, context.defaultTypeOf(feature.get())))
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
index f024eb6eb77..a4b2d17b76d 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
@@ -7,6 +7,7 @@ import com.yahoo.collections.Pair;
import com.yahoo.compress.Compressor;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.search.query.profile.QueryProfileRegistry;
+import com.yahoo.searchdefinition.FeatureNames;
import com.yahoo.searchdefinition.OnnxModel;
import com.yahoo.searchdefinition.LargeRankExpressions;
import com.yahoo.searchdefinition.RankExpressionBody;
@@ -15,6 +16,7 @@ import com.yahoo.searchdefinition.RankProfile;
import com.yahoo.searchdefinition.expressiontransforms.OnnxModelTransformer;
import com.yahoo.searchlib.rankingexpression.ExpressionFunction;
import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.parser.ParseException;
import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode;
import com.yahoo.searchlib.rankingexpression.rule.SerializationContext;
@@ -149,7 +151,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
*/
private final NativeRankTypeDefinitionSet nativeRankTypeDefinitions = new NativeRankTypeDefinitionSet("default");
private final Map<String, String> attributeTypes;
- private final Map<String, String> queryFeatureTypes;
+ private final Map<Reference, TensorType> inputs;
private final Set<String> filterFields = new java.util.LinkedHashSet<>();
private final String rankprofileName;
@@ -165,7 +167,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
QueryProfileRegistry queryProfiles) {
rankprofileName = compiled.name();
attributeTypes = compiled.getAttributeTypes();
- queryFeatureTypes = compiled.getQueryFeatureTypes();
+ inputs = compiled.inputs();
firstPhaseRanking = compiled.getFirstPhaseRanking();
secondPhaseRanking = compiled.getSecondPhaseRanking();
summaryFeatures = new LinkedHashSet<>(compiled.getSummaryFeatures());
@@ -277,11 +279,9 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
private void deriveWeightProperties(RankProfile rankProfile) {
for (RankProfile.RankSetting setting : rankProfile.rankSettings()) {
- if (!setting.getType().equals(RankProfile.RankSetting.Type.WEIGHT)) {
- continue;
- }
+ if (setting.getType() != RankProfile.RankSetting.Type.WEIGHT) continue;
boostAndWeightRankProperties.add(new RankProfile.RankProperty("vespa.fieldweight." + setting.getFieldName(),
- String.valueOf(setting.getIntValue())));
+ String.valueOf(setting.getIntValue())));
}
}
@@ -424,8 +424,10 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
for (Map.Entry<String, String> attributeType : attributeTypes.entrySet()) {
properties.add(new Pair<>("vespa.type.attribute." + attributeType.getKey(), attributeType.getValue()));
}
- for (Map.Entry<String, String> queryFeatureType : queryFeatureTypes.entrySet()) {
- properties.add(new Pair<>("vespa.type.query." + queryFeatureType.getKey(), queryFeatureType.getValue()));
+ for (Map.Entry<Reference, TensorType> input : inputs.entrySet()) {
+ if (FeatureNames.isQueryFeature(input.getKey()))
+ properties.add(new Pair<>("vespa.type.query." + input.getKey().arguments().expressions().get(0),
+ input.getValue().toString()));
}
if (properties.size() >= 1000000) throw new IllegalArgumentException("Too many rank properties");
distributeLargeExpressionsAsFiles(properties, largeRankExpressions);
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/RankingExpressionTypeResolver.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/RankingExpressionTypeResolver.java
index 4154526d950..fdf1dc187cf 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/RankingExpressionTypeResolver.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/RankingExpressionTypeResolver.java
@@ -106,12 +106,12 @@ public class RankingExpressionTypeResolver extends Processor {
return function.arguments().size() > function.argumentTypes().size();
}
- private TensorType resolveType(RankingExpression expression, String expressionDescription, TypeContext context) {
+ private TensorType resolveType(RankingExpression expression, String expressionDescription, TypeContext<Reference> context) {
if (expression == null) return null;
return resolveType(expression.getRoot(), expressionDescription, context);
}
- private TensorType resolveType(ExpressionNode expression, String expressionDescription, TypeContext context) {
+ private TensorType resolveType(ExpressionNode expression, String expressionDescription, TypeContext<Reference> context) {
TensorType type;
try {
type = expression.type(context);
@@ -124,7 +124,7 @@ public class RankingExpressionTypeResolver extends Processor {
return type;
}
- private void ensureValidDouble(RankingExpression expression, String expressionDescription, TypeContext context) {
+ private void ensureValidDouble(RankingExpression expression, String expressionDescription, TypeContext<Reference> context) {
if (expression == null) return;
TensorType type = resolveType(expression, expressionDescription, context);
if ( ! type.equals(TensorType.empty))
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/multifieldresolver/RankProfileTypeSettingsProcessor.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/multifieldresolver/RankProfileTypeSettingsProcessor.java
index 260d76c8ca3..9de6a11ce44 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/multifieldresolver/RankProfileTypeSettingsProcessor.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/multifieldresolver/RankProfileTypeSettingsProcessor.java
@@ -15,13 +15,15 @@ import com.yahoo.searchdefinition.document.ImmutableSDField;
import com.yahoo.searchdefinition.document.ImportedField;
import com.yahoo.searchdefinition.document.ImportedFields;
import com.yahoo.searchdefinition.processing.Processor;
+import com.yahoo.searchlib.rankingexpression.Reference;
+import com.yahoo.tensor.TensorType;
import com.yahoo.vespa.model.container.search.QueryProfiles;
import java.util.Map;
import java.util.Optional;
/**
- * This processes a search instance and sets type settings on all rank profiles.
+ * This processes a schema and adds input type settings on all rank profiles.
*
* Currently, type settings are limited to the type of tensor attribute fields and tensor query features.
*
@@ -83,18 +85,19 @@ public class RankProfileTypeSettingsProcessor extends Processor {
}
private void processFieldDescription(FieldDescription fieldDescription) {
- String fieldName = fieldDescription.getName();
FieldType fieldType = fieldDescription.getType();
if (fieldType instanceof TensorFieldType) {
TensorFieldType tensorFieldType = (TensorFieldType)fieldType;
- FeatureNames.argumentOf(fieldName).ifPresent(argument ->
- addQueryFeatureTypeToRankProfiles(argument, tensorFieldType.asTensorType().toString()));
+ Optional<Reference> reference = Reference.simple(fieldDescription.getName());
+ if (reference.isPresent() && FeatureNames.isQueryFeature(reference.get()))
+ addQueryFeatureTypeToRankProfiles(reference.get(), tensorFieldType.asTensorType());
}
}
- private void addQueryFeatureTypeToRankProfiles(String queryFeature, String queryFeatureType) {
+ private void addQueryFeatureTypeToRankProfiles(Reference queryFeature, TensorType queryFeatureType) {
for (RankProfile profile : rankProfileRegistry.all()) {
- profile.addQueryFeatureType(queryFeature, queryFeatureType);
+ if (! profile.inputs().containsKey(queryFeature)) // declared inputs have precedence
+ profile.addInput(queryFeature, queryFeatureType);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/search/QueryProfiles.java b/config-model/src/main/java/com/yahoo/vespa/model/container/search/QueryProfiles.java
index e22df1b4ec3..e2bc9897c85 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/search/QueryProfiles.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/search/QueryProfiles.java
@@ -228,8 +228,10 @@ public class QueryProfiles implements Serializable, QueryProfilesConfig.Producer
if (stringValue!=null) refB.value(stringValue);
}
- private QueryProfilesConfig.Queryprofile.Property.Builder createPropertyFieldConfig(
- QueryProfile profile, String fullName, String localName, Object value) {
+ private QueryProfilesConfig.Queryprofile.Property.Builder createPropertyFieldConfig(QueryProfile profile,
+ String fullName,
+ String localName,
+ Object value) {
QueryProfilesConfig.Queryprofile.Property.Builder propB = new QueryProfilesConfig.Queryprofile.Property.Builder();
Boolean overridable=null;
if (value instanceof SubstituteString)
@@ -287,7 +289,7 @@ public class QueryProfiles implements Serializable, QueryProfilesConfig.Producer
return fB;
}
- public String toSpaceSeparatedString(List<String> list) {
+ private String toSpaceSeparatedString(List<String> list) {
StringBuilder b = new StringBuilder();
for (Iterator<String> i = list.iterator(); i.hasNext(); ) {
b.append(i.next());
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/ml/ConvertedModel.java b/config-model/src/main/java/com/yahoo/vespa/model/ml/ConvertedModel.java
index 38b1d42862e..8cbd94a8a49 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/ml/ConvertedModel.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/ml/ConvertedModel.java
@@ -215,7 +215,7 @@ public class ConvertedModel {
for (ImportedMlFunction outputFunction : model.outputExpressions()) {
ExpressionFunction expression = asExpressionFunction(outputFunction);
for (Map.Entry<String, TensorType> input : expression.argumentTypes().entrySet()) {
- profile.addInputFeature(input.getKey(), input.getValue());
+ profile.addInput(Reference.fromIdentifier(input.getKey()), input.getValue());
}
addExpression(expression, expression.getName(), constantsReplacedByFunctions,
store, profile, queryProfiles, expressions);
@@ -283,7 +283,7 @@ public class ConvertedModel {
String name = output.getFirst();
ExpressionFunction expression = output.getSecond();
for (Map.Entry<String, TensorType> input : expression.argumentTypes().entrySet()) {
- profile.addInputFeature(input.getKey(), input.getValue());
+ profile.addInput(Reference.fromIdentifier(input.getKey()), input.getValue());
}
TensorType type = expression.getBody().type(profile.typeContext());
if (type != null) {
diff --git a/config-model/src/main/javacc/SDParser.jj b/config-model/src/main/javacc/SDParser.jj
index c4542c36779..724239fc9b7 100644
--- a/config-model/src/main/javacc/SDParser.jj
+++ b/config-model/src/main/javacc/SDParser.jj
@@ -46,6 +46,7 @@ import com.yahoo.searchdefinition.fieldoperation.*;
import com.yahoo.searchlib.rankingexpression.FeatureList;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.searchlib.rankingexpression.evaluation.TensorValue;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorType;
import com.yahoo.vespa.documentmodel.DocumentSummary;
@@ -137,9 +138,9 @@ public class SDParser {
/**
* Parses the given token image as a ranking expression feature list.
*
- * @param image The token image to parse.
- * @return The consumed feature list.
- * @throws ParseException Thrown if the image could not be parsed.
+ * @param image the token image to parse
+ * @return the consumed feature list
+ * @throws ParseException thrown if the image could not be parsed.
*/
private FeatureList getFeatureList(String image) throws ParseException {
try {
@@ -205,6 +206,7 @@ TOKEN :
| < WEIGHT: "weight" >
| < TYPE: "type" >
| < INDEX: "index" >
+| < INPUTS: "inputs">
| < MTOKEN: "token" >
| < TEXT: "text" >
| < WORD: "word" >
@@ -218,6 +220,7 @@ TOKEN :
| < ONNXMODEL: "onnx-model">
| < MODEL: "model" >
| < MUTATE: "mutate" >
+| < QUERY: "query" >
| < RANKPROFILE: "rank-profile" >
| < RANKDEGRADATIONFREQ: "rank-degradation-frequency" >
| < RANKDEGRADATION: "rank-degradation" >
@@ -1975,6 +1978,7 @@ void rankProfileItem(RankProfile profile) : { }
| rankProperties(profile)
| secondPhase(profile)
| rankDegradation(profile)
+ | inputs(profile)
| constants(profile)
| matchFeatures(profile)
| summaryFeatures(profile)
@@ -2187,11 +2191,28 @@ void secondPhaseItem(RankProfile profile) :
)
}
-/**
- * This rule consumes a summary-features block of a rank profile.
- *
- * @param profile The rank profile to modify.
- */
+/** Consumes an inputs block of a rank profile. */
+void inputs(RankProfile profile) :
+{
+ Reference reference;
+ TensorType type;
+}
+{
+ <INPUTS> <LBRACE> (<NL>)*
+ ( reference = queryFeature() <COLON> type = tensorType("Type of " + reference) { profile.addInput(reference, type); } (<NL>)*) *
+ <RBRACE>
+}
+
+Reference queryFeature() :
+{
+ String argument;
+}
+{
+ <QUERY> "(" argument = identifier() ")"
+ { return Reference.simple("query", argument); }
+}
+
+/** Consumes a summary-features block of a rank profile. */
void summaryFeatures(RankProfile profile) :
{
String features;
@@ -2476,9 +2497,7 @@ void rankDegradation(RankProfile profile) :
)
}
-/**
- * Consumes a set of constants available in ranking expressions in the enclosing profile.
- */
+/** Consumes a set of constants available in ranking expressions in the enclosing profile. */
void constants(RankProfile profile) :
{
String name;
@@ -2633,6 +2652,8 @@ String identifier() : { }
| <COMPRESSION>
| <COMPRESSIONLEVEL>
| <COMPRESSIONTHRESHOLD>
+ | <CONSTANT>
+ | <CONSTANTS>
| <CONTEXT>
| <CREATEIFNONEXISTENT>
| <DENSEPOSTINGLISTTHRESHOLD>
@@ -2671,6 +2692,8 @@ String identifier() : { }
| <INDEXING>
| <INDEXINGREWRITE>
| <INHERITS>
+ | <INLINE>
+ | <INPUTS>
| <INTEGER>
| <KEEPRANKCOUNT>
| <LITERAL>
@@ -2699,6 +2722,7 @@ String identifier() : { }
| <PRIMARY>
| <PROPERTIES>
| <QUATERNARY>
+ | <QUERY>
| <QUERYCOMMAND>
| <RANK>
| <MODEL>
@@ -2746,8 +2770,6 @@ String identifier() : { }
| <WEIGHT>
| <WEIGHTEDSET>
| <WORD>
- | <INLINE>
- | <CONSTANTS>
)
{ return token.image; }
}
diff --git a/config-model/src/test/derived/neuralnet/neuralnet.sd b/config-model/src/test/derived/neuralnet/neuralnet.sd
index 0df5ea69f50..b67081e71a7 100644
--- a/config-model/src/test/derived/neuralnet/neuralnet.sd
+++ b/config-model/src/test/derived/neuralnet/neuralnet.sd
@@ -75,95 +75,95 @@ search neuralnet {
maxSignedSixtyFourBitInteger: 9223372036854775807
}
- macro log10_1p(x) {
+ function log10_1p(x) {
expression: log10(x+1)
}
- macro textScoreToUse() {
+ function textScoreToUse() {
expression: if(isNan(attribute(normalizedTextScore)) == 1, 0, attribute(normalizedTextScore))
}
- macro rCountToUse() {
+ function rCountToUse() {
expression: if(isNan(attribute(rCount)) == 1, 0, if(attribute(rCount) < 0, 0, attribute(rCount)))
}
- macro uniqueRCountToUse() {
+ function uniqueRCountToUse() {
expression: if(isNan(attribute(uniqueRCount)) == 1, 0, if(attribute(uniqueRACount) < 0, 0, attribute(uniqueRACount)))
}
- macro uvCountToUse() {
+ function uvCountToUse() {
expression: if(isNan(attribute(uvCount)) == 1, 0, if(attribute(uvCount) < 0, 0, attribute(uvCount)))
}
- macro dvCountToUse() {
+ function dvCountToUse() {
expression: if(isNan(attribute(dvCount)) == 1, 0, if(attribute(dvCount) < 0, 0, attribute(dvCount)))
}
- macro aVoteCountToUse() {
+ function aVoteCountToUse() {
expression: if(isNan(attribute(aVoteCount)) == 1, 0, if(attribute(aVoteCount) < 0, 0, attribute(aVoteCount)))
}
- macro totalPR() {
+ function totalPR() {
expression: uniqueRCountToUse + query(voteToRRatio) * (uvCountToUse - dvCountToUse) - aVoteCountToUse
}
- macro totalvote() {
+ function totalvote() {
expression: query(reportaweight) * aVoteCountToUse + dvCountToUse + query(rweight) * uniqueRCountToUse + uvCountToUse
}
- macro phat() {
+ function phat() {
expression: if (totalvote == 0, 0, ( query(rweight) * uniqueRCountToUse + uvCountToUse) / totalvote)
}
- macro nCScoreToUse() {
+ function nCScoreToUse() {
expression: if (totalPR > 0, log10(totalPR), 0)
}
- macro hsScoreToUse() {
+ function hsScoreToUse() {
expression: attribute(hsScore)
}
- macro tScoreToUse() {
+ function tScoreToUse() {
expression: if (isNan(attribute(t)) == 1, 0.6, attribute(t))
}
- macro relevanceScoreToUse() {
+ function relevanceScoreToUse() {
expression: if (isNan(attribute(relevance)) == 1, 0.254, attribute(relevance))
}
- macro freshnessToUse() {
+ function freshnessToUse() {
expression: if (freshness(createdAt).logscale < 0.01, 0.01, freshness(createdAt).logscale)
}
- macro rankedAt() {
+ function rankedAt() {
expression: now
}
- macro createdAtToUse() {
+ function createdAtToUse() {
expression: if(isNan(attribute(createdAt)) == 1, rankedAt, attribute(createdAt))
}
- macro laAtToUse() {
+ function laAtToUse() {
expression: if(isNan(attribute(laAt)) == 1, attribute(createdAt), attribute(laAt))
}
- macro markedAsAAtToUse() {
+ function markedAsAAtToUse() {
expression: if(isNan(attribute(markedAsAAt)) == 1, maxSignedSixtyFourBitInteger, attribute(markedAsAAt))
}
- macro tdToUse() {
+ function tdToUse() {
expression: pow(2, 0 - ((rankedAt - createdAtToUse) / query(decay)))
}
- macro commentOverallScore() {
+ function commentOverallScore() {
expression: query(textweight) * textScoreToUse + query(communityweight) * nCScoreToUse
}
- macro pinScore() {
+ function pinScore() {
expression: if(isNan(attribute(pinned)) == 1, 0, query(pinweight) * attribute(pinned))
}
- macro freshnessRank() {
+ function freshnessRank() {
expression: nativeRank + freshness(createdAt)
}
@@ -174,7 +174,7 @@ search neuralnet {
}
rank-profile neuralNetworkProfile inherits defaultRankProfile {
- macro nn_input() {
+ function nn_input() {
expression {
concat(log10_1p(aVoteCountToUse),
concat(log10_1p(dvCountToUse),
@@ -188,17 +188,17 @@ search neuralnet {
}
}
- macro get_model_weights(field) {
+ function get_model_weights(field) {
expression: if(query(field) == 0, constant(field), query(field))
}
- macro layer_0() {
+ function layer_0() {
expression: elu(xw_plus_b(nn_input, get_model_weights(W_0), get_model_weights(b_0), x))
}
- macro layer_1() {
+ function layer_1() {
expression: elu(xw_plus_b(layer_0, get_model_weights(W_1), get_model_weights(b_1), hidden))
}
- macro layer_out() {
+ function layer_out() {
expression: sum(xw_plus_b(layer_1, get_model_weights(W_out), get_model_weights(b_out), out))
}
first-phase {
diff --git a/config-model/src/test/derived/neuralnet_noqueryprofile/neuralnet.sd b/config-model/src/test/derived/neuralnet_noqueryprofile/neuralnet.sd
new file mode 100644
index 00000000000..8b2ccae34ef
--- /dev/null
+++ b/config-model/src/test/derived/neuralnet_noqueryprofile/neuralnet.sd
@@ -0,0 +1,248 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+search neuralnet {
+
+ document neuralnet {
+
+ field pinned type int {
+ indexing: attribute
+ }
+
+ field createdAt type long {
+ indexing: attribute
+ }
+
+ field updatedAt type long {
+ indexing: attribute
+ }
+
+ field uvCount type int {
+ indexing: attribute
+ }
+
+ field dvCount type int {
+ indexing: attribute
+ }
+
+ field aVoteCount type int {
+ indexing: attribute
+ }
+
+ field rCount type int {
+ indexing: attribute
+ }
+
+ field uniqueRACount type int {
+ indexing: attribute
+ }
+
+ field rTo type string {
+ indexing: attribute
+ }
+
+ field markedAsAAt type long {
+ indexing: attribute
+ }
+
+ field normalizedTextScore type float {
+ indexing: attribute
+ }
+
+ field t type float {
+ indexing: attribute
+ }
+
+ field relevance type float {
+ indexing: attribute
+ }
+
+ field normalizedCS type float {
+ indexing: attribute
+ }
+
+ field laAt type long {
+ indexing: attribute
+ }
+
+ field hsScore type double {
+ indexing: attribute
+ }
+
+ }
+
+ rank-profile defaultRankProfile inherits default {
+
+ inputs {
+ query(W_0): tensor(x[9],hidden[9])
+ query(b_0): tensor(hidden[9])
+ query(W_1): tensor(hidden[9],out[9])
+ query(b_1): tensor(out[9])
+ query(W_out): tensor(out[9])
+ query(b_out): tensor(out[1])
+ }
+
+ constants {
+ maxSignedSixtyFourBitInteger: 9223372036854775807
+ }
+
+ function log10_1p(x) {
+ expression: log10(x+1)
+ }
+
+ function textScoreToUse() {
+ expression: if(isNan(attribute(normalizedTextScore)) == 1, 0, attribute(normalizedTextScore))
+ }
+
+ function rCountToUse() {
+ expression: if(isNan(attribute(rCount)) == 1, 0, if(attribute(rCount) < 0, 0, attribute(rCount)))
+ }
+
+ function uniqueRCountToUse() {
+ expression: if(isNan(attribute(uniqueRCount)) == 1, 0, if(attribute(uniqueRACount) < 0, 0, attribute(uniqueRACount)))
+ }
+
+ function uvCountToUse() {
+ expression: if(isNan(attribute(uvCount)) == 1, 0, if(attribute(uvCount) < 0, 0, attribute(uvCount)))
+ }
+
+ function dvCountToUse() {
+ expression: if(isNan(attribute(dvCount)) == 1, 0, if(attribute(dvCount) < 0, 0, attribute(dvCount)))
+ }
+
+ function aVoteCountToUse() {
+ expression: if(isNan(attribute(aVoteCount)) == 1, 0, if(attribute(aVoteCount) < 0, 0, attribute(aVoteCount)))
+ }
+
+ function totalPR() {
+ expression: uniqueRCountToUse + query(voteToRRatio) * (uvCountToUse - dvCountToUse) - aVoteCountToUse
+ }
+
+ function totalvote() {
+ expression: query(reportaweight) * aVoteCountToUse + dvCountToUse + query(rweight) * uniqueRCountToUse + uvCountToUse
+ }
+
+ function phat() {
+ expression: if (totalvote == 0, 0, ( query(rweight) * uniqueRCountToUse + uvCountToUse) / totalvote)
+ }
+
+ function nCScoreToUse() {
+ expression: if (totalPR > 0, log10(totalPR), 0)
+ }
+
+ function hsScoreToUse() {
+ expression: attribute(hsScore)
+ }
+
+ function tScoreToUse() {
+ expression: if (isNan(attribute(t)) == 1, 0.6, attribute(t))
+ }
+
+ function relevanceScoreToUse() {
+ expression: if (isNan(attribute(relevance)) == 1, 0.254, attribute(relevance))
+ }
+
+ function freshnessToUse() {
+ expression: if (freshness(createdAt).logscale < 0.01, 0.01, freshness(createdAt).logscale)
+ }
+
+ function rankedAt() {
+ expression: now
+ }
+
+ function createdAtToUse() {
+ expression: if(isNan(attribute(createdAt)) == 1, rankedAt, attribute(createdAt))
+ }
+
+ function laAtToUse() {
+ expression: if(isNan(attribute(laAt)) == 1, attribute(createdAt), attribute(laAt))
+ }
+
+ function markedAsAAtToUse() {
+ expression: if(isNan(attribute(markedAsAAt)) == 1, maxSignedSixtyFourBitInteger, attribute(markedAsAAt))
+ }
+
+ function tdToUse() {
+ expression: pow(2, 0 - ((rankedAt - createdAtToUse) / query(decay)))
+ }
+
+ function commentOverallScore() {
+ expression: query(textweight) * textScoreToUse + query(communityweight) * nCScoreToUse
+ }
+
+ function pinScore() {
+ expression: if(isNan(attribute(pinned)) == 1, 0, query(pinweight) * attribute(pinned))
+ }
+
+ function freshnessRank() {
+ expression: nativeRank + freshness(createdAt)
+ }
+
+ first-phase {
+ expression: nativeRank
+ }
+
+ }
+
+ rank-profile neuralNetworkProfile inherits defaultRankProfile {
+ function nn_input() {
+ expression {
+ concat(log10_1p(aVoteCountToUse),
+ concat(log10_1p(dvCountToUse),
+ concat(log10_1p(uniqueRCountToUse),
+ concat(log10_1p(uvCountToUse),
+ concat(phat,
+ concat(log10_1p(totalvote),
+ concat(hsScoreToUse,
+ concat(tdToUse,
+ tScoreToUse, x), x), x), x), x), x), x), x)
+ }
+ }
+
+ function get_model_weights(field) {
+ expression: if(query(field) == 0, constant(field), query(field))
+ }
+
+ function layer_0() {
+ expression: elu(xw_plus_b(nn_input, get_model_weights(W_0), get_model_weights(b_0), x))
+ }
+ function layer_1() {
+ expression: elu(xw_plus_b(layer_0, get_model_weights(W_1), get_model_weights(b_1), hidden))
+ }
+ function layer_out() {
+ expression: sum(xw_plus_b(layer_1, get_model_weights(W_out), get_model_weights(b_out), out))
+ }
+ first-phase {
+ expression: freshnessRank
+ }
+ second-phase {
+ expression: layer_out
+ rerank-count: 2000
+ }
+
+ }
+
+ constant W_0 {
+ file: neural-network-201805/W_0.json
+ type: tensor(x[9],hidden[9])
+ }
+ constant b_0 {
+ file: neural-network-201805/b_0.json
+ type: tensor(hidden[9])
+ }
+ constant W_1 {
+ file: neural-network-201805/W_1.json
+ type: tensor(hidden[9],out[9])
+ }
+ constant b_1 {
+ file: neural-network-201805/b_1.json
+ type: tensor(out[9])
+ }
+ constant W_out {
+ file: neural-network-201805/W_out.json
+ type: tensor(out[9])
+ }
+ constant b_out {
+ file: neural-network-201805/b_out.json
+ type: tensor(out[1])
+ }
+
+}
diff --git a/config-model/src/test/derived/neuralnet_noqueryprofile/rank-profiles.cfg b/config-model/src/test/derived/neuralnet_noqueryprofile/rank-profiles.cfg
new file mode 100644
index 00000000000..9c3cfd28b9a
--- /dev/null
+++ b/config-model/src/test/derived/neuralnet_noqueryprofile/rank-profiles.cfg
@@ -0,0 +1,174 @@
+rankprofile[].name "default"
+rankprofile[].name "unranked"
+rankprofile[].fef.property[].name "vespa.rank.firstphase"
+rankprofile[].fef.property[].value "value(0)"
+rankprofile[].fef.property[].name "vespa.hitcollector.heapsize"
+rankprofile[].fef.property[].value "0"
+rankprofile[].fef.property[].name "vespa.hitcollector.arraysize"
+rankprofile[].fef.property[].value "0"
+rankprofile[].fef.property[].name "vespa.dump.ignoredefaultfeatures"
+rankprofile[].fef.property[].value "true"
+rankprofile[].name "defaultRankProfile"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p).rankingScript"
+rankprofile[].fef.property[].value "log10(x + 1)"
+rankprofile[].fef.property[].name "rankingExpression(textScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(normalizedTextScore)) == 1, 0, attribute(normalizedTextScore))"
+rankprofile[].fef.property[].name "rankingExpression(rCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(rCount)) == 1, 0, if (attribute(rCount) < 0, 0, attribute(rCount)))"
+rankprofile[].fef.property[].name "rankingExpression(uniqueRCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(uniqueRCount)) == 1, 0, if (attribute(uniqueRACount) < 0, 0, attribute(uniqueRACount)))"
+rankprofile[].fef.property[].name "rankingExpression(uvCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(uvCount)) == 1, 0, if (attribute(uvCount) < 0, 0, attribute(uvCount)))"
+rankprofile[].fef.property[].name "rankingExpression(dvCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(dvCount)) == 1, 0, if (attribute(dvCount) < 0, 0, attribute(dvCount)))"
+rankprofile[].fef.property[].name "rankingExpression(aVoteCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(aVoteCount)) == 1, 0, if (attribute(aVoteCount) < 0, 0, attribute(aVoteCount)))"
+rankprofile[].fef.property[].name "rankingExpression(totalPR).rankingScript"
+rankprofile[].fef.property[].value "rankingExpression(uniqueRCountToUse) + query(voteToRRatio) * (rankingExpression(uvCountToUse) - rankingExpression(dvCountToUse)) - rankingExpression(aVoteCountToUse)"
+rankprofile[].fef.property[].name "rankingExpression(totalvote).rankingScript"
+rankprofile[].fef.property[].value "query(reportaweight) * rankingExpression(aVoteCountToUse) + rankingExpression(dvCountToUse) + query(rweight) * rankingExpression(uniqueRCountToUse) + rankingExpression(uvCountToUse)"
+rankprofile[].fef.property[].name "rankingExpression(phat).rankingScript"
+rankprofile[].fef.property[].value "if (rankingExpression(totalvote) == 0, 0, (query(rweight) * rankingExpression(uniqueRCountToUse) + rankingExpression(uvCountToUse)) / rankingExpression(totalvote))"
+rankprofile[].fef.property[].name "rankingExpression(nCScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (rankingExpression(totalPR) > 0, log10(rankingExpression(totalPR)), 0)"
+rankprofile[].fef.property[].name "rankingExpression(hsScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "attribute(hsScore)"
+rankprofile[].fef.property[].name "rankingExpression(tScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(t)) == 1, 0.6, attribute(t))"
+rankprofile[].fef.property[].name "rankingExpression(relevanceScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(relevance)) == 1, 0.254, attribute(relevance))"
+rankprofile[].fef.property[].name "rankingExpression(freshnessToUse).rankingScript"
+rankprofile[].fef.property[].value "if (freshness(createdAt).logscale < 0.01, 0.01, freshness(createdAt).logscale)"
+rankprofile[].fef.property[].name "rankingExpression(rankedAt).rankingScript"
+rankprofile[].fef.property[].value "now"
+rankprofile[].fef.property[].name "rankingExpression(createdAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(createdAt)) == 1, rankingExpression(rankedAt), attribute(createdAt))"
+rankprofile[].fef.property[].name "rankingExpression(laAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(laAt)) == 1, attribute(createdAt), attribute(laAt))"
+rankprofile[].fef.property[].name "rankingExpression(markedAsAAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(markedAsAAt)) == 1, 9223372036854775807, attribute(markedAsAAt))"
+rankprofile[].fef.property[].name "rankingExpression(tdToUse).rankingScript"
+rankprofile[].fef.property[].value "pow(2,0 - ((rankingExpression(rankedAt) - rankingExpression(createdAtToUse)) / query(decay)))"
+rankprofile[].fef.property[].name "rankingExpression(commentOverallScore).rankingScript"
+rankprofile[].fef.property[].value "query(textweight) * rankingExpression(textScoreToUse) + query(communityweight) * rankingExpression(nCScoreToUse)"
+rankprofile[].fef.property[].name "rankingExpression(pinScore).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(pinned)) == 1, 0, query(pinweight) * attribute(pinned))"
+rankprofile[].fef.property[].name "rankingExpression(freshnessRank).rankingScript"
+rankprofile[].fef.property[].value "nativeRank + freshness(createdAt)"
+rankprofile[].fef.property[].name "vespa.rank.firstphase"
+rankprofile[].fef.property[].value "nativeRank"
+rankprofile[].fef.property[].name "vespa.type.query.b_out"
+rankprofile[].fef.property[].value "tensor(out[1])"
+rankprofile[].fef.property[].name "vespa.type.query.W_out"
+rankprofile[].fef.property[].value "tensor(out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.b_0"
+rankprofile[].fef.property[].value "tensor(hidden[9])"
+rankprofile[].fef.property[].name "vespa.type.query.b_1"
+rankprofile[].fef.property[].value "tensor(out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.W_1"
+rankprofile[].fef.property[].value "tensor(hidden[9],out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.W_0"
+rankprofile[].fef.property[].value "tensor(hidden[9],x[9])"
+rankprofile[].name "neuralNetworkProfile"
+rankprofile[].fef.property[].name "rankingExpression(freshnessRank).rankingScript"
+rankprofile[].fef.property[].value "nativeRank + freshness(createdAt)"
+rankprofile[].fef.property[].name "rankingExpression(aVoteCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(aVoteCount)) == 1, 0, if (attribute(aVoteCount) < 0, 0, attribute(aVoteCount)))"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p@af9a8c53ba738798).rankingScript"
+rankprofile[].fef.property[].value "log10(rankingExpression(aVoteCountToUse) + 1)"
+rankprofile[].fef.property[].name "rankingExpression(dvCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(dvCount)) == 1, 0, if (attribute(dvCount) < 0, 0, attribute(dvCount)))"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p@6ad21b437fe95dd9).rankingScript"
+rankprofile[].fef.property[].value "log10(rankingExpression(dvCountToUse) + 1)"
+rankprofile[].fef.property[].name "rankingExpression(uniqueRCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(uniqueRCount)) == 1, 0, if (attribute(uniqueRACount) < 0, 0, attribute(uniqueRACount)))"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p@c05478688f81fe20).rankingScript"
+rankprofile[].fef.property[].value "log10(rankingExpression(uniqueRCountToUse) + 1)"
+rankprofile[].fef.property[].name "rankingExpression(uvCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(uvCount)) == 1, 0, if (attribute(uvCount) < 0, 0, attribute(uvCount)))"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p@53f0a2c000e82f4).rankingScript"
+rankprofile[].fef.property[].value "log10(rankingExpression(uvCountToUse) + 1)"
+rankprofile[].fef.property[].name "rankingExpression(totalvote).rankingScript"
+rankprofile[].fef.property[].value "query(reportaweight) * rankingExpression(aVoteCountToUse) + rankingExpression(dvCountToUse) + query(rweight) * rankingExpression(uniqueRCountToUse) + rankingExpression(uvCountToUse)"
+rankprofile[].fef.property[].name "rankingExpression(phat).rankingScript"
+rankprofile[].fef.property[].value "if (rankingExpression(totalvote) == 0, 0, (query(rweight) * rankingExpression(uniqueRCountToUse) + rankingExpression(uvCountToUse)) / rankingExpression(totalvote))"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p@d7da61ad34902e89).rankingScript"
+rankprofile[].fef.property[].value "log10(rankingExpression(totalvote) + 1)"
+rankprofile[].fef.property[].name "rankingExpression(hsScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "attribute(hsScore)"
+rankprofile[].fef.property[].name "rankingExpression(rankedAt).rankingScript"
+rankprofile[].fef.property[].value "now"
+rankprofile[].fef.property[].name "rankingExpression(createdAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(createdAt)) == 1, rankingExpression(rankedAt), attribute(createdAt))"
+rankprofile[].fef.property[].name "rankingExpression(tdToUse).rankingScript"
+rankprofile[].fef.property[].value "pow(2,0 - ((rankingExpression(rankedAt) - rankingExpression(createdAtToUse)) / query(decay)))"
+rankprofile[].fef.property[].name "rankingExpression(tScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(t)) == 1, 0.6, attribute(t))"
+rankprofile[].fef.property[].name "rankingExpression(nn_input).rankingScript"
+rankprofile[].fef.property[].value "concat(rankingExpression(log10_1p@af9a8c53ba738798), concat(rankingExpression(log10_1p@6ad21b437fe95dd9), concat(rankingExpression(log10_1p@c05478688f81fe20), concat(rankingExpression(log10_1p@53f0a2c000e82f4), concat(rankingExpression(phat), concat(rankingExpression(log10_1p@d7da61ad34902e89), concat(rankingExpression(hsScoreToUse), concat(rankingExpression(tdToUse), rankingExpression(tScoreToUse), x), x), x), x), x), x), x), x)"
+rankprofile[].fef.property[].name "rankingExpression(nn_input).type"
+rankprofile[].fef.property[].value "tensor(x[9])"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@1f2b4afc2c45fbee).rankingScript"
+rankprofile[].fef.property[].value "if (query(W_0) == 0, constant(W_0), query(W_0))"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@e752cecc7900ff3e).rankingScript"
+rankprofile[].fef.property[].value "if (query(b_0) == 0, constant(b_0), query(b_0))"
+rankprofile[].fef.property[].name "rankingExpression(layer_0).rankingScript"
+rankprofile[].fef.property[].value "elu(join(reduce(join(rankingExpression(nn_input), rankingExpression(get_model_weights@1f2b4afc2c45fbee), f(a,b)(a * b)), sum, x), rankingExpression(get_model_weights@e752cecc7900ff3e), f(a,b)(a + b)))"
+rankprofile[].fef.property[].name "rankingExpression(layer_0).type"
+rankprofile[].fef.property[].value "tensor(hidden[9])"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@eac265fa16b752cf).rankingScript"
+rankprofile[].fef.property[].value "if (query(W_1) == 0, constant(W_1), query(W_1))"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@b953c19adb7d2154).rankingScript"
+rankprofile[].fef.property[].value "if (query(b_1) == 0, constant(b_1), query(b_1))"
+rankprofile[].fef.property[].name "rankingExpression(layer_1).rankingScript"
+rankprofile[].fef.property[].value "elu(join(reduce(join(rankingExpression(layer_0), rankingExpression(get_model_weights@eac265fa16b752cf), f(a,b)(a * b)), sum, hidden), rankingExpression(get_model_weights@b953c19adb7d2154), f(a,b)(a + b)))"
+rankprofile[].fef.property[].name "rankingExpression(layer_1).type"
+rankprofile[].fef.property[].value "tensor(out[9])"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@418462473aa32b7d).rankingScript"
+rankprofile[].fef.property[].value "if (query(W_out) == 0, constant(W_out), query(W_out))"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights@23f46853cab72961).rankingScript"
+rankprofile[].fef.property[].value "if (query(b_out) == 0, constant(b_out), query(b_out))"
+rankprofile[].fef.property[].name "rankingExpression(layer_out).rankingScript"
+rankprofile[].fef.property[].value "reduce(join(reduce(join(rankingExpression(layer_1), rankingExpression(get_model_weights@418462473aa32b7d), f(a,b)(a * b)), sum, out), rankingExpression(get_model_weights@23f46853cab72961), f(a,b)(a + b)), sum)"
+rankprofile[].fef.property[].name "rankingExpression(log10_1p).rankingScript"
+rankprofile[].fef.property[].value "log10(x + 1)"
+rankprofile[].fef.property[].name "rankingExpression(textScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(normalizedTextScore)) == 1, 0, attribute(normalizedTextScore))"
+rankprofile[].fef.property[].name "rankingExpression(rCountToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(rCount)) == 1, 0, if (attribute(rCount) < 0, 0, attribute(rCount)))"
+rankprofile[].fef.property[].name "rankingExpression(totalPR).rankingScript"
+rankprofile[].fef.property[].value "rankingExpression(uniqueRCountToUse) + query(voteToRRatio) * (rankingExpression(uvCountToUse) - rankingExpression(dvCountToUse)) - rankingExpression(aVoteCountToUse)"
+rankprofile[].fef.property[].name "rankingExpression(nCScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (rankingExpression(totalPR) > 0, log10(rankingExpression(totalPR)), 0)"
+rankprofile[].fef.property[].name "rankingExpression(relevanceScoreToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(relevance)) == 1, 0.254, attribute(relevance))"
+rankprofile[].fef.property[].name "rankingExpression(freshnessToUse).rankingScript"
+rankprofile[].fef.property[].value "if (freshness(createdAt).logscale < 0.01, 0.01, freshness(createdAt).logscale)"
+rankprofile[].fef.property[].name "rankingExpression(laAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(laAt)) == 1, attribute(createdAt), attribute(laAt))"
+rankprofile[].fef.property[].name "rankingExpression(markedAsAAtToUse).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(markedAsAAt)) == 1, 9223372036854775807, attribute(markedAsAAt))"
+rankprofile[].fef.property[].name "rankingExpression(commentOverallScore).rankingScript"
+rankprofile[].fef.property[].value "query(textweight) * rankingExpression(textScoreToUse) + query(communityweight) * rankingExpression(nCScoreToUse)"
+rankprofile[].fef.property[].name "rankingExpression(pinScore).rankingScript"
+rankprofile[].fef.property[].value "if (isNan(attribute(pinned)) == 1, 0, query(pinweight) * attribute(pinned))"
+rankprofile[].fef.property[].name "rankingExpression(get_model_weights).rankingScript"
+rankprofile[].fef.property[].value "if (query(field) == 0, constant(field), query(field))"
+rankprofile[].fef.property[].name "vespa.rank.firstphase"
+rankprofile[].fef.property[].value "rankingExpression(freshnessRank)"
+rankprofile[].fef.property[].name "vespa.rank.secondphase"
+rankprofile[].fef.property[].value "rankingExpression(layer_out)"
+rankprofile[].fef.property[].name "vespa.hitcollector.heapsize"
+rankprofile[].fef.property[].value "2000"
+rankprofile[].fef.property[].name "vespa.type.query.b_out"
+rankprofile[].fef.property[].value "tensor(out[1])"
+rankprofile[].fef.property[].name "vespa.type.query.W_out"
+rankprofile[].fef.property[].value "tensor(out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.b_0"
+rankprofile[].fef.property[].value "tensor(hidden[9])"
+rankprofile[].fef.property[].name "vespa.type.query.b_1"
+rankprofile[].fef.property[].value "tensor(out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.W_1"
+rankprofile[].fef.property[].value "tensor(hidden[9],out[9])"
+rankprofile[].fef.property[].name "vespa.type.query.W_0"
+rankprofile[].fef.property[].value "tensor(hidden[9],x[9])"
diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/FeatureNamesTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/FeatureNamesTestCase.java
index c86b5aa93a2..3494ab780b2 100644
--- a/config-model/src/test/java/com/yahoo/searchdefinition/FeatureNamesTestCase.java
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/FeatureNamesTestCase.java
@@ -32,8 +32,8 @@ public class FeatureNamesTestCase {
@Test
public void testConstantFeature() {
- assertEquals("constant(\"foo/bar\")",
- FeatureNames.asConstantFeature("foo/bar").toString());
+ assertEquals("constant(foo)",
+ FeatureNames.asConstantFeature("foo").toString());
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/derived/NeuralNetTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/derived/NeuralNetTestCase.java
index d8f5446b6a5..ee82fd732ab 100644
--- a/config-model/src/test/java/com/yahoo/searchdefinition/derived/NeuralNetTestCase.java
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/derived/NeuralNetTestCase.java
@@ -2,6 +2,8 @@
package com.yahoo.searchdefinition.derived;
import com.yahoo.search.Query;
+import com.yahoo.search.query.profile.QueryProfile;
+import com.yahoo.search.query.profile.compiled.CompiledQueryProfile;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry;
import com.yahoo.search.query.profile.config.QueryProfileConfigurer;
import com.yahoo.searchdefinition.parser.ParseException;
@@ -20,12 +22,24 @@ public class NeuralNetTestCase extends AbstractExportingTestCase {
public void testNeuralNet() throws IOException, ParseException {
ComponentId.resetGlobalCountersForTests();
DerivedConfiguration c = assertCorrectDeriving("neuralnet");
+ // Verify that query profiles end up correct when passed through the same intermediate forms as a full system
+ CompiledQueryProfileRegistry queryProfiles =
+ QueryProfileConfigurer.createFromConfig(new QueryProfiles(c.getQueryProfiles(), (level, message) -> {}).getConfig()).compile();
+ assertNeuralNetQuery(c, queryProfiles.getComponent("default"));
+ }
+ @Test
+ public void testNeuralNet_noQueryProfiles() throws IOException, ParseException {
+ ComponentId.resetGlobalCountersForTests();
+ DerivedConfiguration c = assertCorrectDeriving("neuralnet_noqueryprofile");
// Verify that query profiles end up correct when passed through the same intermediate forms as a full system
CompiledQueryProfileRegistry queryProfiles =
QueryProfileConfigurer.createFromConfig(new QueryProfiles(c.getQueryProfiles(), (level, message) -> {}).getConfig()).compile();
- Query q = new Query("?test=foo&ranking.features.query(b_1)=[1,2,3,4,5,6,7,8,9]",
- queryProfiles.getComponent("default"));
+ assertNeuralNetQuery(c, queryProfiles.getComponent("default"));
+ }
+
+ private void assertNeuralNetQuery(DerivedConfiguration c, CompiledQueryProfile defaultprofile) {
+ Query q = new Query("?test=foo&ranking.features.query(b_1)=[1,2,3,4,5,6,7,8,9]", defaultprofile);
assertEquals("tensor(out[9]):[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]",
q.properties().get("ranking.features.query(b_1)").toString());
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java
index 75bbe55128c..656463a7b45 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java
@@ -12,6 +12,7 @@ import com.yahoo.tensor.evaluation.Name;
import java.util.Deque;
import java.util.Objects;
import java.util.Optional;
+import java.util.regex.Pattern;
/**
* A reference to a feature, function, or value in ranking expressions
@@ -30,7 +31,11 @@ public class Reference extends Name implements Comparable<Reference> {
/** True if this was created by the "fromIdentifier" method. This lets us separate 'foo()' and 'foo' */
private final boolean isIdentifier;
+ private final static Pattern identifierPattern = Pattern.compile("[A-Za-z0-9_@.\"-]+");
+
public static Reference fromIdentifier(String identifier) {
+ if ( ! identifierPattern.matcher(identifier).matches())
+ throw new IllegalArgumentException("Identifiers can only contain [A-Za-z0-9_]+, but was '" + identifier + "'");
return new Reference(identifier, Arguments.EMPTY, null, true);
}
@@ -48,7 +53,6 @@ public class Reference extends Name implements Comparable<Reference> {
this.isIdentifier = isIdentifier;
}
-
public Arguments arguments() { return arguments; }
public String output() { return output; }
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/CompositeNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/CompositeNode.java
index 6fdb233299b..451a961f641 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/CompositeNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/CompositeNode.java
@@ -11,7 +11,7 @@ import java.util.List;
public abstract class CompositeNode extends ExpressionNode {
/**
- * <p>Returns a read-only list containing the immediate children of this composite</p>
+ * Returns a read-only list containing the immediate children of this composite.
*
* @return The children of this.
*/
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
index 8ac1829b16b..aa6a6df0960 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
@@ -42,11 +42,6 @@ public final class ReferenceNode extends CompositeNode {
return reference.name();
}
- @Override
- public int hashCode() {
- return reference.hashCode();
- }
-
/** Returns the arguments, never null */
public Arguments getArguments() { return reference.arguments(); }
@@ -138,4 +133,9 @@ public final class ReferenceNode extends CompositeNode {
return setArguments(newChildren);
}
+ @Override
+ public int hashCode() {
+ return reference.hashCode();
+ }
+
}