diff options
author | Jon Bratseth <bratseth@oath.com> | 2018-07-06 13:17:25 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@oath.com> | 2018-07-06 13:17:25 +0200 |
commit | 99228d5d9bfa7aea7472895e9c5c959d9b5fba1b (patch) | |
tree | 5f43cc8eca80da69ffd865fe0fba50de5b9eef2f | |
parent | a2a175887d62296af5051a07f0c1dd36cc07c4b0 (diff) |
Import bound functions separately
-rw-r--r-- | config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java | 5 | ||||
-rw-r--r-- | model-inference/src/main/java/ai/vespa/models/evaluation/Model.java | 23 | ||||
-rw-r--r-- | model-inference/src/main/java/ai/vespa/models/evaluation/ModelsEvaluator.java | 1 | ||||
-rw-r--r-- | model-inference/src/main/java/ai/vespa/models/evaluation/RankProfilesConfigImporter.java | 82 | ||||
-rw-r--r-- | model-inference/src/main/java/ai/vespa/models/evaluation/config/RankProfilesConfigImporter.java | 55 | ||||
-rw-r--r-- | model-inference/src/test/java/ai/vespa/models/evaluation/RankProfilesImporterTest.java (renamed from model-inference/src/test/java/ai/vespa/models/evaluation/config/RankProfilesImporterTest.java) | 31 |
6 files changed, 121 insertions, 76 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 a69c524e863..5855dedc415 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/RankProfile.java @@ -932,8 +932,8 @@ public class RankProfile implements Serializable, Cloneable { public static class Macro implements Serializable, Cloneable { private final String name; - private String textualExpression=null; - private RankingExpression expression=null; + private String textualExpression = null; + private RankingExpression expression = null; private List<String> formalParams = new ArrayList<>(); /** True if this should be inlined into calling expressions. Useful for very cheap macros. */ @@ -998,6 +998,7 @@ public class RankProfile implements Serializable, Cloneable { } public static final class DiversitySettings { + private String attribute = null; private int minGroups = 0; private double cutoffFactor = 10; diff --git a/model-inference/src/main/java/ai/vespa/models/evaluation/Model.java b/model-inference/src/main/java/ai/vespa/models/evaluation/Model.java index 76d990a493e..b2eb8546a7c 100644 --- a/model-inference/src/main/java/ai/vespa/models/evaluation/Model.java +++ b/model-inference/src/main/java/ai/vespa/models/evaluation/Model.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList; import com.yahoo.searchlib.rankingexpression.ExpressionFunction; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -16,18 +17,38 @@ public class Model { private final String name; + /** Free functions */ private final ImmutableList<ExpressionFunction> functions; + /** An instance of each usage of the above function, where variables are replaced by their bindings */ + private final ImmutableList<ExpressionFunction> boundFunctions; + public Model(String name, Collection<ExpressionFunction> functions) { + this(name, functions, Collections.emptyList()); + } + + Model(String name, Collection<ExpressionFunction> functions, Collection<ExpressionFunction> boundFunctions) { this.name = name; this.functions = ImmutableList.copyOf(functions); + this.boundFunctions = ImmutableList.copyOf(boundFunctions); } public String name() { return name; } - /** Returns an immutable list of the expression functions of this */ + /** Returns an immutable list of the free (callable) functions of this */ public List<ExpressionFunction> functions() { return functions; } + /** Returns an immutable list of the bound function instances of this */ + List<ExpressionFunction> boundFunctions() { return functions; } + + /** Returns the function withe the given name, or null if none */ // TODO: Parameter overloading? + ExpressionFunction function(String name) { + for (ExpressionFunction function : functions) + if (function.getName().equals(name)) + return function; + return null; + } + @Override public String toString() { return "Model '" + name + "'"; } diff --git a/model-inference/src/main/java/ai/vespa/models/evaluation/ModelsEvaluator.java b/model-inference/src/main/java/ai/vespa/models/evaluation/ModelsEvaluator.java index c1a22a361e9..3532409766b 100644 --- a/model-inference/src/main/java/ai/vespa/models/evaluation/ModelsEvaluator.java +++ b/model-inference/src/main/java/ai/vespa/models/evaluation/ModelsEvaluator.java @@ -1,7 +1,6 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package ai.vespa.models.evaluation; -import ai.vespa.models.evaluation.config.RankProfilesConfigImporter; import com.yahoo.vespa.config.search.RankProfilesConfig; /** diff --git a/model-inference/src/main/java/ai/vespa/models/evaluation/RankProfilesConfigImporter.java b/model-inference/src/main/java/ai/vespa/models/evaluation/RankProfilesConfigImporter.java new file mode 100644 index 00000000000..30eabb6f8a4 --- /dev/null +++ b/model-inference/src/main/java/ai/vespa/models/evaluation/RankProfilesConfigImporter.java @@ -0,0 +1,82 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.models.evaluation; + +import ai.vespa.models.evaluation.Model; +import com.yahoo.searchlib.rankingexpression.ExpressionFunction; +import com.yahoo.searchlib.rankingexpression.RankingExpression; +import com.yahoo.vespa.config.search.RankProfilesConfig; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Converts RankProfilesConfig instances to RankingExpressions for evaluation + * + * @author bratseth + */ +class RankProfilesConfigImporter { + + private static final Pattern expressionPattern = + Pattern.compile("rankingExpression\\(([a-zA-Z0-9_]+)(@[a-f0-9]+\\.[a-f0-9]+)?\\)\\.rankingScript"); + + /** + * Returns a map of the models contained in this config, indexed on name. + * The map is modifiable and owned by the caller. + */ + public Map<String, Model> importFrom(RankProfilesConfig config) { + Map<String, Model> models = new HashMap<>(); + for (RankProfilesConfig.Rankprofile profile : config.rankprofile()) { + Model model = importProfile(profile); + models.put(model.name(), model); + } + return models; + } + + private Model importProfile(RankProfilesConfig.Rankprofile profile) { + System.out.println("Importing " + profile.name()); + List<ExpressionFunction> functions = new ArrayList<>(); + List<ExpressionFunction> boundFunctions = new ArrayList<>(); + ExpressionFunction firstPhase = null; + ExpressionFunction secondPhase = null; + for (RankProfilesConfig.Rankprofile.Fef.Property property : profile.fef().property()) { + Matcher expressionMatcher = expressionPattern.matcher(property.name()); + if ( expressionMatcher.matches()) { + String name = expressionMatcher.group(1); + String instance = expressionMatcher.group(2); + List<String> arguments = new ArrayList<>(); + RankingExpression expression = RankingExpression.from(property.value()); + + if (instance == null) { + System.out.println(" " + name + ": " + expression); + functions.add(new ExpressionFunction(name, arguments, expression)); + } else { + System.out.println(" Binding of " + name + ": " + expression); + boundFunctions.add(new ExpressionFunction(name + instance, arguments, expression)); + } + } + else if (property.name().equals("vespa.rank.firstphase")) { // Include in addition to macros + firstPhase = new ExpressionFunction("firstphase", new ArrayList<>(), RankingExpression.from(property.value())); + } + else if (property.name().equals("vespa.rank.secondphase")) { // Include in addition to macros + secondPhase = new ExpressionFunction("secondphase", new ArrayList<>(), RankingExpression.from(property.value())); + } + } + if (functionByName("firstphase", functions) == null && firstPhase != null) // may be already included, depending on body + functions.add(firstPhase); + if (functionByName("secondphase", functions) == null && secondPhase != null) // may be already included, depending on body + functions.add(secondPhase); + return new Model(profile.name(), functions, boundFunctions); + } + + private ExpressionFunction functionByName(String name, List<ExpressionFunction> functions) { + for (ExpressionFunction function : functions) + if (function.getName().equals(name)) + return function; + return null; + } + +} diff --git a/model-inference/src/main/java/ai/vespa/models/evaluation/config/RankProfilesConfigImporter.java b/model-inference/src/main/java/ai/vespa/models/evaluation/config/RankProfilesConfigImporter.java deleted file mode 100644 index a81006d526e..00000000000 --- a/model-inference/src/main/java/ai/vespa/models/evaluation/config/RankProfilesConfigImporter.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package ai.vespa.models.evaluation.config; - -import ai.vespa.models.evaluation.Model; -import com.yahoo.searchlib.rankingexpression.ExpressionFunction; -import com.yahoo.searchlib.rankingexpression.RankingExpression; -import com.yahoo.vespa.config.search.RankProfilesConfig; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Converts RankProfilesConfig instances to RankingExpressions for evaluation - * - * @author bratseth - */ -public class RankProfilesConfigImporter { - - private static final Pattern expressionPattern = Pattern.compile("rankingExpression\\(([a-zA-Z0-9_]+)\\)\\.rankingScript"); - - /** - * Returns a map of the models contained in this config, indexed on name. - * The map is modifiable and owned by the caller. - */ - public Map<String, Model> importFrom(RankProfilesConfig config) { - Map<String, Model> models = new HashMap<>(); - for (RankProfilesConfig.Rankprofile profile : config.rankprofile()) { - Model model = importProfile(profile); - models.put(model.name(), model); - } - return models; - } - - private Model importProfile(RankProfilesConfig.Rankprofile profile) { - System.out.println("Importing " + profile.name()); - List<ExpressionFunction> functions = new ArrayList<>(); - for (RankProfilesConfig.Rankprofile.Fef.Property property : profile.fef().property()) { - Matcher expressionMatcher = expressionPattern.matcher(property.name()); - if ( ! expressionMatcher.matches()) continue; - - System.out.println(" Importing " + expressionMatcher.group(0)); - - String name = expressionMatcher.group(0); - List<String> arguments = new ArrayList<>(); - RankingExpression expression = RankingExpression.from(property.value()); - functions.add(new ExpressionFunction(name, arguments, expression)); - } - return new Model(profile.name(), functions); - } - -} diff --git a/model-inference/src/test/java/ai/vespa/models/evaluation/config/RankProfilesImporterTest.java b/model-inference/src/test/java/ai/vespa/models/evaluation/RankProfilesImporterTest.java index 2e93a1a138d..16ae433b958 100644 --- a/model-inference/src/test/java/ai/vespa/models/evaluation/config/RankProfilesImporterTest.java +++ b/model-inference/src/test/java/ai/vespa/models/evaluation/RankProfilesImporterTest.java @@ -1,7 +1,6 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package ai.vespa.models.evaluation.config; +package ai.vespa.models.evaluation; -import ai.vespa.models.evaluation.Model; import com.yahoo.config.subscription.ConfigGetter; import com.yahoo.config.subscription.FileSource; import com.yahoo.searchlib.rankingexpression.ExpressionFunction; @@ -13,7 +12,6 @@ import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; /** * Tests instantiating models from rank-profiles configs. @@ -23,7 +21,7 @@ import static org.junit.Assert.assertTrue; public class RankProfilesImporterTest { @Test - public void testRankexpression() { + public void testImporting() { String configPath = "src/test/resources/config/rankexpression/rank-profiles.cfg"; RankProfilesConfig config = new ConfigGetter<>(new FileSource(new File(configPath)), RankProfilesConfig.class).getConfig(""); Map<String, Model> models = new RankProfilesConfigImporter().importFrom(config); @@ -31,21 +29,20 @@ public class RankProfilesImporterTest { Model macros = models.get("macros"); assertNotNull(macros); assertEquals(4, macros.functions().size()); - ExpressionFunction function = functionByName("fourtimessum", macros); - assertNotNull(function); - - } - - @Test - public void testRegexp() { - assertTrue("a(foo)".matches("a\\([a-zA-Z0-9_]+\\)")); + assertFunction("fourtimessum", "4 * (var1 + var2)", macros); + assertFunction("firstphase", "match + fieldMatch(title) + rankingExpression(myfeature)", macros); + assertFunction("secondphase", "rankingExpression(fourtimessum@5cf279212355b980.67f1e87166cfef86)", macros); + assertFunction("myfeature", + "70 * fieldMatch(title).completeness * pow(0 - fieldMatch(title).earliness,2) + " + + "30 * pow(0 - fieldMatch(description).earliness,2)", + macros); } - private ExpressionFunction functionByName(String name, Model model) { - for (ExpressionFunction function : model.functions()) - if (function.getName().equals(name)) - return function; - return null; + private void assertFunction(String name, String expression, Model model) { + ExpressionFunction function = model.function(name); + assertNotNull(function); + assertEquals(name, function.getName()); + assertEquals(expression, function.getBody().toString()); } } |