summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2018-02-21 13:10:38 +0100
committerJon Bratseth <bratseth@oath.com>2018-02-21 13:10:38 +0100
commit96d16478b29443c420ff64acc8e5ff90271c5951 (patch)
tree15f2795f55a02055f4e01057cb41c4f194bca49a /searchlib
parent108ab8eb0781fb59b8cbc13281816d5f7425b064 (diff)
Revert "Merge pull request #5091 from vespa-engine/revert-5065-bratseth/typecheck-all-2"
This reverts commit f15c8a6384031adfe0764f20e6448be4eccd517b, reversing changes made to 2a343e5a88a023a3f3246db2f47726e229d28fac.
Diffstat (limited to 'searchlib')
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java31
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/FeatureList.java5
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java6
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java121
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java5
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Context.java10
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/DoubleOnlyArrayContext.java5
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapContext.java7
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java38
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java32
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTForestNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Arguments.java18
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/BooleanNode.java1
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ConstantNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/EmbracedNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ExpressionNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java74
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/GeneratorLambdaFunctionNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/IfNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NameNode.java4
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NegativeNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NotNode.java3
-rwxr-xr-xsearchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java111
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java33
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SetMembershipNode.java3
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TensorFunctionNode.java10
-rw-r--r--searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/EvaluationTestCase.java7
-rw-r--r--searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeResolutionTestCase.java22
-rw-r--r--searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/rule/ArgumentsTestCase.java4
34 files changed, 401 insertions, 185 deletions
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 2e2858da238..262aba89f27 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java
@@ -3,6 +3,7 @@ package com.yahoo.searchlib.rankingexpression;
import com.google.common.collect.ImmutableList;
import com.yahoo.searchlib.rankingexpression.rule.ExpressionNode;
+import com.yahoo.searchlib.rankingexpression.rule.FunctionReferenceContext;
import com.yahoo.searchlib.rankingexpression.rule.SerializationContext;
import com.yahoo.text.Utf8;
@@ -11,9 +12,9 @@ import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
- * <p>A function defined by a ranking expression</p>
+ * A function defined by a ranking expression
*
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ * @author Simon Thoresen
* @author bratseth
*/
public class ExpressionFunction {
@@ -23,7 +24,7 @@ public class ExpressionFunction {
private final RankingExpression body;
/**
- * <p>Constructs a new function</p>
+ * Constructs a new function
*
* @param name the name of this function
* @param arguments its argument names
@@ -43,28 +44,27 @@ public class ExpressionFunction {
public RankingExpression getBody() { return body; }
/**
- * <p>Create and return an instance of this function based on the given
- * arguments. If function calls are nested, this call might produce
- * additional scripts.</p>
+ * Creates and returns an instance of this function based on the given
+ * arguments. If function calls are nested, this call may produce
+ * additional functions.
*
* @param context the context used to expand this
- * @param arguments the arguments to instantiate on.
+ * @param argumentValues the arguments to instantiate on.
* @param path the expansion path leading to this.
* @return the script function instance created.
*/
- public Instance expand(SerializationContext context, List<ExpressionNode> arguments, Deque<String> path) {
+ public Instance expand(SerializationContext context, List<ExpressionNode> argumentValues, Deque<String> path) {
Map<String, String> argumentBindings = new HashMap<>();
- for (int i = 0; i < this.arguments.size() && i < arguments.size(); ++i) {
- argumentBindings.put(this.arguments.get(i), arguments.get(i).toString(context, path, null));
+ for (int i = 0; i < arguments.size() && i < arguments.size(); ++i) {
+ argumentBindings.put(arguments.get(i), argumentValues.get(i).toString(context, path, null));
}
- return new Instance(toSymbol(argumentBindings), body.getRoot().toString(context.createBinding(argumentBindings), path, null));
+ return new Instance(toSymbol(argumentBindings), body.getRoot().toString(context.withBindings(argumentBindings), path, null));
}
/**
* Returns a symbolic string that represents this function with a given
* list of arguments. The arguments are mangled by hashing the string
- * representation of the argument expressions, so we might need to revisit
- * this if we start seeing collisions.
+ * representation of the argument expressions.
*
* @param argumentBindings the bound arguments to include in the symbolic name.
* @return the symbolic name for an instance of this function
@@ -85,8 +85,8 @@ public class ExpressionFunction {
/**
- * <p>Returns a more unique hash code than what Java's own {@link
- * String#hashCode()} method would produce.</p>
+ * Returns a more unique hash code than what Java's own {@link
+ * String#hashCode()} method would produce.
*
* @param str The string to hash.
* @return A 64 bit long hash code.
@@ -136,4 +136,5 @@ public class ExpressionFunction {
}
}
+
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/FeatureList.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/FeatureList.java
index 49466f1974d..f0532d9d433 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/FeatureList.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/FeatureList.java
@@ -91,8 +91,8 @@ public class FeatureList implements Iterable<ReferenceNode> {
/**
* Returns the feature at the given index.
*
- * @param i The index of the feature to return.
- * @return The featuer at the given index.
+ * @param i the index of the feature to return.
+ * @return the feature at the given index.
*/
public ReferenceNode get(int i) {
return features.get(i);
@@ -137,4 +137,5 @@ public class FeatureList implements Iterable<ReferenceNode> {
public Iterator<ReferenceNode> iterator() {
return features.iterator();
}
+
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java
index c8d90e8c4e8..6b2422d7cb2 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java
@@ -244,10 +244,6 @@ public class RankingExpression implements Serializable {
* @return a list of named rank properties required to implement this expression.
*/
public Map<String, String> getRankProperties(List<ExpressionFunction> macros) {
- Map<String, ExpressionFunction> arg = new HashMap<>();
- for (ExpressionFunction function : macros) {
- arg.put(function.getName(), function);
- }
Deque<String> path = new LinkedList<>();
SerializationContext context = new SerializationContext(macros);
String serializedRoot = root.toString(context, path, null);
@@ -272,7 +268,7 @@ public class RankingExpression implements Serializable {
*
* @throws IllegalArgumentException if this expression is not type correct in this context
*/
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return root.type(context);
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java
new file mode 100644
index 00000000000..6277721e8f5
--- /dev/null
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java
@@ -0,0 +1,121 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.searchlib.rankingexpression;
+
+import com.yahoo.searchlib.rankingexpression.rule.Arguments;
+import com.yahoo.searchlib.rankingexpression.rule.CompositeNode;
+import com.yahoo.searchlib.rankingexpression.rule.ExpressionNode;
+import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode;
+import com.yahoo.searchlib.rankingexpression.rule.SerializationContext;
+import com.yahoo.tensor.evaluation.TypeContext;
+
+import java.util.Deque;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * A reference to a feature, function, or value in ranking expressions
+ *
+ * @author bratseth
+ */
+public class Reference extends TypeContext.Name {
+
+ private final String name;
+ private final Arguments arguments;
+
+ /**
+ * The output, or null if none
+ */
+ private final String output;
+
+ public Reference(String name, Arguments arguments, String output) {
+ super(name);
+ Objects.requireNonNull(name, "name cannot be null");
+ Objects.requireNonNull(arguments, "arguments cannot be null");
+ this.name = name;
+ this.arguments = arguments;
+ this.output = output;
+ }
+
+ public String name() { return name; }
+
+ public Arguments arguments() { return arguments; }
+
+ public String output() { return output; }
+
+ /**
+ * Creates a reference to a simple feature consisting of a name and a single argument
+ */
+ public static Reference simple(String name, String argumentValue) {
+ return new Reference(name,
+ new Arguments(new ReferenceNode(argumentValue)),
+ null);
+ }
+
+ /**
+ * Returns the given simple feature as a reference, or empty if it is not a valid simple
+ * feature string on the form name(argument).
+ */
+ public static Optional<Reference> simple(String feature) {
+ int startParenthesis = feature.indexOf('(');
+ if (startParenthesis < 0)
+ return Optional.empty();
+ int endParenthesis = feature.lastIndexOf(')');
+ String featureName = feature.substring(0, startParenthesis);
+ if (startParenthesis < 1 || endParenthesis < startParenthesis) return Optional.empty();
+ String argument = feature.substring(startParenthesis + 1, endParenthesis);
+ if (argument.startsWith("'") || argument.startsWith("\""))
+ argument = argument.substring(1);
+ if (argument.endsWith("'") || argument.endsWith("\""))
+ argument = argument.substring(0, argument.length() - 1);
+ return Optional.of(simple(featureName, argument));
+ }
+
+ /**
+ * Returns whether this is a simple identifier - no arguments or output
+ */
+ public boolean isIdentifier() {
+ return this.arguments.expressions().size() == 0 && output == null;
+ }
+
+ public Reference withArguments(Arguments arguments) {
+ return new Reference(name, arguments, output);
+ }
+
+ public Reference withOutput(String output) {
+ return new Reference(name, arguments, output);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Reference)) return false;
+ Reference other = (Reference) o;
+ if (!Objects.equals(other.name, this.name)) return false;
+ if (!Objects.equals(other.arguments, this.arguments)) return false;
+ if (!Objects.equals(other.output, this.output)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, arguments, output);
+ }
+
+ @Override
+ public String toString() {
+ return toString(new SerializationContext(), null, null);
+ }
+
+ public String toString(SerializationContext context, Deque<String> path, CompositeNode parent) {
+ StringBuilder b = new StringBuilder(name);
+ if (arguments != null && arguments.expressions().size() > 0)
+ b.append("(").append(arguments.expressions().stream()
+ .map(node -> node.toString(context, path, parent))
+ .collect(Collectors.joining(","))).append(")");
+ if (output != null)
+ b.append(".").append(output);
+ return b.toString();
+ }
+
+}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java
index 5f8daa69ecf..ee5952d9aea 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.evaluation;
import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.tensor.TensorType;
import java.util.Arrays;
@@ -82,8 +83,8 @@ public class ArrayContext extends AbstractArrayContext implements Cloneable {
}
@Override
- public TensorType getType(String name) {
- Integer index = nameToIndex().get(name);
+ public TensorType getType(Reference reference) {
+ Integer index = nameToIndex().get(reference.toString());
if (index == null) return null;
return values[index].type();
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Context.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Context.java
index 861f9565d66..4e046df11ca 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Context.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/Context.java
@@ -1,9 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.evaluation;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.rule.Arguments;
import com.yahoo.searchlib.rankingexpression.rule.ExpressionNode;
import com.yahoo.tensor.Tensor;
+import com.yahoo.tensor.TensorType;
import com.yahoo.tensor.evaluation.EvaluationContext;
import java.util.Set;
@@ -14,7 +16,7 @@ import java.util.stream.Collectors;
*
* @author bratseth
*/
-public abstract class Context implements EvaluationContext {
+public abstract class Context implements EvaluationContext<Reference> {
/**
* Returns the value of a simple variable name.
@@ -24,6 +26,11 @@ public abstract class Context implements EvaluationContext {
*/
public abstract Value get(String name);
+ @Override
+ public TensorType getType(String reference) {
+ throw new UnsupportedOperationException("Not able to parse gereral references from string form");
+ }
+
/** Returns a variable as a tensor */
@Override
public Tensor getTensor(String name) { return get(name).asTensor(); }
@@ -46,6 +53,7 @@ public abstract class Context implements EvaluationContext {
* calculation to output several), or null to output the
* "main" (or only) value.
*/
+ // TODO: Remove/change to use reference?
public Value get(String name, Arguments arguments, String output) {
if (arguments != null && arguments.expressions().size() > 0)
name = name + "(" + arguments.expressions().stream().map(ExpressionNode::toString).collect(Collectors.joining(",")) + ")";
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/DoubleOnlyArrayContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/DoubleOnlyArrayContext.java
index 0625e8506cc..0004036da4b 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/DoubleOnlyArrayContext.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/DoubleOnlyArrayContext.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.evaluation;
import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.tensor.TensorType;
/**
@@ -68,7 +69,9 @@ public class DoubleOnlyArrayContext extends AbstractArrayContext {
}
@Override
- public TensorType getType(String name) { return TensorType.empty; }
+ public TensorType getType(Reference reference) {
+ return TensorType.empty; // Double only
+ }
/** Perform a slow lookup by name */
@Override
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapContext.java
index a81d0c89f8f..4ef24d60bba 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapContext.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapContext.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.evaluation;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.tensor.TensorType;
import java.util.Collections;
@@ -15,7 +16,7 @@ import java.util.Set;
*/
public class MapContext extends Context {
- private Map<String, Value> bindings = new HashMap<>();
+ private Map<String, Value> bindings = new HashMap<>(); // TODO: Change String to Reference
private boolean frozen = false;
@@ -42,8 +43,8 @@ public class MapContext extends Context {
/** Returns the type of the given value key, or null if it is not bound. */
@Override
- public TensorType getType(String key) {
- Value value = bindings.get(key);
+ public TensorType getType(Reference key) {
+ Value value = bindings.get(key.toString());
if (value == null) return null;
return value.type();
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java
new file mode 100644
index 00000000000..2a42e2d92f7
--- /dev/null
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java
@@ -0,0 +1,38 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.searchlib.rankingexpression.evaluation;// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.yahoo.searchlib.rankingexpression.Reference;
+import com.yahoo.tensor.TensorType;
+import com.yahoo.tensor.evaluation.TypeContext;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A context which only contains type information.
+ *
+ * @author bratseth
+ */
+public class MapTypeContext implements TypeContext<Reference> {
+
+ private final Map<Reference, TensorType> featureTypes = new HashMap<>();
+
+ public void setType(Reference reference, TensorType type) {
+ featureTypes.put(reference, type);
+ }
+
+ @Override
+ public TensorType getType(String reference) {
+ throw new UnsupportedOperationException("Not able to parse gereral references from string form");
+ }
+
+ @Override
+ public TensorType getType(Reference reference) {
+ return featureTypes.get(reference);
+ }
+
+ /** Returns an unmodifiable map of the bindings in this */
+ public Map<Reference, TensorType> bindings() { return Collections.unmodifiableMap(featureTypes); }
+
+}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java
deleted file mode 100644
index ff2088263d8..00000000000
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.searchlib.rankingexpression.evaluation;// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-import com.yahoo.tensor.TensorType;
-import com.yahoo.tensor.evaluation.TypeContext;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A context which only contains type information.
- *
- * @author bratseth
- */
-public class TypeMapContext implements TypeContext {
-
- private final Map<String, TensorType> featureTypes = new HashMap<>();
-
- public void setType(String name, TensorType type) {
- featureTypes.put(name, type);
- }
-
- @Override
- public TensorType getType(String name) {
- return featureTypes.get(name);
- }
-
- /** Returns an unmodifiable map of the bindings in this */
- public Map<String, TensorType> bindings() { return Collections.unmodifiableMap(featureTypes); }
-
-}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTForestNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTForestNode.java
index 8ee4cdbf297..649c70122f1 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTForestNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTForestNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.evaluation.gbdtoptimization;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.DoubleValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -26,7 +27,7 @@ public class GBDTForestNode extends ExpressionNode {
}
@Override
- public final TensorType type(TypeContext context) { return TensorType.empty; }
+ public final TensorType type(TypeContext<Reference> context) { return TensorType.empty; }
@Override
public final Value evaluate(Context context) {
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTNode.java
index aac635b2545..53a286f09f6 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/gbdtoptimization/GBDTNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.evaluation.gbdtoptimization;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.DoubleValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -51,7 +52,7 @@ public final class GBDTNode extends ExpressionNode {
public final double[] values() { return values; }
@Override
- public final TensorType type(TypeContext context) { return TensorType.empty; }
+ public final TensorType type(TypeContext<Reference> context) { return TensorType.empty; }
@Override
public final Value evaluate(Context context) {
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Arguments.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Arguments.java
index fb9a7cb9ad7..d3a12d0f312 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Arguments.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/Arguments.java
@@ -13,7 +13,7 @@ import java.util.List;
/**
* A set of argument expressions to a function or feature.
- * This is immutable.
+ * This is a value object.
*
* @author bratseth
*/
@@ -22,7 +22,11 @@ public final class Arguments implements Serializable {
private final ImmutableList<ExpressionNode> expressions;
public Arguments() {
- this(null);
+ this(ImmutableList.of());
+ }
+
+ public Arguments(ExpressionNode singleArgument) {
+ this(ImmutableList.of(singleArgument));
}
public Arguments(List<? extends ExpressionNode> expressions) {
@@ -38,9 +42,12 @@ public final class Arguments implements Serializable {
this.expressions = b.build();
}
- /** Returns an unmodifiable list of the expressions in this */
+ /** Returns an unmodifiable list of the expressions in this, never null */
public List<ExpressionNode> expressions() { return expressions; }
+ /** Returns the number of arguments in this */
+ public int size() { return expressions.size(); }
+
/** Evaluate all arguments in this */
public Value[] evaluate(Context context) {
Value[] values=new Value[expressions.size()];
@@ -62,8 +69,9 @@ public final class Arguments implements Serializable {
}
@Override
- public boolean equals(Object rhs) {
- return rhs instanceof Arguments && expressions.equals(((Arguments)rhs).expressions);
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ return other instanceof Arguments && expressions.equals(((Arguments)other).expressions);
}
@Override
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java
index fc6428a4c33..49c49bed9bd 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ArithmeticNode.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.rule;
import com.google.common.collect.ImmutableList;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -80,7 +81,7 @@ public final class ArithmeticNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
// Compute type using tensor types as arithmetic operators are supported on tensors
// and is correct also in the special case of doubles.
// As all our functions are type-commutative, we don't need to take operator precedence into account
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/BooleanNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/BooleanNode.java
index 1d7d9b1ecda..cd4ddbcae55 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/BooleanNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/BooleanNode.java
@@ -5,7 +5,6 @@ package com.yahoo.searchlib.rankingexpression.rule;
* A node which produces a boolean value when evaluated.
*
* @author bratseth
- * @since 5.1.21
*/
public abstract class BooleanNode extends CompositeNode {
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java
index 7601c0e6180..eb328486045 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ComparisonNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -49,7 +50,7 @@ public class ComparisonNode extends BooleanNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return TensorType.empty; // by definition
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ConstantNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ConstantNode.java
index 1ea8d03f0eb..3ddd7223349 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ConstantNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ConstantNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -49,7 +50,7 @@ public final class ConstantNode extends ExpressionNode {
}
@Override
- public TensorType type(TypeContext context) { return value.type(); }
+ public TensorType type(TypeContext<Reference> context) { return value.type(); }
@Override
public Value evaluate(Context context) {
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/EmbracedNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/EmbracedNode.java
index fd9fab99db8..47c2897e4a4 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/EmbracedNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/EmbracedNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -50,7 +51,7 @@ public final class EmbracedNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return value.type(context);
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ExpressionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ExpressionNode.java
index 477f4db4981..6bb163590de 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ExpressionNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ExpressionNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -48,7 +49,7 @@ public abstract class ExpressionNode implements Serializable {
* @param context the variable type bindings to use for this evaluation
* @throws IllegalArgumentException if there are variables which are not bound in the given map
*/
- public abstract TensorType type(TypeContext context);
+ public abstract TensorType type(TypeContext<Reference> context);
/**
* Returns the value of evaluating this expression over the given context.
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionNode.java
index 79515229019..1da2210a39c 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.DoubleValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -67,7 +68,7 @@ public final class FunctionNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
if (arguments.expressions().size() == 0)
return TensorType.empty;
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java
new file mode 100644
index 00000000000..ed1e2838717
--- /dev/null
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java
@@ -0,0 +1,74 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.searchlib.rankingexpression.rule;
+
+import com.google.common.collect.ImmutableMap;
+import com.yahoo.searchlib.rankingexpression.ExpressionFunction;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The context of a function invocation.
+ *
+ * @author bratseth
+ */
+public class FunctionReferenceContext {
+
+ /** Expression functions indexed by name */
+ private final ImmutableMap<String, ExpressionFunction> functions;
+
+ /** Mapping from argument names to the expressions they resolve to */
+ // TODO: Make private
+ public final Map<String, String> bindings = new HashMap<>();
+
+ /** Create a context for a single serialization task */
+ public FunctionReferenceContext() {
+ this(Collections.emptyList());
+ }
+
+ /** Create a context for a single serialization task */
+ public FunctionReferenceContext(Collection<ExpressionFunction> functions) {
+ this(toMap(functions), Collections.emptyMap());
+ }
+
+ public FunctionReferenceContext(Collection<ExpressionFunction> functions, Map<String, String> bindings) {
+ this(toMap(functions), bindings);
+ }
+
+ /** Create a context for a single serialization task */
+ public FunctionReferenceContext(Map<String, ExpressionFunction> functions) {
+ this(functions.values());
+ }
+
+ /** Create a context for a single serialization task */
+ public FunctionReferenceContext(Map<String, ExpressionFunction> functions, Map<String, String> bindings) {
+ this.functions = ImmutableMap.copyOf(functions);
+ if (bindings != null)
+ this.bindings.putAll(bindings);
+ }
+
+ private static ImmutableMap<String, ExpressionFunction> toMap(Collection<ExpressionFunction> list) {
+ ImmutableMap.Builder<String,ExpressionFunction> mapBuilder = new ImmutableMap.Builder<>();
+ for (ExpressionFunction function : list)
+ mapBuilder.put(function.getName(), function);
+ return mapBuilder.build();
+ }
+
+ /**
+ * Returns a function or null if it isn't defined in this context
+ */
+ public ExpressionFunction getFunction(String name) { return functions.get(name); }
+
+ protected Map<String, ExpressionFunction> functions() { return functions; }
+
+ /** Returns the resolution of an argument, or null if it isn't defined in this context */
+ public String getBinding(String name) { return bindings.get(name); }
+
+ /** Returns a new context with the bindings replaced by the given bindings */
+ public FunctionReferenceContext withBindings(Map<String, String> bindings) {
+ return new FunctionReferenceContext(this.functions, bindings);
+ }
+
+}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/GeneratorLambdaFunctionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/GeneratorLambdaFunctionNode.java
index e42884ecc05..c87eb0ace39 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/GeneratorLambdaFunctionNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/GeneratorLambdaFunctionNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.MapContext;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -48,7 +49,7 @@ public class GeneratorLambdaFunctionNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) { return type; }
+ public TensorType type(TypeContext<Reference> context) { return type; }
/** Evaluate this in a context which must have the arguments bound */
@Override
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/IfNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/IfNode.java
index 66b250736e8..ee4edac4941 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/IfNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/IfNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -75,7 +76,7 @@ public final class IfNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
TensorType trueType = trueExpression.type(context);
TensorType falseType = falseExpression.type(context);
return trueType.dimensionwiseGeneralizationWith(falseType).orElseThrow(() ->
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java
index da946228291..61086f8182a 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/LambdaFunctionNode.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.rule;
import com.google.common.collect.ImmutableList;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.MapContext;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -57,7 +58,7 @@ public class LambdaFunctionNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return TensorType.empty; // by definition - no nested lambdas
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NameNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NameNode.java
index f55ed59b65c..f1adf331630 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NameNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NameNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -14,6 +15,7 @@ import java.util.Deque;
*
* @author Simon Thoresen
*/
+// TODO: This is achieved by ReferenceNode in almost all cases - remove this
public final class NameNode extends ExpressionNode {
private final String name;
@@ -32,7 +34,7 @@ public final class NameNode extends ExpressionNode {
}
@Override
- public TensorType type(TypeContext context) { throw new RuntimeException("Named nodes can not have a type"); }
+ public TensorType type(TypeContext<Reference> context) { throw new RuntimeException("Named nodes can not have a type"); }
@Override
public Value evaluate(Context context) {
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NegativeNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NegativeNode.java
index 9cbe5f98c72..fcc03dc4862 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NegativeNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NegativeNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -38,7 +39,7 @@ public class NegativeNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return value.type(context);
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NotNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NotNode.java
index e7041600635..a539f496ff5 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NotNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/NotNode.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.rule;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -38,7 +39,7 @@ public class NotNode extends BooleanNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return value.type(context);
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
index 05a6773c5cb..78f53b1593d 100755
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java
@@ -3,6 +3,7 @@ package com.yahoo.searchlib.rankingexpression.rule;
import com.yahoo.searchlib.rankingexpression.ExpressionFunction;
import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
import com.yahoo.tensor.TensorType;
@@ -13,114 +14,102 @@ import java.util.Deque;
import java.util.List;
/**
- * A node referring either to a value in the context or to another named ranking expression.
+ * A node referring either to a value in the context or to a named ranking expression (function aka macro).
*
* @author simon
* @author bratseth
*/
public final class ReferenceNode extends CompositeNode {
- private final String name, output;
-
- private final Arguments arguments;
+ private final Reference reference;
+ /* Creates a node with a simple identifier reference */
public ReferenceNode(String name) {
this(name, null, null);
}
public ReferenceNode(String name, List<? extends ExpressionNode> arguments, String output) {
- this.name = name;
- this.arguments = arguments != null ? new Arguments(arguments) : new Arguments();
- this.output = output;
+ this.reference = new Reference(name,
+ arguments != null ? new Arguments(arguments) : new Arguments(),
+ output);
+ }
+
+ public ReferenceNode(Reference reference) {
+ this.reference = reference;
}
public String getName() {
- return name;
+ return reference.name();
}
/** Returns the arguments, never null */
- public Arguments getArguments() { return arguments; }
+ public Arguments getArguments() { return reference.arguments(); }
/** Returns a copy of this where the arguments are replaced by the given arguments */
public ReferenceNode setArguments(List<ExpressionNode> arguments) {
- return new ReferenceNode(name, arguments, output);
+ return new ReferenceNode(reference.withArguments(new Arguments(arguments)));
}
/** Returns the specific output this references, or null if none specified */
- public String getOutput() { return output; }
+ public String getOutput() { return reference.output(); }
/** Returns a copy of this node with a modified output */
public ReferenceNode setOutput(String output) {
- return new ReferenceNode(name, arguments.expressions(), output);
+ return new ReferenceNode(reference.withOutput(output));
}
/** Returns an empty list as this has no children */
@Override
- public List<ExpressionNode> children() { return arguments.expressions(); }
+ public List<ExpressionNode> children() { return reference.arguments().expressions(); }
@Override
public String toString(SerializationContext context, Deque<String> path, CompositeNode parent) {
- if (path == null)
- path = new ArrayDeque<>();
- String myName = this.name;
- String myOutput = this.output;
- List<ExpressionNode> myArguments = this.arguments.expressions();
-
- String resolvedArgument = context.getBinding(myName);
- if (resolvedArgument != null && this.arguments.expressions().size() == 0 && myOutput == null) {
- // Replace this whole node with the value of the argument value that it maps to
- myName = resolvedArgument;
- myArguments = null;
- myOutput = null;
- } else if (context.getFunction(myName) != null) {
- // Replace by the referenced expression
- ExpressionFunction function = context.getFunction(myName);
- if (function != null && myArguments != null && function.arguments().size() == myArguments.size() && myOutput == null) {
- String myPath = name + this.arguments.expressions();
- if (path.contains(myPath)) {
- throw new IllegalStateException("Cycle in ranking expression function: " + path);
- }
- path.addLast(myPath);
- ExpressionFunction.Instance instance = function.expand(context, myArguments, path);
- path.removeLast();
- context.addFunctionSerialization(RankingExpression.propertyName(instance.getName()), instance.getExpressionString());
- myName = "rankingExpression(" + instance.getName() + ")";
- myArguments = null;
- myOutput = null;
- }
+ if (reference.isIdentifier() && context.getBinding(getName()) != null) {
+ // a bound identifier: replace by the value it is bound to
+ return context.getBinding(getName());
}
- // Always print the same way, the magic is already done.
- StringBuilder ret = new StringBuilder(myName);
- if (myArguments != null && myArguments.size() > 0) {
- ret.append("(");
- for (int i = 0; i < myArguments.size(); ++i) {
- ret.append(myArguments.get(i).toString(context, path, this));
- if (i < myArguments.size() - 1) {
- ret.append(",");
- }
- }
- ret.append(")");
+
+ ExpressionFunction function = context.getFunction(getName());
+ if (function != null && function.arguments().size() == getArguments().size() && getOutput() == null) {
+ // a function reference: replace by the referenced function wrapped in rankingExpression
+ if (path == null)
+ path = new ArrayDeque<>();
+ String myPath = getName() + getArguments().expressions();
+ if (path.contains(myPath))
+ throw new IllegalStateException("Cycle in ranking expression function: " + path);
+ path.addLast(myPath);
+ ExpressionFunction.Instance instance = function.expand(context, getArguments().expressions(), path);
+ path.removeLast();
+ context.addFunctionSerialization(RankingExpression.propertyName(instance.getName()), instance.getExpressionString());
+ return "rankingExpression(" + instance.getName() + ")";
}
- ret.append(myOutput != null ? "." + myOutput : "");
- return ret.toString();
+
+ // not resolved in this context: output as-is
+ return reference.toString(context, path, parent);
}
+ /** Returns the reference of this node */
+ public Reference reference() { return reference; }
+
@Override
- public TensorType type(TypeContext context) {
- // Don't support outputs of different type, for simplicity
- return context.getType(toString());
+ public TensorType type(TypeContext<Reference> context) {
+ TensorType type = context.getType(reference);
+ if (type == null)
+ throw new IllegalArgumentException("Unknown feature '" + toString() + "'");
+ return type;
}
@Override
public Value evaluate(Context context) {
- if (arguments.expressions().isEmpty() && output == null)
- return context.get(name);
- return context.get(name, arguments, output);
+ // TODO: Context should accept a Reference instead.
+ if (reference.isIdentifier())
+ return context.get(reference.name());
+ return context.get(getName(), getArguments(), getOutput());
}
@Override
public CompositeNode setChildren(List<ExpressionNode> newChildren) {
- return new ReferenceNode(name, newChildren, output);
+ return setArguments(newChildren);
}
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java
index ba765d07094..796c13a8669 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SerializationContext.java
@@ -16,17 +16,11 @@ import java.util.Map;
*
* @author bratseth
*/
-public class SerializationContext {
+public class SerializationContext extends FunctionReferenceContext {
- /** Expression functions indexed by name */
- private final ImmutableMap<String, ExpressionFunction> functions;
-
- /** A cache of already serialized expressions indexed by name */
+ /** Serialized form of functions indexed by name */
private final Map<String, String> serializedFunctions;
- /** Mapping from argument names to the expressions they resolve to */
- public final Map<String, String> bindings = new HashMap<>();
-
/** Create a context for a single serialization task */
public SerializationContext() {
this(Collections.emptyList());
@@ -77,17 +71,10 @@ public class SerializationContext {
*/
public SerializationContext(ImmutableMap<String,ExpressionFunction> functions, Map<String, String> bindings,
Map<String, String> serializedFunctions) {
- this.functions = functions;
+ super(functions, bindings);
this.serializedFunctions = serializedFunctions;
- if (bindings != null)
- this.bindings.putAll(bindings);
}
- /**
- * Returns a function or null if it isn't defined in this context
- */
- public ExpressionFunction getFunction(String name) { return functions.get(name); }
-
/** Adds the serialization of a function */
public void addFunctionSerialization(String name, String expressionString) {
serializedFunctions.put(name, expressionString);
@@ -98,17 +85,9 @@ public class SerializationContext {
return serializedFunctions.get(name);
}
- /**
- * Returns the resolution of an argument, or null if it isn't defined in this context
- */
- public String getBinding(String name) { return bindings.get(name); }
-
- /**
- * Returns a new context which shares the functions and serialized function map with this but has different
- * arguments.
- */
- public SerializationContext createBinding(Map<String, String> arguments) {
- return new SerializationContext(this.functions, arguments, this.serializedFunctions);
+ @Override
+ public SerializationContext withBindings(Map<String, String> bindings) {
+ return new SerializationContext(functions().values(), bindings, this.serializedFunctions);
}
public Map<String, String> serializedFunctions() { return serializedFunctions; }
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SetMembershipNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SetMembershipNode.java
index a7b82f4753f..cb31219579a 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SetMembershipNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/SetMembershipNode.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.rule;
import com.google.common.collect.ImmutableList;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.BooleanValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.TensorValue;
@@ -60,7 +61,7 @@ public class SetMembershipNode extends BooleanNode {
}
@Override
- public TensorType type(TypeContext context) {
+ public TensorType type(TypeContext<Reference> context) {
return TensorType.empty;
}
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TensorFunctionNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TensorFunctionNode.java
index ec6af4bb413..6c9b6bb4a98 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TensorFunctionNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/TensorFunctionNode.java
@@ -2,6 +2,7 @@
package com.yahoo.searchlib.rankingexpression.rule;
import com.google.common.annotations.Beta;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.evaluation.Context;
import com.yahoo.searchlib.rankingexpression.evaluation.TensorValue;
import com.yahoo.searchlib.rankingexpression.evaluation.Value;
@@ -64,7 +65,7 @@ public class TensorFunctionNode extends CompositeNode {
}
@Override
- public TensorType type(TypeContext context) { return function.type(context); }
+ public TensorType type(TypeContext<Reference> context) { return function.type(context); }
@Override
public Value evaluate(Context context) {
@@ -111,12 +112,13 @@ public class TensorFunctionNode extends CompositeNode {
public PrimitiveTensorFunction toPrimitive() { return this; }
@Override
- public TensorType type(TypeContext context) {
- return expression.type(context);
+ @SuppressWarnings("unchecked") // Generics awkwardness
+ public <NAMETYPE extends TypeContext.Name> TensorType type(TypeContext<NAMETYPE> context) {
+ return expression.type((TypeContext<Reference>)context);
}
@Override
- public Tensor evaluate(EvaluationContext context) {
+ public <NAMETYPE extends TypeContext.Name> Tensor evaluate(EvaluationContext<NAMETYPE> context) {
return expression.evaluate((Context)context).asTensor();
}
diff --git a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/EvaluationTestCase.java b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/EvaluationTestCase.java
index e9030cf5852..f2122bb5da9 100644
--- a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/EvaluationTestCase.java
+++ b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/EvaluationTestCase.java
@@ -378,8 +378,13 @@ public class EvaluationTestCase {
private static class StructuredTestContext extends MapContext {
@Override
+ public Value get(String feature) {
+ throw new RuntimeException("Called simple get for feature " + feature);
+ }
+
+ @Override
public Value get(String name, Arguments arguments, String output) {
- if (!name.equals("average")) {
+ if ( ! name.equals("average")) {
throw new IllegalArgumentException("Unknown operation '" + name + "'");
}
if (arguments.expressions().size() != 2) {
diff --git a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeResolutionTestCase.java b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeResolutionTestCase.java
index c882c887c8d..a08d510eec4 100644
--- a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeResolutionTestCase.java
+++ b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeResolutionTestCase.java
@@ -3,6 +3,7 @@
package com.yahoo.searchlib.rankingexpression.evaluation;
import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.searchlib.rankingexpression.parser.ParseException;
import com.yahoo.tensor.TensorType;
import com.yahoo.tensor.evaluation.TypeContext;
@@ -18,12 +19,17 @@ public class TypeResolutionTestCase {
@Test
public void testTypeResolution() {
- TypeMapContext context = new TypeMapContext();
- context.setType("query(x1)", TensorType.fromSpec("tensor(x[])"));
- context.setType("query(x2)", TensorType.fromSpec("tensor(x[10])"));
- context.setType("query(y1)", TensorType.fromSpec("tensor(y[])"));
- context.setType("query(xy1)", TensorType.fromSpec("tensor(x[10],y[])"));
- context.setType("query(xy2)", TensorType.fromSpec("tensor(x[],y[10])"));
+ MapTypeContext context = new MapTypeContext();
+ context.setType(Reference.simple("query", "x1"),
+ TensorType.fromSpec("tensor(x[])"));
+ context.setType(Reference.simple("query", "x2"),
+ TensorType.fromSpec("tensor(x[10])"));
+ context.setType(Reference.simple("query", "y1"),
+ TensorType.fromSpec("tensor(y[])"));
+ context.setType(Reference.simple("query", "xy1"),
+ TensorType.fromSpec("tensor(x[10],y[])"));
+ context.setType(Reference.simple("query", "xy2"),
+ TensorType.fromSpec("tensor(x[],y[10])"));
assertType("tensor(x[])", "query(x1)", context);
assertType("tensor(x[])", "if (1>0, query(x1), query(x2))", context);
@@ -31,7 +37,7 @@ public class TypeResolutionTestCase {
assertIncompatibleType("if (1>0, query(x1), query(y1))", context);
}
- private void assertType(String type, String expression, TypeContext context) {
+ private void assertType(String type, String expression, TypeContext<Reference> context) {
try {
assertEquals(TensorType.fromSpec(type), new RankingExpression(expression).type(context));
}
@@ -40,7 +46,7 @@ public class TypeResolutionTestCase {
}
}
- private void assertIncompatibleType(String expression, TypeContext context) {
+ private void assertIncompatibleType(String expression, TypeContext<Reference> context) {
try {
new RankingExpression(expression).type(context);
fail("Expected type incompatibility exception");
diff --git a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/rule/ArgumentsTestCase.java b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/rule/ArgumentsTestCase.java
index 867331e99ce..303135888d8 100644
--- a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/rule/ArgumentsTestCase.java
+++ b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/rule/ArgumentsTestCase.java
@@ -9,13 +9,13 @@ import java.util.Collections;
import static org.junit.Assert.*;
/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ * @author Simon Thoresen
*/
public class ArgumentsTestCase {
@Test
public void requireThatAccessorsWork() {
- Arguments args = new Arguments(null);
+ Arguments args = new Arguments();
assertTrue(args.expressions().isEmpty());
args = new Arguments(Collections.<ExpressionNode>emptyList());