diff options
author | Jon Bratseth <bratseth@gmail.com> | 2023-03-20 11:24:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-20 11:24:14 +0100 |
commit | 24b297f12cdb8707d15ad554554eaaff76bcbdd3 (patch) | |
tree | 1a1a64b6224b296b5d79b06b110bcf03665be86f | |
parent | 722ea7f065eaf28cbe3c27e0e8cafb53a7799980 (diff) | |
parent | 8ab3f0d995666384080e9d1a44df2eac01efca31 (diff) |
Merge pull request #26489 from vespa-engine/arnej/deterministic-rank-properties
Arnej/deterministic rank properties
7 files changed, 262 insertions, 15 deletions
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 f9b3bc77040..639930041c3 100644 --- a/config-model/src/main/java/com/yahoo/schema/RankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/RankProfile.java @@ -683,6 +683,25 @@ public class RankProfile implements Cloneable { addRankProperty(new RankProperty(name, parameter)); } + /* + * set a rank-property that should be a single-value parameter; + * if the same name is used multiple times, that parameter must be identical each time. + */ + public void setRankProperty(String name, String parameter) { + var old = rankProperties.get(name); + if (old != null) { + if (old.size() != 1) { + throw new IllegalStateException("setRankProperty used for multi-valued property " + name); + } + var oldVal = old.get(0).getValue(); + if (! oldVal.equals(parameter)) { + throw new IllegalArgumentException("setRankProperty would change property " + name + " from " + oldVal + " to " + parameter); + } + } else { + addRankProperty(new RankProperty(name, parameter)); + } + } + private void addRankProperty(RankProperty rankProperty) { // Just the usual multimap semantics here rankProperties.computeIfAbsent(rankProperty.getName(), (String key) -> new ArrayList<>(1)).add(rankProperty); @@ -1091,7 +1110,7 @@ public class RankProfile implements Cloneable { inlineFunctions); RankingExpression expression = expressionTransforms.transform(function.function().getBody(), context); for (Map.Entry<String, String> rankProperty : context.rankProperties().entrySet()) { - addRankProperty(rankProperty.getKey(), rankProperty.getValue()); + setRankProperty(rankProperty.getKey(), rankProperty.getValue()); } return function.withExpression(expression); } diff --git a/config-model/src/main/java/com/yahoo/schema/expressiontransforms/RankProfileTransformContext.java b/config-model/src/main/java/com/yahoo/schema/expressiontransforms/RankProfileTransformContext.java index cfc859345ad..890fa5e7a10 100644 --- a/config-model/src/main/java/com/yahoo/schema/expressiontransforms/RankProfileTransformContext.java +++ b/config-model/src/main/java/com/yahoo/schema/expressiontransforms/RankProfileTransformContext.java @@ -12,7 +12,7 @@ import com.yahoo.searchlib.rankingexpression.transform.TransformContext; import com.yahoo.tensor.Tensor; import com.yahoo.tensor.TensorType; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; @@ -27,7 +27,7 @@ public class RankProfileTransformContext extends TransformContext { private final QueryProfileRegistry queryProfiles; private final ImportedMlModels importedModels; private final Map<String, RankProfile.RankingExpressionFunction> inlineFunctions; - private final Map<String, String> rankProperties = new HashMap<>(); + private final Map<String, String> rankProperties = new LinkedHashMap<>(); public RankProfileTransformContext(RankProfile rankProfile, QueryProfileRegistry queryProfiles, diff --git a/config-model/src/test/derived/globalphase_onnx_inside/rank-profiles.cfg b/config-model/src/test/derived/globalphase_onnx_inside/rank-profiles.cfg index e456dec58ed..58be9b400aa 100644 --- a/config-model/src/test/derived/globalphase_onnx_inside/rank-profiles.cfg +++ b/config-model/src/test/derived/globalphase_onnx_inside/rank-profiles.cfg @@ -1,10 +1,49 @@ rankprofile[].name "default" +rankprofile[].fef.property[].name "vespa.type.attribute.aa" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "vespa.type.query.bb" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].fef.property[].name "vespa.type.query.yy" +rankprofile[].fef.property[].value "tensor(d0[2])" +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[].fef.property[].name "vespa.type.attribute.aa" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].name "simple" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "reduce(attribute(aa), sum)" +rankprofile[].fef.property[].name "vespa.rank.globalphase" +rankprofile[].fef.property[].value "rankingExpression(globalphase)" +rankprofile[].fef.property[].name "rankingExpression(globalphase).rankingScript" +rankprofile[].fef.property[].value "onnx(direct).out{d0:(attribute(extra))}" +rankprofile[].fef.property[].name "vespa.match.feature" +rankprofile[].fef.property[].value "attribute(aa)" +rankprofile[].fef.property[].name "vespa.match.feature" +rankprofile[].fef.property[].value "attribute(extra)" +rankprofile[].fef.property[].name "vespa.globalphase.rerankcount" +rankprofile[].fef.property[].value "13" +rankprofile[].fef.property[].name "vespa.type.attribute.aa" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "vespa.type.query.bb" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].fef.property[].name "vespa.type.query.yy" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].name "one" rankprofile[].fef.property[].name "rankingExpression(handicap).rankingScript" rankprofile[].fef.property[].value "query(yy)" rankprofile[].fef.property[].name "rankingExpression(handicap).type" rankprofile[].fef.property[].value "tensor(d0[2])" rankprofile[].fef.property[].name "rankingExpression(indirect_a).rankingScript" -rankprofile[].fef.property[].value "attribute(aa) + tensor(d1[3])((d1 + attribute(extra)))" +rankprofile[].fef.property[].value "attribute(aa)" rankprofile[].fef.property[].name "rankingExpression(indirect_a).type" rankprofile[].fef.property[].value "tensor(d1[3])" rankprofile[].fef.property[].name "rankingExpression(indirect_x).rankingScript" @@ -25,24 +64,71 @@ rankprofile[].fef.property[].name "rankingExpression(globalphase).rankingScript" rankprofile[].fef.property[].value "reduce(constant(ww) * (onnx(inside).foobar - rankingExpression(handicap)), sum)" rankprofile[].fef.property[].name "vespa.match.feature" rankprofile[].fef.property[].value "attribute(aa)" +rankprofile[].fef.property[].name "vespa.globalphase.rerankcount" +rankprofile[].fef.property[].value "13" +rankprofile[].fef.property[].name "vespa.type.attribute.aa" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "vespa.type.query.bb" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].fef.property[].name "vespa.type.query.yy" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].name "two" +rankprofile[].fef.property[].name "rankingExpression(indirect_a).rankingScript" +rankprofile[].fef.property[].value "tensor(d1[3])((d1 + attribute(extra)))" +rankprofile[].fef.property[].name "rankingExpression(indirect_a).type" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "rankingExpression(indirect_x).rankingScript" +rankprofile[].fef.property[].value "constant(xx)" +rankprofile[].fef.property[].name "rankingExpression(indirect_x).type" +rankprofile[].fef.property[].value "tensor(d0[2],d1[3])" +rankprofile[].fef.property[].name "rankingExpression(indirect_b).rankingScript" +rankprofile[].fef.property[].value "query(bb)" +rankprofile[].fef.property[].name "rankingExpression(indirect_b).type" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "reduce(attribute(aa), sum)" +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(constant(ww) * onnx(twoside).foobar, sum)" rankprofile[].fef.property[].name "vespa.match.feature" rankprofile[].fef.property[].value "attribute(extra)" rankprofile[].fef.property[].name "vespa.globalphase.rerankcount" -rankprofile[].fef.property[].value "13" +rankprofile[].fef.property[].value "42" rankprofile[].fef.property[].name "vespa.type.attribute.aa" rankprofile[].fef.property[].value "tensor(d1[3])" rankprofile[].fef.property[].name "vespa.type.query.bb" rankprofile[].fef.property[].value "tensor(d0[2])" rankprofile[].fef.property[].name "vespa.type.query.yy" rankprofile[].fef.property[].value "tensor(d0[2])" -rankprofile[].name "unranked" +rankprofile[].name "three" +rankprofile[].fef.property[].name "rankingExpression(indirect_a).rankingScript" +rankprofile[].fef.property[].value "tensor(d1[3]):{{d1:0}:0.25,{d1:1}:(attribute(extra)),{d1:2}:0.75}" +rankprofile[].fef.property[].name "rankingExpression(indirect_a).type" +rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "rankingExpression(indirect_x).rankingScript" +rankprofile[].fef.property[].value "constant(xx)" +rankprofile[].fef.property[].name "rankingExpression(indirect_x).type" +rankprofile[].fef.property[].value "tensor(d0[2],d1[3])" +rankprofile[].fef.property[].name "rankingExpression(indirect_b).rankingScript" +rankprofile[].fef.property[].value "query(bb)" +rankprofile[].fef.property[].name "rankingExpression(indirect_b).type" +rankprofile[].fef.property[].value "tensor(d0[2])" 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[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "reduce(attribute(aa), sum)" +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(constant(ww) * onnx(another).foobar, sum)" +rankprofile[].fef.property[].name "vespa.globalphase.rerankcount" +rankprofile[].fef.property[].value "1001" rankprofile[].fef.property[].name "vespa.type.attribute.aa" rankprofile[].fef.property[].value "tensor(d1[3])" +rankprofile[].fef.property[].name "vespa.type.query.bb" +rankprofile[].fef.property[].value "tensor(d0[2])" +rankprofile[].fef.property[].name "vespa.type.query.yy" +rankprofile[].fef.property[].value "tensor(d0[2])" diff --git a/config-model/src/test/derived/globalphase_onnx_inside/test.sd b/config-model/src/test/derived/globalphase_onnx_inside/test.sd index f5788611b0a..3e48f912931 100644 --- a/config-model/src/test/derived/globalphase_onnx_inside/test.sd +++ b/config-model/src/test/derived/globalphase_onnx_inside/test.sd @@ -23,6 +23,26 @@ schema test { query(bb) tensor(d0[2]) query(yy) tensor(d0[2]) } + } + + rank-profile simple inherits default { + onnx-model direct { + file: files/ax_plus_b.onnx + input vector_A: attribute(aa) + input matrix_X: constant(xx) + input vector_B: query(bb) + output vector_Y: out + } + first-phase { + expression: sum(attribute(aa)) + } + global-phase { + rerank-count: 13 + expression: onnx(direct).out{d0:attribute(extra)} + } + } + + rank-profile one inherits default { onnx-model inside { file: files/ax_plus_b.onnx input vector_A: indirect_a @@ -41,7 +61,59 @@ schema test { expression: sum(constant(ww) * (onnx(inside).foobar - handicap)) } function indirect_a() { - expression: attribute(aa) + tensor(d1[3])(d1+attribute(extra)) + expression: attribute(aa) + } + function indirect_x() { + expression: constant(xx) + } + function indirect_b() { + expression: query(bb) + } + } + + rank-profile two inherits default { + onnx-model twoside { + file: files/ax_plus_b.onnx + input vector_A: indirect_a + input matrix_X: indirect_x + input vector_B: indirect_b + output vector_Y: foobar + } + first-phase { + expression: sum(attribute(aa)) + } + global-phase { + rerank-count: 42 + expression: sum(constant(ww) * onnx(twoside).foobar) + } + function indirect_a() { + expression: tensor(d1[3])(d1+attribute(extra)) + } + function indirect_x() { + expression: constant(xx) + } + function indirect_b() { + expression: query(bb) + } + } + + rank-profile three inherits default { + onnx-model another { + file: files/ax_plus_b.onnx + input vector_A: indirect_a + input matrix_X: indirect_x + input vector_B: indirect_b + output vector_Y: foobar + } + first-phase { + expression: sum(attribute(aa)) + } + global-phase { + rerank-count: 1001 + expression: sum(constant(ww) * onnx(another).foobar) + } + function indirect_a() { + expression: tensor(d1[3]):[0.25, attribute(extra), 0.75] } function indirect_x() { expression: constant(xx) diff --git a/config-model/src/test/derived/rankproperties/rank-profiles.cfg b/config-model/src/test/derived/rankproperties/rank-profiles.cfg index 3ca44288282..b6f51a88197 100644 --- a/config-model/src/test/derived/rankproperties/rank-profiles.cfg +++ b/config-model/src/test/derived/rankproperties/rank-profiles.cfg @@ -50,3 +50,49 @@ rankprofile[].fef.property[].name "vespa.fieldweight.description" rankprofile[].fef.property[].value "35" rankprofile[].fef.property[].name "vespa.fieldweight.tag" rankprofile[].fef.property[].value "88" +rankprofile[].name "withconstants1" +rankprofile[].fef.property[].name "constant(a).value" +rankprofile[].fef.property[].value "tensor(x[2]):[1.0, 2.0]" +rankprofile[].fef.property[].name "constant(a).type" +rankprofile[].fef.property[].value "tensor(x[2])" +rankprofile[].fef.property[].name "constant(b).value" +rankprofile[].fef.property[].value "tensor(y[3]):[3.0, 4.0, 5.0]" +rankprofile[].fef.property[].name "constant(b).type" +rankprofile[].fef.property[].value "tensor(y[3])" +rankprofile[].fef.property[].name "rankingExpression(usea).rankingScript" +rankprofile[].fef.property[].value "constant(a) * 1.0" +rankprofile[].fef.property[].name "rankingExpression(usea).type" +rankprofile[].fef.property[].value "tensor(x[2])" +rankprofile[].fef.property[].name "rankingExpression(useb).rankingScript" +rankprofile[].fef.property[].value "constant(a) * 1.0 + constant(b)" +rankprofile[].fef.property[].name "rankingExpression(useb).type" +rankprofile[].fef.property[].value "tensor(x[2],y[3])" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "reduce(nativeFieldMatch + constant(a) * 1.0 + constant(b), sum)" +rankprofile[].name "withconstants2" +rankprofile[].fef.property[].name "constant(a).value" +rankprofile[].fef.property[].value "tensor(x[2]):[1.0, 2.0]" +rankprofile[].fef.property[].name "constant(a).type" +rankprofile[].fef.property[].value "tensor(x[2])" +rankprofile[].fef.property[].name "constant(b).value" +rankprofile[].fef.property[].value "tensor(y[3]):[3.0, 4.0, 5.0]" +rankprofile[].fef.property[].name "constant(b).type" +rankprofile[].fef.property[].value "tensor(y[3])" +rankprofile[].fef.property[].name "rankingExpression(usea).rankingScript" +rankprofile[].fef.property[].value "constant(a) * 1.0" +rankprofile[].fef.property[].name "rankingExpression(usea).type" +rankprofile[].fef.property[].value "tensor(x[2])" +rankprofile[].fef.property[].name "rankingExpression(useb).rankingScript" +rankprofile[].fef.property[].value "constant(a) * 1.0 + constant(b)" +rankprofile[].fef.property[].name "rankingExpression(useb).type" +rankprofile[].fef.property[].value "tensor(x[2],y[3])" +rankprofile[].fef.property[].name "rankingExpression(usec).rankingScript" +rankprofile[].fef.property[].value "constant(a) + constant(b)" +rankprofile[].fef.property[].name "rankingExpression(usec).type" +rankprofile[].fef.property[].value "tensor(x[2],y[3])" +rankprofile[].fef.property[].name "vespa.rank.firstphase" +rankprofile[].fef.property[].value "rankingExpression(firstphase)" +rankprofile[].fef.property[].name "rankingExpression(firstphase).rankingScript" +rankprofile[].fef.property[].value "reduce(nativeFieldMatch + constant(a) + constant(b), sum)" diff --git a/config-model/src/test/derived/rankproperties/rankproperties.sd b/config-model/src/test/derived/rankproperties/rankproperties.sd index a2eb987d4ff..a13b3081ca7 100644 --- a/config-model/src/test/derived/rankproperties/rankproperties.sd +++ b/config-model/src/test/derived/rankproperties/rankproperties.sd @@ -59,4 +59,28 @@ schema rankproperties { } } + rank-profile withconstants1 { + constants { + constant(a) tensor(x[2]) : [1,2] + constant(b) tensor(y[3]) : [3,4,5] + } + function inline usea() { + expression: constant(a)*1.0 + } + function inline useb() { + expression: usea + constant(b) + } + first-phase { + expression: sum(nativeFieldMatch + useb) + } + } + + rank-profile withconstants2 inherits withconstants1 { + function inline usec() { + expression: constant(a)+constant(b) + } + first-phase { + expression: sum(nativeFieldMatch + usec) + } + } } diff --git a/config-model/src/test/java/com/yahoo/schema/processing/VespaMlModelTestCase.java b/config-model/src/test/java/com/yahoo/schema/processing/VespaMlModelTestCase.java index 01e80e0f47a..664cfaf4ad7 100644 --- a/config-model/src/test/java/com/yahoo/schema/processing/VespaMlModelTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/processing/VespaMlModelTestCase.java @@ -25,8 +25,8 @@ public class VespaMlModelTestCase { private final Path applicationDir = Path.fromString("src/test/integration/vespa/"); private final String expectedRankConfig = - "constant(constant1).type : tensor(x[3])\n" + "constant(constant1).value : tensor(x[3]):[0.5, 1.5, 2.5]\n" + + "constant(constant1).type : tensor(x[3])\n" + "rankingExpression(foo1).rankingScript : reduce(reduce(input1 * input2, sum, name) * constant(constant1), max, x) * 3.0\n" + "rankingExpression(foo1).input1.type : tensor(name{},x[3])\n" + "rankingExpression(foo1).input2.type : tensor(x[3])\n" + |