aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2021-10-13 00:00:32 +0200
committerGitHub <noreply@github.com>2021-10-13 00:00:32 +0200
commita5e37d9dfada0dbc346857b09be18779d2652adf (patch)
tree7db1ebe0d36cc3b76b90f7eabca6c7cf037422ed
parent35155da6c455db4247197560033103e102c04a00 (diff)
parent5a96592dcb33d28dfb062fcf53ba1956d1de53ab (diff)
Merge pull request #19521 from vespa-engine/balder/on-exeute-in-rank-profilev7.482.13
Add support for control of execute on match, rerank, and summary.
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java20
-rw-r--r--config-model/src/main/javacc/SDParser.jj51
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/RankPropertiesTestCase.java127
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<ExecuteOperation> 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<ExecuteOperation> 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)
@@ -2087,6 +2093,43 @@ void inheritsRankProfile(RankProfile profile) :
}
/**
+ * This rule consumes an execute statement of a rank-profile.
+ *
+ * @param profile The profile to modify.
+ */
+void execute(RankProfile profile) :
+{
+}
+{
+ <EXECUTE> lbrace() (execute_operation(profile) <NL>)+ <RBRACE>
+ { }
+}
+
+void execute_operation(RankProfile profile) :
+{
+ String attribute, operation;
+ RankProfile.ExecuteOperation.Phase phase;
+}
+{
+ ( <ON_MATCH> { phase = RankProfile.ExecuteOperation.Phase.onmatch; }
+ | <ON_RERANK> { phase = RankProfile.ExecuteOperation.Phase.onrerank; }
+ | <ON_SUMMARY> { phase = RankProfile.ExecuteOperation.Phase.onsummary; }
+ )
+ lbrace() attribute = identifier() operation = execute_expr() (<NL>)* <RBRACE>
+ { 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.
*
* @param profile The profile to modify.
@@ -2844,6 +2887,14 @@ double consumeFloat() : { }
<DOUBLE> { 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<RankProfile.ExecuteOperation> 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());
+ }
}