diff options
author | Jon Bratseth <bratseth@oath.com> | 2021-01-13 10:01:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-13 10:01:22 +0100 |
commit | 9c3327f07b0dd785619f0aa36d6a50a9092b298e (patch) | |
tree | 8368fe7b85a46a2f2e1b37d0856292b7d930103e | |
parent | bf1446b201d476a76be76c92d38bb6d4b5002077 (diff) | |
parent | 9ed2a987c41abb4177b99b9730dc552bfee40f21 (diff) |
Merge pull request #16022 from vespa-engine/lesters/expressions-as-arguments-3
Lesters/expressions as arguments 3
9 files changed, 360 insertions, 32 deletions
diff --git a/config-model/src/test/derived/function_arguments/rank-profiles.cfg b/config-model/src/test/derived/function_arguments/rank-profiles.cfg new file mode 100644 index 00000000000..318b0303a75 --- /dev/null +++ b/config-model/src/test/derived/function_arguments/rank-profiles.cfg @@ -0,0 +1,71 @@ +rankprofile[].name "default" +rankprofile[].fef.property[].name "vespa.type.attribute.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})" +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.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].name "test" +rankprofile[].fef.property[].name "rankingExpression(sin).rankingScript" +rankprofile[].fef.property[].value "sqrt(x)" +rankprofile[].fef.property[].name "rankingExpression(my_func).rankingScript" +rankprofile[].fef.property[].value "x * x" +rankprofile[].fef.property[].name "rankingExpression(my_func@8896f70effb70cdf).rankingScript" +rankprofile[].fef.property[].value "10 * 10" +rankprofile[].fef.property[].name "rankingExpression(my_func@1786f26b4c59c157).rankingScript" +rankprofile[].fef.property[].value "10.1 * 10.1" +rankprofile[].fef.property[].name "rankingExpression(my_func@e7527c516d79e256).rankingScript" +rankprofile[].fef.property[].value "-10 * -10" +rankprofile[].fef.property[].name "rankingExpression(my_func@20d1c0e3bac283b8).rankingScript" +rankprofile[].fef.property[].value "-10.1 * -10.1" +rankprofile[].fef.property[].name "rankingExpression(test_numeric_constants).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@8896f70effb70cdf) + rankingExpression(my_func@1786f26b4c59c157) + rankingExpression(my_func@e7527c516d79e256) + rankingExpression(my_func@20d1c0e3bac283b8)" +rankprofile[].fef.property[].name "rankingExpression(my_func@6f53bfe04128d771).rankingScript" +rankprofile[].fef.property[].value "\"string\" * \"string\"" +rankprofile[].fef.property[].name "rankingExpression(test_string_constants).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@6f53bfe04128d771)" +rankprofile[].fef.property[].name "rankingExpression(my_func@70ae74a94a4fcc5f).rankingScript" +rankprofile[].fef.property[].value "attribute(f1) * attribute(f1)" +rankprofile[].fef.property[].name "rankingExpression(my_func@69ee30cd56b0320f).rankingScript" +rankprofile[].fef.property[].value "term(0).significance * term(0).significance" +rankprofile[].fef.property[].name "rankingExpression(my_func@3c275a61d799634c).rankingScript" +rankprofile[].fef.property[].value "cos(-1.1) * cos(-1.1)" +rankprofile[].fef.property[].name "rankingExpression(my_func@93f6e2e9f3345ca2).rankingScript" +rankprofile[].fef.property[].value "cos(attribute(f1)) * cos(attribute(f1))" +rankprofile[].fef.property[].name "rankingExpression(test_features).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@70ae74a94a4fcc5f) + rankingExpression(my_func@69ee30cd56b0320f) + rankingExpression(my_func@3c275a61d799634c) + rankingExpression(my_func@93f6e2e9f3345ca2)" +rankprofile[].fef.property[].name "rankingExpression(sin@b482a98f3faecbbf).rankingScript" +rankprofile[].fef.property[].value "sqrt(3.14)" +rankprofile[].fef.property[].name "rankingExpression(my_func@1187ba7b5ded5ee0).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(sin@b482a98f3faecbbf) * rankingExpression(sin@b482a98f3faecbbf)" +rankprofile[].fef.property[].name "rankingExpression(my_func@80d1935ed5770717).rankingScript" +rankprofile[].fef.property[].value "cos(3.14) * cos(3.14)" +rankprofile[].fef.property[].name "rankingExpression(test_feature_shadowing).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@1187ba7b5ded5ee0) + rankingExpression(my_func@80d1935ed5770717)" +rankprofile[].fef.property[].name "rankingExpression(my_func@36b285d8fa8a8a1d).rankingScript" +rankprofile[].fef.property[].value "if * if" +rankprofile[].fef.property[].name "rankingExpression(my_func@c0435b78a640e96d).rankingScript" +rankprofile[].fef.property[].value "unknown * unknown" +rankprofile[].fef.property[].name "rankingExpression(my_func@5e5ae9764203b993).rankingScript" +rankprofile[].fef.property[].value "cos * cos" +rankprofile[].fef.property[].name "rankingExpression(test_identifiers).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@36b285d8fa8a8a1d) + rankingExpression(my_func@c0435b78a640e96d) + rankingExpression(my_func@5e5ae9764203b993)" +rankprofile[].fef.property[].name "rankingExpression(my_func@a03bffb2024104a4).rankingScript" +rankprofile[].fef.property[].value "attribute(query(q1)) * attribute(query(q1))" +rankprofile[].fef.property[].name "rankingExpression(test_parses_but_invalid).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@a03bffb2024104a4)" +rankprofile[].fef.property[].name "vespa.type.attribute.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})"
\ No newline at end of file diff --git a/config-model/src/test/derived/function_arguments/test.sd b/config-model/src/test/derived/function_arguments/test.sd new file mode 100644 index 00000000000..a8b0eebe367 --- /dev/null +++ b/config-model/src/test/derived/function_arguments/test.sd @@ -0,0 +1,52 @@ +# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +search args { + + document args { + field f1 type float { + indexing: attribute | summary + } + field t1 type tensor<float>(x{}) { + indexing: attribute | summary + } + field t2 type tensor<float>(x{}) { + indexing: attribute | summary + } + } + + rank-profile test { + + function sin(x) { # shadows internal function "sin" + expression: sqrt(x) + } + + function my_func(x) { + expression: x * x + } + + function test_numeric_constants() { + expression: my_func(10) + my_func(10.1) + my_func(-10) + my_func(-10.1) + } + + function test_string_constants() { + expression: my_func("string") # + my_func(-"string") -> -"string" parses but not a valid Value + } + + function test_features() { + expression: my_func(attribute(f1)) + my_func(term(0).significance) + my_func(cos(-1.1)) + my_func(cos(attribute(f1))) + } + + function test_feature_shadowing() { + expression: my_func(sin(3.14)) + my_func(cos(3.14)) + } + + function test_identifiers() { + expression: my_func(if) + my_func(unknown) + my_func(cos) + } + + function test_parses_but_invalid() { + expression: my_func(attribute(query(q1))) + } + + } + +} diff --git a/config-model/src/test/derived/function_arguments_with_expressions/rank-profiles.cfg b/config-model/src/test/derived/function_arguments_with_expressions/rank-profiles.cfg new file mode 100644 index 00000000000..5e7b38fc264 --- /dev/null +++ b/config-model/src/test/derived/function_arguments_with_expressions/rank-profiles.cfg @@ -0,0 +1,105 @@ +rankprofile[].name "default" +rankprofile[].fef.property[].name "vespa.type.attribute.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})" +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.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].name "test" +rankprofile[].fef.property[].name "rankingExpression(my_square).rankingScript" +rankprofile[].fef.property[].value "x * x" +rankprofile[].fef.property[].name "rankingExpression(my_square@31852fecfab75f29).rankingScript" +rankprofile[].fef.property[].value "2 * 2" +rankprofile[].fef.property[].name "rankingExpression(my_square@56bfa257b4b447a2).rankingScript" +rankprofile[].fef.property[].value "-3.14 * -3.14" +rankprofile[].fef.property[].name "rankingExpression(test_constant).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@31852fecfab75f29) + rankingExpression(my_square@56bfa257b4b447a2)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@c76aeb97d0b6610c).rankingScript" +rankprofile[].fef.property[].value "attribute(i1) * 2" +rankprofile[].fef.property[].name "rankingExpression(my_square@52d8ef83411bc8d0).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@c76aeb97d0b6610c) * rankingExpression(autogenerated_ranking_feature@c76aeb97d0b6610c)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@828fd0618dc7fc06).rankingScript" +rankprofile[].fef.property[].value "attribute(i1) < 1" +rankprofile[].fef.property[].name "rankingExpression(my_square@6b77cba8e7358f11).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@828fd0618dc7fc06) * rankingExpression(autogenerated_ranking_feature@828fd0618dc7fc06)" +rankprofile[].fef.property[].name "rankingExpression(test_arithmetic).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@52d8ef83411bc8d0) + rankingExpression(my_square@6b77cba8e7358f11)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@675b0f8c6790c8bb).rankingScript" +rankprofile[].fef.property[].value "!attribute(i1)" +rankprofile[].fef.property[].name "rankingExpression(my_square@35879139f3786e2f).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@675b0f8c6790c8bb) * rankingExpression(autogenerated_ranking_feature@675b0f8c6790c8bb)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@6084beaceb676bf2).rankingScript" +rankprofile[].fef.property[].value "-attribute(i1)" +rankprofile[].fef.property[].name "rankingExpression(my_square@819381f707f3ee78).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@6084beaceb676bf2) * rankingExpression(autogenerated_ranking_feature@6084beaceb676bf2)" +rankprofile[].fef.property[].name "rankingExpression(test_not_neg).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@35879139f3786e2f) + rankingExpression(my_square@819381f707f3ee78)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@b41d2fa3c2ee40a3).rankingScript" +rankprofile[].fef.property[].value "if (attribute(i1) in [0, 1, 2], 0, 1)" +rankprofile[].fef.property[].name "rankingExpression(my_square@643af1a7339a8b1b).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@b41d2fa3c2ee40a3) * rankingExpression(autogenerated_ranking_feature@b41d2fa3c2ee40a3)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@335f7caa94692e97).rankingScript" +rankprofile[].fef.property[].value "attribute(i1) in [0, 1, 2]" +rankprofile[].fef.property[].name "rankingExpression(my_square@d48185ac029647a5).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@335f7caa94692e97) * rankingExpression(autogenerated_ranking_feature@335f7caa94692e97)" +rankprofile[].fef.property[].name "rankingExpression(test_if_in).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@643af1a7339a8b1b) + rankingExpression(my_square@d48185ac029647a5)" +rankprofile[].fef.property[].name "rankingExpression(my_square@9a5117ae5a6d491b).rankingScript" +rankprofile[].fef.property[].value "cos(attribute(i1)) * cos(attribute(i1))" +rankprofile[].fef.property[].name "rankingExpression(test_function).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@9a5117ae5a6d491b)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@6c8232a0cd94322d).rankingScript" +rankprofile[].fef.property[].value "(attribute(i1) * 2)" +rankprofile[].fef.property[].name "rankingExpression(my_square@181aa0cc505c1788).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@6c8232a0cd94322d) * rankingExpression(autogenerated_ranking_feature@6c8232a0cd94322d)" +rankprofile[].fef.property[].name "rankingExpression(test_embraced).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@181aa0cc505c1788)" +rankprofile[].fef.property[].name "rankingExpression(my_func).rankingScript" +rankprofile[].fef.property[].value "reduce(t, sum, x) + 1" +rankprofile[].fef.property[].name "rankingExpression(my_func@9bbaee2bad5a2fc0).rankingScript" +rankprofile[].fef.property[].value "reduce(attribute(t1), sum, x) + 1" +rankprofile[].fef.property[].name "rankingExpression(test_func).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@9bbaee2bad5a2fc0)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@43bc412603c00a4a).rankingScript" +rankprofile[].fef.property[].value "attribute(t1) * attribute(t2)" +rankprofile[].fef.property[].name "rankingExpression(my_func@7f288a910482845a).rankingScript" +rankprofile[].fef.property[].value "reduce(rankingExpression(autogenerated_ranking_feature@43bc412603c00a4a), sum, x) + 1" +rankprofile[].fef.property[].name "rankingExpression(test_tensor_func_with_expr).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@7f288a910482845a)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@c1057dea8228da3a).rankingScript" +rankprofile[].fef.property[].value "map(attribute(t1), f(x)(x * x))" +rankprofile[].fef.property[].name "rankingExpression(my_func@901c2cc6ceb37765).rankingScript" +rankprofile[].fef.property[].value "reduce(rankingExpression(autogenerated_ranking_feature@c1057dea8228da3a), sum, x) + 1" +rankprofile[].fef.property[].name "rankingExpression(test_func_with_tensor_func).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@901c2cc6ceb37765)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@fb1a4642f23d9d05).rankingScript" +rankprofile[].fef.property[].value "attribute(t1){x:0}" +rankprofile[].fef.property[].name "rankingExpression(my_square@1d27f1b495b50910).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(autogenerated_ranking_feature@fb1a4642f23d9d05) * rankingExpression(autogenerated_ranking_feature@fb1a4642f23d9d05)" +rankprofile[].fef.property[].name "rankingExpression(test_func_with_slice).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_square@1d27f1b495b50910)" +rankprofile[].fef.property[].name "rankingExpression(call_func_with_expr@640470df47a83000.c156faa8f98c0b0c).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@7f288a910482845a)" +rankprofile[].fef.property[].name "rankingExpression(test_func_via_func_with_expr).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(call_func_with_expr@640470df47a83000.c156faa8f98c0b0c)" +rankprofile[].fef.property[].name "rankingExpression(autogenerated_ranking_feature@1044065d971a7507).rankingScript" +rankprofile[].fef.property[].value "a * b" +rankprofile[].fef.property[].name "rankingExpression(my_func@93366be10bade547).rankingScript" +rankprofile[].fef.property[].value "reduce(rankingExpression(autogenerated_ranking_feature@1044065d971a7507), sum, x) + 1" +rankprofile[].fef.property[].name "rankingExpression(call_func_with_expr).rankingScript" +rankprofile[].fef.property[].value "rankingExpression(my_func@93366be10bade547)" +rankprofile[].fef.property[].name "vespa.type.attribute.t1" +rankprofile[].fef.property[].value "tensor<float>(x{})" +rankprofile[].fef.property[].name "vespa.type.attribute.t2" +rankprofile[].fef.property[].value "tensor<float>(x{})"
\ No newline at end of file diff --git a/config-model/src/test/derived/function_arguments_with_expressions/test.sd b/config-model/src/test/derived/function_arguments_with_expressions/test.sd new file mode 100644 index 00000000000..bf7453f9001 --- /dev/null +++ b/config-model/src/test/derived/function_arguments_with_expressions/test.sd @@ -0,0 +1,76 @@ +# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +search test { + + document test { + field i1 type int { + indexing: attribute | summary + } + field t1 type tensor<float>(x{}) { + indexing: attribute | summary + } + field t2 type tensor<float>(x{}) { + indexing: attribute | summary + } + } + + rank-profile test { + + function my_square(x) { + expression: x * x + } + + function test_constant() { + expression: my_square(2) + my_square(-3.14) + } + + function test_arithmetic() { + expression: my_square(attribute(i1) * 2) + my_square(attribute(i1) < 1) + } + + function test_not_neg() { + expression: my_square( ! attribute(i1) ) + my_square( -attribute(i1) ) + } + + function test_if_in() { + expression: my_square( if(attribute(i1) in [0,1,2], 0, 1) ) + my_square( attribute(i1) in [0,1,2] ) + } + + function test_function() { + expression: my_square( cos(attribute(i1)) ) + } + + function test_embraced() { + expression: my_square( ( attribute(i1) * 2 ) ) + } + + function my_func(t) { + expression: sum(t, x) + 1 + } + + function test_func() { + expression: my_func( attribute(t1) ) + } + + function test_tensor_func_with_expr() { + expression: my_func( attribute(t1) * attribute(t2) ) + } + + function test_func_with_tensor_func() { + expression: my_func( map(attribute(t1), f(x)(x * x)) ) + } + + function test_func_with_slice() { + expression: my_square( attribute(t1){x:0} ) + } + + function test_func_via_func_with_expr() { + expression: call_func_with_expr( attribute(t1), attribute(t2) ) + } + + function call_func_with_expr(a, b) { + expression: my_func( a * b ) + } + + } + +} diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/RankingExpressionShadowingTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/RankingExpressionShadowingTestCase.java index 84a6d2a154a..8fe4a8fb022 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/RankingExpressionShadowingTestCase.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/RankingExpressionShadowingTestCase.java @@ -207,22 +207,20 @@ public class RankingExpressionShadowingTestCase extends SchemaTestCase { queryProfiles, new ImportedMlModels(), new AttributeFields(s)).configProperties(); - assertEquals("(rankingExpression(relu@).rankingScript, max(1.0,reduce(query(q) * constant(W_hidden), sum, input) + constant(b_input)))", + assertEquals("(rankingExpression(autogenerated_ranking_feature@).rankingScript, reduce(query(q) * constant(W_hidden), sum, input) + constant(b_input))", censorBindingHash(testRankProperties.get(0).toString())); - assertEquals("(rankingExpression(hidden_layer).rankingScript, rankingExpression(relu@))", + assertEquals("(rankingExpression(relu@).rankingScript, max(1.0,rankingExpression(autogenerated_ranking_feature@)))", censorBindingHash(testRankProperties.get(1).toString())); - assertEquals("(rankingExpression(hidden_layer).type, tensor(x[1]))", + assertEquals("(rankingExpression(hidden_layer).rankingScript, rankingExpression(relu@))", censorBindingHash(testRankProperties.get(2).toString())); assertEquals("(rankingExpression(final_layer).rankingScript, sigmoid(reduce(rankingExpression(hidden_layer) * constant(W_final), sum, hidden) + constant(b_final)))", - testRankProperties.get(3).toString()); - assertEquals("(rankingExpression(final_layer).type, tensor(x[1]))", testRankProperties.get(4).toString()); assertEquals("(rankingExpression(relu).rankingScript, max(1.0,x))", - testRankProperties.get(5).toString()); + testRankProperties.get(6).toString()); assertEquals("(vespa.rank.secondphase, rankingExpression(secondphase))", - testRankProperties.get(6).toString()); + testRankProperties.get(7).toString()); assertEquals("(rankingExpression(secondphase).rankingScript, reduce(rankingExpression(final_layer), sum))", - testRankProperties.get(7).toString()); + testRankProperties.get(8).toString()); } private QueryProfileRegistry queryProfileWith(String field, String type) { diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/derived/ExpressionsAsArgsTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/derived/ExpressionsAsArgsTestCase.java new file mode 100644 index 00000000000..9a5c30f773e --- /dev/null +++ b/config-model/src/test/java/com/yahoo/searchdefinition/derived/ExpressionsAsArgsTestCase.java @@ -0,0 +1,25 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition.derived; + +import com.yahoo.searchdefinition.parser.ParseException; +import org.junit.Test; + +import java.io.IOException; + +/** + * Tests correct deriving of expressions as arguments to functions. + * + * @author lesters + */ +public class ExpressionsAsArgsTestCase extends AbstractExportingTestCase { + + @Test + public void testDocumentDeriving() throws IOException, ParseException { + assertCorrectDeriving("function_arguments"); + assertCorrectDeriving("function_arguments_with_expressions"); + } + +} + + + diff --git a/searchlib/abi-spec.json b/searchlib/abi-spec.json index 88eccb4559f..d412f408350 100644 --- a/searchlib/abi-spec.json +++ b/searchlib/abi-spec.json @@ -875,7 +875,6 @@ "public final java.lang.String outs()", "public final java.lang.String out()", "public final java.util.List args()", - "public final com.yahoo.searchlib.rankingexpression.rule.ExpressionNode arg()", "public final com.yahoo.searchlib.rankingexpression.rule.ExpressionNode function()", "public final com.yahoo.searchlib.rankingexpression.rule.FunctionNode scalarOrTensorFunction()", "public final com.yahoo.searchlib.rankingexpression.rule.TensorFunctionNode tensorFunction()", 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 9f900ffed36..3974ca7ed0d 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java @@ -3,7 +3,12 @@ package com.yahoo.searchlib.rankingexpression; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.yahoo.searchlib.rankingexpression.rule.ConstantNode; import com.yahoo.searchlib.rankingexpression.rule.ExpressionNode; +import com.yahoo.searchlib.rankingexpression.rule.FunctionNode; +import com.yahoo.searchlib.rankingexpression.rule.NameNode; +import com.yahoo.searchlib.rankingexpression.rule.NegativeNode; +import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode; import com.yahoo.searchlib.rankingexpression.rule.SerializationContext; import com.yahoo.tensor.TensorType; import com.yahoo.text.Utf8; @@ -131,7 +136,16 @@ public class ExpressionFunction { public Instance expand(SerializationContext context, List<ExpressionNode> argumentValues, Deque<String> path) { Map<String, String> argumentBindings = new HashMap<>(); for (int i = 0; i < arguments.size() && i < argumentValues.size(); ++i) { - argumentBindings.put(arguments.get(i), argumentValues.get(i).toString(new StringBuilder(), context, path, null).toString()); + String key = arguments.get(i); + ExpressionNode expr = argumentValues.get(i); + String binding = expr.toString(new StringBuilder(), context, path, null).toString(); + + if (shouldGenerateFeature(expr)) { + String funcName = "autogenerated_ranking_feature@" + Long.toHexString(symbolCode(key + "=" + binding)); + context.addFunctionSerialization(RankingExpression.propertyName(funcName), binding); + binding = "rankingExpression(" + funcName + ")"; + } + argumentBindings.put(key, binding); } context = argumentBindings.isEmpty() ? context.withoutBindings() : context.withBindings(argumentBindings); String symbol = toSymbol(argumentBindings); @@ -139,6 +153,15 @@ public class ExpressionFunction { return new Instance(symbol, expressionString); } + private boolean shouldGenerateFeature(ExpressionNode expr) { + if (expr instanceof ConstantNode) return false; + if (expr instanceof ReferenceNode) return false; + if (expr instanceof NameNode) return false; + if (expr instanceof FunctionNode) return false; + if (expr instanceof NegativeNode && ((NegativeNode) expr).getValue() instanceof ConstantNode) return false; + return true; + } + /** * Returns a symbolic string that represents this function with a given * list of arguments. The arguments are mangled by hashing the string @@ -161,7 +184,6 @@ public class ExpressionFunction { return ret.toString(); } - /** * Returns a more unique hash code than what Java's own {@link * String#hashCode()} method would produce. diff --git a/searchlib/src/main/javacc/RankingExpressionParser.jj b/searchlib/src/main/javacc/RankingExpressionParser.jj index 09880b8dfc3..36b1f9627bb 100755 --- a/searchlib/src/main/javacc/RankingExpressionParser.jj +++ b/searchlib/src/main/javacc/RankingExpressionParser.jj @@ -328,30 +328,10 @@ List<ExpressionNode> args() : ExpressionNode argument; } { - ( ( argument = arg() { arguments.add(argument); } ( <COMMA> argument = arg() { arguments.add(argument); } )* )? ) + ( ( argument = expression() { arguments.add(argument); } ( <COMMA> argument = expression() { arguments.add(argument); } )* )? ) { return arguments; } } -// TODO: Replace use of this for function arguments with value() -// For that to work with the current search execution framework -// we need to generate another function for the argument such that we can replace -// instances of the argument with the reference to that function in the same way -// as we replace by constants/names today (this can make for some fun combinatorial explosion). -// We should also stop doing function expansion in the toString of a function. -// - Jon 2014-05-02 -ExpressionNode arg() : -{ - ExpressionNode ret; - String name; - Function fnc; -} -{ - ( ret = constantPrimitive() | - LOOKAHEAD(2) ret = feature() | - name = identifier() { ret = new NameNode(name); } ) - { return ret; } -} - ExpressionNode function() : { ExpressionNode function; |