aboutsummaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorArne Juul <arnej@vespa.ai>2023-10-30 11:27:01 +0000
committerArne Juul <arnej@vespa.ai>2023-10-30 11:51:20 +0000
commitdeb7ac732b85a497a545f8df15e9d4e65943031c (patch)
tree8d411a1be666e70f2fb8eefb77d0205e374b24fd /config-model
parentf2d3bcf477b133cd3f6519466bd07a9a14cfdf3e (diff)
handle functions with arguments
* should work as match-features and summary-features now * and they will become hidden/implicit match-feature if used from global-phase
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java35
-rw-r--r--config-model/src/test/derived/rankingexpression/rank-profiles.cfg88
-rw-r--r--config-model/src/test/derived/rankingexpression/rankexpression.sd38
3 files changed, 150 insertions, 11 deletions
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 68fa0fe6de9..87b79ddcdc3 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
@@ -301,28 +301,41 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
private void replaceFunctionFeatures(Set<ReferenceNode> features, SerializationContext context) {
if (features == null) return;
- Map<String, ReferenceNode> functionFeatures = new LinkedHashMap<>();
+ Set<ReferenceNode> functionFeatures = new LinkedHashSet<>();
for (Iterator<ReferenceNode> i = features.iterator(); i.hasNext(); ) {
ReferenceNode referenceNode = i.next();
// Is the feature a function?
ExpressionFunction function = context.getFunction(referenceNode.getName());
if (function != null) {
- String propertyName = RankingExpression.propertyName(referenceNode.getName());
- String expressionString = function.getBody().getRoot().toString(context).toString();
+ if (referenceNode.getOutput() != null) {
+ throw new IllegalArgumentException("function " + referenceNode.getName() +
+ " cannot provide output " + referenceNode.getOutput() +
+ " demanded by feature " + referenceNode);
+ }
+ int needArgs = function.arguments().size();
+ var useArgs = referenceNode.getArguments();
+ if (needArgs != useArgs.size()) {
+ throw new IllegalArgumentException("function " + referenceNode.getName() +
+ " needs " + needArgs +
+ " arguments but gets " + useArgs.size() +
+ " from feature " + referenceNode);
+ }
+ var instance = function.expand(context, useArgs.expressions(), new java.util.ArrayDeque<>());
+ String propertyName = RankingExpression.propertyName(instance.getName());
+ String expressionString = instance.getExpressionString();
context.addFunctionSerialization(propertyName, expressionString);
- function.returnType().ifPresent(t -> context.addFunctionTypeSerialization(referenceNode.getName(), t));
- var backendReferenceNode = new ReferenceNode(wrapInRankingExpression(referenceNode.getName()),
- referenceNode.getArguments().expressions(),
- referenceNode.getOutput());
+ function.returnType().ifPresent(t -> context.addFunctionTypeSerialization(instance.getName(), t));
+ String backendReference = wrapInRankingExpression(instance.getName());
+ var backendReferenceNode = new ReferenceNode(backendReference, List.of(), null);
// tell backend to map back to the name the user expects:
- featureRenames.put(backendReferenceNode.toString(), referenceNode.toString());
- functionFeatures.put(referenceNode.getName(), backendReferenceNode);
+ featureRenames.put(backendReference, referenceNode.toString());
+ functionFeatures.add(backendReferenceNode);
i.remove(); // Will add the expanded one in next block
}
}
// Then, replace the features that were functions
- for (Map.Entry<String, ReferenceNode> e : functionFeatures.entrySet()) {
- features.add(e.getValue());
+ for (ReferenceNode mappedFun : functionFeatures) {
+ features.add(mappedFun);
}
}
diff --git a/config-model/src/test/derived/rankingexpression/rank-profiles.cfg b/config-model/src/test/derived/rankingexpression/rank-profiles.cfg
index b3257c962dd..87882eef273 100644
--- a/config-model/src/test/derived/rankingexpression/rank-profiles.cfg
+++ b/config-model/src/test/derived/rankingexpression/rank-profiles.cfg
@@ -582,3 +582,91 @@ rankprofile[].normalizer[].name "normalize@3221316369@rrank"
rankprofile[].normalizer[].input "nativeRank"
rankprofile[].normalizer[].algo RRANK
rankprofile[].normalizer[].kparam 60.0
+rankprofile[].name "function-with-arg-as-summary-feature"
+rankprofile[].fef.property[].name "vespa.type.feature.attribute(t1)"
+rankprofile[].fef.property[].value "tensor(m{},v[3])"
+rankprofile[].fef.property[].name "rankingExpression(plusOne@478d886d33f680d).rankingScript"
+rankprofile[].fef.property[].value "41 + 1"
+rankprofile[].fef.property[].name "rankingExpression(useAttr@93d0729be0db6c70.30effc5f9cc0df93).rankingScript"
+rankprofile[].fef.property[].value "attribute(foo1) * 17"
+rankprofile[].fef.property[].name "rankingExpression(plusOne).rankingScript"
+rankprofile[].fef.property[].value "x + 1"
+rankprofile[].fef.property[].name "rankingExpression(useAttr).rankingScript"
+rankprofile[].fef.property[].value "attribute(name) * weight"
+rankprofile[].fef.property[].name "vespa.rank.firstphase"
+rankprofile[].fef.property[].value "nativeRank"
+rankprofile[].fef.property[].name "vespa.summary.feature"
+rankprofile[].fef.property[].value "attribute(t1)"
+rankprofile[].fef.property[].name "vespa.summary.feature"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@478d886d33f680d)"
+rankprofile[].fef.property[].name "vespa.summary.feature"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@93d0729be0db6c70.30effc5f9cc0df93)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@478d886d33f680d)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "plusOne(41)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@93d0729be0db6c70.30effc5f9cc0df93)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "useAttr(foo1,17)"
+rankprofile[].fef.property[].name "vespa.type.attribute.t1"
+rankprofile[].fef.property[].value "tensor(m{},v[3])"
+rankprofile[].name "function-with-arg-in-global-phase"
+rankprofile[].fef.property[].name "rankingExpression(useAttr@6598f1aecaec0a2d.40876484d21a389).rankingScript"
+rankprofile[].fef.property[].value "attribute(t1) * 42"
+rankprofile[].fef.property[].name "rankingExpression(plusOne@31852fecfab75f29).rankingScript"
+rankprofile[].fef.property[].value "2 + 1"
+rankprofile[].fef.property[].name "rankingExpression(useAttr@93d0729be0db6c70.fe12ed266262cc16).rankingScript"
+rankprofile[].fef.property[].value "attribute(foo1) * 1.25"
+rankprofile[].fef.property[].name "rankingExpression(withIndirect@93d0729be0db6c70).rankingScript"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@93d0729be0db6c70.fe12ed266262cc16)"
+rankprofile[].fef.property[].name "rankingExpression(plusOne@4a2b16f9107d7185).rankingScript"
+rankprofile[].fef.property[].value "attribute(foo2) + 1"
+rankprofile[].fef.property[].name "vespa.type.feature.useAttr(t1,42)"
+rankprofile[].fef.property[].value "tensor(m{},v[3])"
+rankprofile[].fef.property[].name "rankingExpression(plusOne).rankingScript"
+rankprofile[].fef.property[].value "x + 1"
+rankprofile[].fef.property[].name "rankingExpression(useAttr).rankingScript"
+rankprofile[].fef.property[].value "attribute(name) * weight"
+rankprofile[].fef.property[].name "rankingExpression(useAttr@2e0b6bb9bf541103.fe12ed266262cc16).rankingScript"
+rankprofile[].fef.property[].value "attribute(name) * 1.25"
+rankprofile[].fef.property[].name "rankingExpression(withIndirect).rankingScript"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@2e0b6bb9bf541103.fe12ed266262cc16)"
+rankprofile[].fef.property[].name "vespa.rank.firstphase"
+rankprofile[].fef.property[].value "nativeRank"
+rankprofile[].fef.property[].name "vespa.rank.globalphase"
+rankprofile[].fef.property[].value "rankingExpression(globalphase)"
+rankprofile[].fef.property[].name "rankingExpression(globalphase).rankingScript"
+rankprofile[].fef.property[].value "reduce(rankingExpression(useAttr@6598f1aecaec0a2d.40876484d21a389) + rankingExpression(plusOne@31852fecfab75f29) + rankingExpression(withIndirect@93d0729be0db6c70) + rankingExpression(plusOne@4a2b16f9107d7185), sum)"
+rankprofile[].fef.property[].name "vespa.match.feature"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@4a2b16f9107d7185)"
+rankprofile[].fef.property[].name "vespa.match.feature"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@31852fecfab75f29)"
+rankprofile[].fef.property[].name "vespa.match.feature"
+rankprofile[].fef.property[].value "rankingExpression(withIndirect@93d0729be0db6c70)"
+rankprofile[].fef.property[].name "vespa.match.feature"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@6598f1aecaec0a2d.40876484d21a389)"
+rankprofile[].fef.property[].name "vespa.hidden.matchfeature"
+rankprofile[].fef.property[].value "plusOne(2)"
+rankprofile[].fef.property[].name "vespa.hidden.matchfeature"
+rankprofile[].fef.property[].value "withIndirect(foo1)"
+rankprofile[].fef.property[].name "vespa.hidden.matchfeature"
+rankprofile[].fef.property[].value "useAttr(t1,42)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@4a2b16f9107d7185)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "plusOne(attribute(foo2))"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(plusOne@31852fecfab75f29)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "plusOne(2)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(withIndirect@93d0729be0db6c70)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "withIndirect(foo1)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "rankingExpression(useAttr@6598f1aecaec0a2d.40876484d21a389)"
+rankprofile[].fef.property[].name "vespa.feature.rename"
+rankprofile[].fef.property[].value "useAttr(t1,42)"
+rankprofile[].fef.property[].name "vespa.type.attribute.t1"
+rankprofile[].fef.property[].value "tensor(m{},v[3])"
diff --git a/config-model/src/test/derived/rankingexpression/rankexpression.sd b/config-model/src/test/derived/rankingexpression/rankexpression.sd
index 15537f1f9d0..1ccf74bfe17 100644
--- a/config-model/src/test/derived/rankingexpression/rankexpression.sd
+++ b/config-model/src/test/derived/rankingexpression/rankexpression.sd
@@ -469,4 +469,42 @@ schema rankexpression {
match-features: nativeRank
}
+ rank-profile function-with-arg-as-summary-feature {
+ function plusOne(x) {
+ expression: x + 1
+ }
+ function useAttr(name, weight) {
+ expression: attribute(name) * weight
+ }
+ first-phase {
+ expression: nativeRank
+ }
+ summary-features {
+ attribute(t1)
+ plusOne(41)
+ useAttr(foo1, 17)
+ }
+ }
+
+ rank-profile function-with-arg-in-global-phase {
+ function plusOne(x) {
+ expression: x + 1
+ }
+ function useAttr(name, weight) {
+ expression: attribute(name) * weight
+ }
+ function withIndirect(name) {
+ expression: useAttr(name, 1.25)
+ }
+ first-phase {
+ expression: nativeRank
+ }
+ global-phase {
+ expression: sum(useAttr(t1, 42) + plusOne(2) + withIndirect(foo1) + plusOne(attribute(foo2)))
+ }
+ match-features {
+ plusOne(attribute(foo2))
+ }
+ }
+
}