diff options
author | Jon Bratseth <bratseth@gmail.com> | 2023-03-02 21:18:03 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-02 21:18:03 +0100 |
commit | 3d3d8fbbfe3577c34039e22e51438415442da7d0 (patch) | |
tree | 3fed20816f0c44095fc88417f4a2d39c88697221 | |
parent | e8843502782cf63a490fe9cd45c43329d509b0f5 (diff) | |
parent | 27f83008c0026108f9fc3a7cffa576897cb7a55d (diff) |
Merge pull request #26270 from vespa-engine/arnej/ranking-expression-wrapping
Arnej/ranking expression wrapping
17 files changed, 253 insertions, 24 deletions
diff --git a/config-model/src/main/java/com/yahoo/schema/OnnxModel.java b/config-model/src/main/java/com/yahoo/schema/OnnxModel.java index 6baaea6ea05..272b668b5fb 100644 --- a/config-model/src/main/java/com/yahoo/schema/OnnxModel.java +++ b/config-model/src/main/java/com/yahoo/schema/OnnxModel.java @@ -55,7 +55,7 @@ public class OnnxModel extends DistributableResource { return ref.toString(); } // or a function (evaluated by backend) - if (ref.isSimple() && "rankingExpression".equals(ref.name())) { + if (ref.isSimpleRankingExpressionWrapper()) { var arg = ref.simpleArgument(); if (arg.isPresent()) { return ref.toString(); diff --git a/config-model/src/main/java/com/yahoo/schema/RankProfile.java b/config-model/src/main/java/com/yahoo/schema/RankProfile.java index 7cb0a088f5f..a00bbb682a8 100644 --- a/config-model/src/main/java/com/yahoo/schema/RankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/RankProfile.java @@ -1169,7 +1169,7 @@ public class RankProfile implements Cloneable { // Source is either a simple reference (query/attribute/constant/rankingExpression)... Optional<Reference> reference = Reference.simple(source); if (reference.isPresent()) { - if (reference.get().name().equals("rankingExpression") && reference.get().simpleArgument().isPresent()) { + if (reference.get().isSimpleRankingExpressionWrapper()) { source = reference.get().simpleArgument().get(); // look up function below } else { return Optional.of(context.getType(reference.get())); diff --git a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java index 31a38752bec..acb125197d2 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java @@ -20,6 +20,7 @@ import com.yahoo.searchlib.rankingexpression.parser.ParseException; import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode; import com.yahoo.searchlib.rankingexpression.rule.SerializationContext; import com.yahoo.vespa.config.search.RankProfilesConfig; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -273,9 +274,9 @@ public class RawRankProfile implements RankProfilesConfig.Producer { String propertyName = RankingExpression.propertyName(referenceNode.getName()); String expressionString = function.getBody().getRoot().toString(context).toString(); context.addFunctionSerialization(propertyName, expressionString); - ReferenceNode backendReferenceNode = new ReferenceNode("rankingExpression(" + referenceNode.getName() + ")", - referenceNode.getArguments().expressions(), - referenceNode.getOutput()); + var backendReferenceNode = new ReferenceNode(wrapInRankingExpression(referenceNode.getName()), + referenceNode.getArguments().expressions(), + referenceNode.getOutput()); // tell backend to map back to the name the user expects: featureRenames.put(backendReferenceNode.toString(), referenceNode.toString()); functionFeatures.put(referenceNode.getName(), backendReferenceNode); @@ -499,7 +500,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { if (expression.getRoot() instanceof ReferenceNode) { properties.add(new Pair<>("vespa.rank." + phase, expression.getRoot().toString())); } else { - properties.add(new Pair<>("vespa.rank." + phase, "rankingExpression(" + name + ")")); + properties.add(new Pair<>("vespa.rank." + phase, wrapInRankingExpression(name))); properties.add(new Pair<>(RankingExpression.propertyName(name), expression.getRoot().toString())); } return properties; @@ -520,7 +521,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { for (Map.Entry<String, String> mapping : onnxModel.getInputMap().entrySet()) { String source = mapping.getValue(); if (functionNames.contains(source)) { - onnxModel.addInputNameMapping(mapping.getKey(), "rankingExpression(" + source + ")"); + onnxModel.addInputNameMapping(mapping.getKey(), wrapInRankingExpression(source)); } } } diff --git a/config-model/src/test/derived/rankingmacros/rank-profiles.cfg b/config-model/src/test/derived/rankingmacros/rank-profiles.cfg new file mode 100644 index 00000000000..71b7bc7166c --- /dev/null +++ b/config-model/src/test/derived/rankingmacros/rank-profiles.cfg @@ -0,0 +1,83 @@ +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 "standalone" +rankprofile[].fef.property[].name "rankingExpression(myfeature).rankingScript" +rankprofile[].fef.property[].value "7 * attribute(num)" +rankprofile[].fef.property[].name "rankingExpression(fourtimessum@2b1138e8965e7ff5.67f1e87166cfef86).rankingScript" +rankprofile[].fef.property[].value "4 * (match + match)" +rankprofile[].fef.property[].name "rankingExpression(macro_with_dollar$).rankingScript" +rankprofile[].fef.property[].value "69" +rankprofile[].fef.property[].name "rankingExpression(anotherfeature).rankingScript" +rankprofile[].fef.property[].value "10 * rankingExpression(myfeature)" +rankprofile[].fef.property[].name "rankingExpression(yetanotherfeature).rankingScript" +rankprofile[].fef.property[].value "100 * rankingExpression(myfeature)" +rankprofile[].fef.property[].name "rankingExpression(fourtimessum).rankingScript" +rankprofile[].fef.property[].value "4 * (var1 + var2)" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "match + fieldMatch(title) + rankingExpression(myfeature)" +rankprofile[].fef.property[].name "vespa.rank.secondphase" +rankprofile[].fef.property[].value "rankingExpression(secondphase)" +rankprofile[].fef.property[].name "rankingExpression(secondphase).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(fourtimessum@2b1138e8965e7ff5.67f1e87166cfef86) + 0 * rankingExpression(macro_with_dollar$)" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "firstPhase" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "rankingExpression(myfeature)" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "rankingExpression(anotherfeature)" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "rankingExpression(yetanotherfeature)" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "rankingExpression(macro_with_dollar$)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "rankingExpression(anotherfeature)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "anotherfeature" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "rankingExpression(yetanotherfeature)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "yetanotherfeature" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "rankingExpression(macro_with_dollar$)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "macro_with_dollar$" +rankprofile[].name "constantsAndMacro" +rankprofile[].fef.property[].name "rankingExpression(c).rankingScript" +rankprofile[].fef.property[].value "attribute(num)" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "attribute(num) * 2.0 + 3.0" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "firstPhase" +rankprofile[].name "doc" +rankprofile[].fef.property[].name "rankingExpression(myfeature).rankingScript" +rankprofile[].fef.property[].value "fieldMatch(title) + freshness(timestamp)" +rankprofile[].fef.property[].name "rankingExpression(otherfeature@6b0a229a66fcaa04).rankingScript" +rankprofile[].fef.property[].value "nativeRank(title,body)" +rankprofile[].fef.property[].name "rankingExpression(otherfeature).rankingScript" +rankprofile[].fef.property[].value "nativeRank(foo,body)" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(myfeature) * 10" +rankprofile[].fef.property[].name "vespa.rank.secondphase" +rankprofile[].fef.property[].value "rankingExpression(secondphase)" +rankprofile[].fef.property[].name "rankingExpression(secondphase).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(otherfeature@6b0a229a66fcaa04) * rankingExpression(myfeature)" +rankprofile[].fef.property[].name "vespa.summary.feature" +rankprofile[].fef.property[].value "rankingExpression(myfeature)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "rankingExpression(myfeature)" +rankprofile[].fef.property[].name "vespa.feature.rename" +rankprofile[].fef.property[].value "myfeature" diff --git a/config-model/src/test/derived/rankingmacros/rankingmacros.sd b/config-model/src/test/derived/rankingmacros/rankingmacros.sd new file mode 100644 index 00000000000..84598cb483a --- /dev/null +++ b/config-model/src/test/derived/rankingmacros/rankingmacros.sd @@ -0,0 +1,105 @@ +# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +schema rankingmacros { + + document rankingmacros { + field title type string { + indexing: index + } + field timestamp type long { + indexing: attribute + } + field description type string { + indexing: index + } + field num type int { + indexing: attribute + } + field abstract type string { + indexing: index + } + field body type string { + indexing: index + } + field usstaticrank type string { + indexing: attribute + } + field boostmax type string { + indexing: index + } + field entitytitle type string { + indexing: index + } + } + + rank-profile standalone { + macro fourtimessum(var1, var2) { + expression: 4*(var1+var2) + } + macro myfeature() { + expression { + 7 * attribute(num) + } + } + macro anotherfeature() { + expression: 10*myfeature + } + macro yetanotherfeature() { + expression: 100*rankingExpression(myfeature) # legacy form + } + macro macro_with_dollar$() { # Not allowed + expression: 69 + } + first-phase { + expression: match + fieldMatch(title) + myfeature + } + second-phase { + expression: fourtimessum(match,match) + 0 * macro_with_dollar$ + } + summary-features { + firstPhase + rankingExpression(myfeature) + anotherfeature + yetanotherfeature + macro_with_dollar$ + } + } + + # Profile with macro and constants + rank-profile constantsAndMacro { + macro c() { + expression: attribute(num) + } + + constants { + a: 2 + b: 3 + } + + first-phase { + expression: attribute(num) * a + b + } + + summary-features { + firstPhase + } + } + + # The example in the docs + rank-profile doc inherits default { + macro myfeature() { + expression: fieldMatch(title) + freshness(timestamp) + } + macro otherfeature(foo) { + expression{ nativeRank(foo, body) } + } + + first-phase { + expression: myfeature * 10 + } + second-phase { + expression: otherfeature(title) * myfeature + } + summary-features: myfeature + } + +} diff --git a/config-model/src/test/java/com/yahoo/schema/derived/RankProfilesTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/RankProfilesTestCase.java index 5c24b32e275..a4c03291ce2 100644 --- a/config-model/src/test/java/com/yahoo/schema/derived/RankProfilesTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/derived/RankProfilesTestCase.java @@ -17,4 +17,9 @@ public class RankProfilesTestCase extends AbstractExportingTestCase { void testRankProfiles() throws IOException, ParseException { assertCorrectDeriving("rankprofiles", null, new TestProperties(), new TestableDeployLogger()); } + + @Test + void testMacrosInRankProfiles() throws IOException, ParseException { + assertCorrectDeriving("rankingmacros", null, new TestProperties(), new TestableDeployLogger()); + } } diff --git a/container-search/src/main/java/com/yahoo/search/ranking/HitRescorer.java b/container-search/src/main/java/com/yahoo/search/ranking/HitRescorer.java index ebdbbb693f1..cce6b42d323 100644 --- a/container-search/src/main/java/com/yahoo/search/ranking/HitRescorer.java +++ b/container-search/src/main/java/com/yahoo/search/ranking/HitRescorer.java @@ -3,6 +3,7 @@ package com.yahoo.search.ranking; import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; +import static com.yahoo.searchlib.rankingexpression.Reference.RANKING_EXPRESSION_WRAPPER; import java.util.function.Supplier; import java.util.logging.Logger; @@ -42,7 +43,7 @@ class HitRescorer { } } - private static final String RE_PREFIX = "rankingExpression("; + private static final String RE_PREFIX = RANKING_EXPRESSION_WRAPPER + "("; private static final String RE_SUFFIX = ")"; private static final int RE_PRE_LEN = RE_PREFIX.length(); private static final int RE_SUF_LEN = RE_SUFFIX.length(); diff --git a/container-search/src/main/java/com/yahoo/search/result/FeatureData.java b/container-search/src/main/java/com/yahoo/search/result/FeatureData.java index 421f19475a6..7e9fa3f748a 100644 --- a/container-search/src/main/java/com/yahoo/search/result/FeatureData.java +++ b/container-search/src/main/java/com/yahoo/search/result/FeatureData.java @@ -11,6 +11,7 @@ import com.yahoo.io.GrowableByteBuffer; import com.yahoo.tensor.Tensor; import com.yahoo.tensor.serialization.JsonFormat; import com.yahoo.tensor.serialization.TypedBinaryFormat; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.nio.charset.StandardCharsets; import java.util.Collections; @@ -144,7 +145,7 @@ public class FeatureData implements Inspectable, JsonProducer { if (featureValue.valid()) return featureValue; // Try to wrap by rankingExpression(name) - return value.field("rankingExpression(" + featureName + ")"); + return value.field(wrapInRankingExpression(featureName)); } /** Returns the names of the features available in this */ diff --git a/model-evaluation/src/main/java/ai/vespa/models/evaluation/FunctionReference.java b/model-evaluation/src/main/java/ai/vespa/models/evaluation/FunctionReference.java index 46134074137..34e34a3341d 100644 --- a/model-evaluation/src/main/java/ai/vespa/models/evaluation/FunctionReference.java +++ b/model-evaluation/src/main/java/ai/vespa/models/evaluation/FunctionReference.java @@ -2,6 +2,7 @@ package ai.vespa.models.evaluation; import com.yahoo.collections.Pair; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.util.Objects; import java.util.Optional; @@ -51,7 +52,8 @@ class FunctionReference { } String serialForm() { - return "rankingExpression(" + name + (instance != null ? instance : "") + ")"; + String extra = (instance != null ? instance : ""); + return wrapInRankingExpression(name + extra); } @Override diff --git a/model-evaluation/src/main/java/ai/vespa/models/evaluation/LazyArrayContext.java b/model-evaluation/src/main/java/ai/vespa/models/evaluation/LazyArrayContext.java index 81325740218..47c246c008e 100644 --- a/model-evaluation/src/main/java/ai/vespa/models/evaluation/LazyArrayContext.java +++ b/model-evaluation/src/main/java/ai/vespa/models/evaluation/LazyArrayContext.java @@ -16,6 +16,7 @@ import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode; import com.yahoo.stream.CustomCollectors; import com.yahoo.tensor.Tensor; import com.yahoo.tensor.TensorType; +import static com.yahoo.searchlib.rankingexpression.Reference.RANKING_EXPRESSION_WRAPPER; import java.util.Arrays; import java.util.HashMap; @@ -233,7 +234,11 @@ public final class LazyArrayContext extends Context implements ContextIndex { List<OnnxModel> onnxModels, Map<String, OnnxModel> onnxModelsInUse) { if (isFunctionReference(node)) { - FunctionReference reference = FunctionReference.fromSerial(node.toString()).get(); + var opt = FunctionReference.fromSerial(node.toString()); + if (opt.isEmpty()) { + throw new IllegalArgumentException("Could not extract function " + node + " from serialized form '" + node.toString() +"'"); + } + FunctionReference reference = opt.get(); bindTargets.add(reference.serialForm()); ExpressionFunction function = functions.get(reference); @@ -313,7 +318,7 @@ public final class LazyArrayContext extends Context implements ContextIndex { private boolean isFunctionReference(ExpressionNode node) { if ( ! (node instanceof ReferenceNode reference)) return false; - return reference.getName().equals("rankingExpression") && reference.getArguments().size() == 1; + return reference.getName().equals(RANKING_EXPRESSION_WRAPPER) && reference.getArguments().size() == 1; } private boolean isOnnx(ExpressionNode node) { diff --git a/model-evaluation/src/test/java/ai/vespa/models/evaluation/RankProfileImportingTest.java b/model-evaluation/src/test/java/ai/vespa/models/evaluation/RankProfileImportingTest.java index 1a6f6925caf..c5084166c1f 100644 --- a/model-evaluation/src/test/java/ai/vespa/models/evaluation/RankProfileImportingTest.java +++ b/model-evaluation/src/test/java/ai/vespa/models/evaluation/RankProfileImportingTest.java @@ -49,4 +49,9 @@ public class RankProfileImportingTest { assertEquals("tensor()", rt.get().toString()); } + @Test + public void testImportingExpressionsAsArguments() { + ModelTester tester = new ModelTester("src/test/resources/config/expressions-as-arguments/"); + assertEquals(3, tester.models().size()); + } } diff --git a/searchlib/abi-spec.json b/searchlib/abi-spec.json index 5413907e967..be0414421fe 100644 --- a/searchlib/abi-spec.json +++ b/searchlib/abi-spec.json @@ -364,6 +364,8 @@ "public boolean equals(java.lang.Object)", "public int hashCode()", "public java.lang.String toString()", + "public static java.lang.String wrapInRankingExpression(java.lang.String)", + "public boolean isSimpleRankingExpressionWrapper()", "public java.lang.StringBuilder toString(java.lang.StringBuilder, com.yahoo.searchlib.rankingexpression.rule.SerializationContext, java.util.Deque, com.yahoo.searchlib.rankingexpression.rule.CompositeNode)", "public int compareTo(com.yahoo.searchlib.rankingexpression.Reference)", "public static com.yahoo.searchlib.rankingexpression.Reference fromIdentifier(java.lang.String)", @@ -371,7 +373,9 @@ "public static java.util.Optional simple(java.lang.String)", "public bridge synthetic int compareTo(java.lang.Object)" ], - "fields" : [ ] + "fields" : [ + "public static final java.lang.String RANKING_EXPRESSION_WRAPPER" + ] }, "com.yahoo.searchlib.rankingexpression.evaluation.AbstractArrayContext" : { "superClass" : "com.yahoo.searchlib.rankingexpression.evaluation.Context", diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java index 171151bfdf4..c7d69d7a36a 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java @@ -10,6 +10,7 @@ import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode; import com.yahoo.searchlib.rankingexpression.rule.SerializationContext; import com.yahoo.tensor.TensorType; import com.yahoo.text.Utf8; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -142,7 +143,7 @@ public class ExpressionFunction { if (shouldGenerateFeature(expr)) { String funcName = "autogenerated_ranking_feature@" + Long.toHexString(symbolCode(key + "=" + binding)); context.addFunctionSerialization(RankingExpression.propertyName(funcName), binding); - binding = "rankingExpression(" + funcName + ")"; + binding = wrapInRankingExpression(funcName); } argumentBindings.put(key, binding); } diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java index c9f818544e3..c6de04ed755 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java @@ -11,6 +11,7 @@ import com.yahoo.searchlib.rankingexpression.rule.SerializationContext; import com.yahoo.tensor.TensorType; import com.yahoo.tensor.evaluation.TypeContext; import com.yahoo.text.Text; +import static com.yahoo.searchlib.rankingexpression.Reference.RANKING_EXPRESSION_WRAPPER; import java.io.File; import java.io.FileNotFoundException; @@ -80,7 +81,7 @@ public class RankingExpression implements Serializable { private String name = ""; private ExpressionNode root; - private final static String RANKEXPRESSION = "rankingExpression("; + private final static String RANKEXPRESSION = RANKING_EXPRESSION_WRAPPER + "("; private final static String RANKINGSCRIPT = ").rankingScript"; private final static String EXPRESSION_NAME = ").expressionName"; 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 eaecdf78162..64b251c0cd4 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java @@ -120,17 +120,30 @@ public class Reference extends Name implements Comparable<Reference> { return toString(new StringBuilder(), new SerializationContext(), null, null).toString(); } + public static final String RANKING_EXPRESSION_WRAPPER = "rankingExpression"; + + public static String wrapInRankingExpression(String name) { + return RANKING_EXPRESSION_WRAPPER + "(" + name + ")"; + } + + public boolean isSimpleRankingExpressionWrapper() { + return name().equals(RANKING_EXPRESSION_WRAPPER) && isSimple(); + } + public StringBuilder toString(StringBuilder b, SerializationContext context, Deque<String> path, CompositeNode parent) { b.append(name()); if (arguments.expressions().size() > 0) { b.append("("); - for (int i = 0; i < arguments.expressions().size(); i++) { - ExpressionNode e = arguments.expressions().get(i); - e.toString(b, context, path, parent); - if (i+1 < arguments.expressions().size()) { - b.append(','); + if (isSimpleRankingExpressionWrapper()) { + b.append(simpleArgument().get()); + } else { + for (int i = 0; i < arguments.expressions().size(); i++) { + ExpressionNode e = arguments.expressions().get(i); + e.toString(b, context, path, parent); + if (i+1 < arguments.expressions().size()) { + b.append(','); + } } - } b.append(")"); } 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 85a12a49958..ec377c6f5d9 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 @@ -8,6 +8,7 @@ import com.yahoo.searchlib.rankingexpression.evaluation.Context; import com.yahoo.searchlib.rankingexpression.evaluation.Value; import com.yahoo.tensor.TensorType; import com.yahoo.tensor.evaluation.TypeContext; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.util.ArrayDeque; import java.util.Deque; @@ -95,7 +96,7 @@ public final class ReferenceNode extends CompositeNode { context.addFunctionTypeSerialization(functionName, function.returnType().get()); } path.removeLast(); - return string.append("rankingExpression(").append(functionName).append(')'); + return string.append(wrapInRankingExpression(functionName)); } // Not resolved in this context: output as-is diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java index 7d0c0b98910..e2fffd824b9 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java @@ -6,6 +6,7 @@ import com.yahoo.searchlib.rankingexpression.RankingExpression; import com.yahoo.searchlib.rankingexpression.Reference; import com.yahoo.tensor.TensorType; import com.yahoo.tensor.evaluation.TypeContext; +import static com.yahoo.searchlib.rankingexpression.Reference.wrapInRankingExpression; import java.util.Collection; import java.util.Collections; @@ -97,13 +98,13 @@ public class SerializationContext extends FunctionReferenceContext { /** Adds the serialization of the argument type to a function */ public void addArgumentTypeSerialization(String functionName, String argumentName, TensorType type) { - serializedFunctions.put("rankingExpression(" + functionName + ")." + argumentName + ".type", type.toString()); + serializedFunctions.put(wrapInRankingExpression(functionName) + "." + argumentName + ".type", type.toString()); } /** Adds the serialization of the return type of a function */ public void addFunctionTypeSerialization(String functionName, TensorType type) { if (type.rank() == 0) return; // no explicit type implies scalar (aka rank 0 tensor) - serializedFunctions.put("rankingExpression(" + functionName + ").type", type.toString()); + serializedFunctions.put(wrapInRankingExpression(functionName) + ".type", type.toString()); } @Override |