diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-04-04 10:02:52 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2022-04-04 10:02:52 +0200 |
commit | 5973587421282738babb1be7fe1cd45acd21ddfc (patch) | |
tree | 76913364cdc05fa420ed45687e3c426d7d554d14 | |
parent | 00641e5eef7d792ff376d20922f451de042539c2 (diff) |
Allow inputs declarations in rank profiles
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(); + } + } |