From 5a96592dcb33d28dfb062fcf53ba1956d1de53ab Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 12 Oct 2021 14:13:46 +0200 Subject: Add support for control of execute on match, rerank, and summary. --- .../com/yahoo/searchdefinition/RankProfile.java | 20 ++++ config-model/src/main/javacc/SDParser.jj | 51 +++++++++ .../searchdefinition/RankPropertiesTestCase.java | 127 ++++++++++++++++----- 3 files changed, 172 insertions(+), 26 deletions(-) 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 77182e05f9b..68faa462fdd 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java @@ -673,6 +673,26 @@ public class RankProfile implements Cloneable { inputFeatures.put(ref, declaredType); } + public static class ExecuteOperation { + public enum Phase { onmatch, onrerank, onsummary} + final Phase phase; + final String attribute; + final String operation; + ExecuteOperation(Phase phase, String attribute, String operation) { + this.phase = phase; + this.attribute = attribute; + this.operation = operation; + } + } + private final List executeOperations = new ArrayList<>(); + + public void addExecuteOperation(ExecuteOperation.Phase phase, String attribute, String operation) { + executeOperations.add(new ExecuteOperation(phase, attribute, operation)); + addRankProperty("vespa.execute." + phase + ".attribute", attribute); + addRankProperty("vespa.execute." + phase + ".operation", operation); + } + public List getExecuteOperations() { return executeOperations; } + public RankingExpressionFunction findFunction(String name) { RankingExpressionFunction function = functions.get(name); return ((function == null) && (getInherited() != null)) diff --git a/config-model/src/main/javacc/SDParser.jj b/config-model/src/main/javacc/SDParser.jj index 01a8ac21658..11ebd7c8b3e 100644 --- a/config-model/src/main/javacc/SDParser.jj +++ b/config-model/src/main/javacc/SDParser.jj @@ -205,6 +205,11 @@ TOKEN : | < LOOSE: "loose" > | < STRICT: "strict" > | < DOCUMENT: "document" > +| < EXECUTE: "execute" > +| < OPERATION: "operation" > +| < ON_MATCH: "on-match" > +| < ON_RERANK: "on-rerank" > +| < ON_SUMMARY: "on-summary" > | < STRUCT: "struct" > | < INHERITS: "inherits" > | < FIELD: "field" > @@ -2058,6 +2063,7 @@ Object rankProfileItem(RankProfile profile) : { } | firstPhase(profile) | matchPhase(profile) | function(profile) + | execute(profile) | ignoreRankFeatures(profile) | numThreadsPerSearch(profile) | minHitsPerThread(profile) @@ -2086,6 +2092,43 @@ void inheritsRankProfile(RankProfile profile) : { profile.setInherited(str); } } +/** + * This rule consumes an execute statement of a rank-profile. + * + * @param profile The profile to modify. + */ +void execute(RankProfile profile) : +{ +} +{ + lbrace() (execute_operation(profile) )+ + { } +} + +void execute_operation(RankProfile profile) : +{ + String attribute, operation; + RankProfile.ExecuteOperation.Phase phase; +} +{ + ( { phase = RankProfile.ExecuteOperation.Phase.onmatch; } + | { phase = RankProfile.ExecuteOperation.Phase.onrerank; } + | { phase = RankProfile.ExecuteOperation.Phase.onsummary; } + ) + lbrace() attribute = identifier() operation = execute_expr() ()* + { profile.addExecuteOperation(phase, attribute, operation); } +} + +String execute_expr() : +{ + String op; + Number constant = null; +} +{ + (("++" | "--") { op = token.image; } | ("+=" | "-=" | "*=" | "/=" | "%=" | "=") { op = token.image; } constant = consumeNumber()) + { return constant != null ? (op + constant) : op; } +} + /** * This rule consumes a function statement of a rank-profile. * @@ -2844,6 +2887,14 @@ double consumeFloat() : { } { return Double.valueOf(token.image); } } +Number consumeNumber() : +{ + Number num; +} +{ + (num = consumeFloat() | num = consumeLong()) { return num; } +} + /** * This rule consumes an opening brace with leading and trailing newline tokens. */ diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/RankPropertiesTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/RankPropertiesTestCase.java index 6f913e1c139..987e92c8c68 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/RankPropertiesTestCase.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/RankPropertiesTestCase.java @@ -10,6 +10,9 @@ import com.yahoo.searchdefinition.parser.ParseException; import ai.vespa.rankingexpression.importer.configmodelview.ImportedMlModels; import org.junit.Test; +import java.util.List; + +import static com.yahoo.config.model.test.TestUtil.joinLines; import static org.junit.Assert.assertEquals; /** @@ -21,32 +24,30 @@ public class RankPropertiesTestCase extends SchemaTestCase { public void testRankPropertyInheritance() throws ParseException { RankProfileRegistry rankProfileRegistry = new RankProfileRegistry(); SearchBuilder builder = new SearchBuilder(rankProfileRegistry); - builder.importString( - "search test {\n" + - " document test { \n" + - " field a type string { \n" + - " indexing: index \n" + - " }\n" + - " }\n" + - " \n" + - " rank-profile parent {\n" + - " first-phase {\n" + - " expression: a\n" + - " }\n" + - " rank-properties {\n" + - " query(a): 1500 \n" + - " }\n" + - " }\n" + - " rank-profile child inherits parent {\n" + - " first-phase {\n" + - " expression: a\n" + - " }\n" + - " rank-properties {\n" + - " query(a): 2000 \n" + - " }\n" + - " }\n" + - "\n" + - "}\n"); + builder.importString(joinLines( + "search test {", + " document test {", + " field a type string { ", + " indexing: index ", + " }", + " }", + " rank-profile parent {", + " first-phase {", + " expression: a", + " }", + " rank-properties {", + " query(a): 1500 ", + " }", + " }", + " rank-profile child inherits parent {", + " first-phase {", + " expression: a", + " }", + " rank-properties {", + " query(a): 2000 ", + " }", + " }", + "}")); builder.build(); Search search = builder.getSearch(); AttributeFields attributeFields = new AttributeFields(search); @@ -76,5 +77,79 @@ public class RankPropertiesTestCase extends SchemaTestCase { assertEquals("(query(a), 2000)", rawChild.configProperties().get(0).toString()); } } + @Test + public void testRankProfileExecute() throws ParseException { + RankProfileRegistry rankProfileRegistry = new RankProfileRegistry(); + SearchBuilder builder = new SearchBuilder(rankProfileRegistry); + builder.importString(joinLines( + "search test {", + " document test {", + " field a type int { ", + " indexing: attribute ", + " }", + " }", + " field synthetic_attribute_a type int {", + " indexing: attribute", + " attribute: mutable", + " }", + " field synthetic_attribute_b type double {", + " indexing: attribute", + " attribute: mutable", + " }", + " field synthetic_attribute_c type long {", + " indexing: attribute", + " attribute: mutable", + " }", + " rank-profile a {", + " execute {", + " on-match {", + " synthetic_attribute_a ++", + " }", + " on-rerank {", + " synthetic_attribute_b = 1.01", + " }", + " on-summary {", + " synthetic_attribute_c --", + " }", + " }", + " first-phase {", + " expression: a", + " }", + " }", + " rank-profile b {", + " first-phase {", + " expression: a", + " }", + " second-phase {", + " expression: a", + " }", + " }", + "}")); + builder.build(); + Search search = builder.getSearch(); + RankProfile a = rankProfileRegistry.get(search, "a"); + List operations = a.getExecuteOperations(); + assertEquals(3, operations.size()); + assertEquals(RankProfile.ExecuteOperation.Phase.onmatch, operations.get(0).phase); + assertEquals("synthetic_attribute_a", operations.get(0).attribute); + assertEquals("++", operations.get(0).operation); + assertEquals(RankProfile.ExecuteOperation.Phase.onrerank, operations.get(1).phase); + assertEquals("synthetic_attribute_b", operations.get(1).attribute); + assertEquals("=1.01", operations.get(1).operation); + assertEquals(RankProfile.ExecuteOperation.Phase.onsummary, operations.get(2).phase); + assertEquals("synthetic_attribute_c", operations.get(2).attribute); + assertEquals("--", operations.get(2).operation); + + AttributeFields attributeFields = new AttributeFields(search); + RawRankProfile raw = new RawRankProfile(a, new LargeRankExpressions(new MockFileRegistry()), new QueryProfileRegistry(), new ImportedMlModels(), attributeFields, new TestProperties()); + assertEquals(7, raw.configProperties().size()); + assertEquals("(vespa.execute.onmatch.attribute, synthetic_attribute_a)", raw.configProperties().get(0).toString()); + assertEquals("(vespa.execute.onmatch.operation, ++)", raw.configProperties().get(1).toString()); + assertEquals("(vespa.execute.onrerank.attribute, synthetic_attribute_b)", raw.configProperties().get(2).toString()); + assertEquals("(vespa.execute.onrerank.operation, =1.01)", raw.configProperties().get(3).toString()); + assertEquals("(vespa.execute.onsummary.attribute, synthetic_attribute_c)", raw.configProperties().get(4).toString()); + assertEquals("(vespa.execute.onsummary.operation, --)", raw.configProperties().get(5).toString()); + assertEquals("(vespa.rank.firstphase, a)", raw.configProperties().get(6).toString()); + } } -- cgit v1.2.3