From 3f66466af5e58bc37c46b533dfd087c45b210d9b Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Tue, 20 Feb 2018 18:59:45 +0100 Subject: Revert "Bratseth/typecheck all 2" --- .../rankingexpression/ExpressionFunction.java | 31 +++--- .../searchlib/rankingexpression/FeatureList.java | 5 +- .../rankingexpression/RankingExpression.java | 6 +- .../searchlib/rankingexpression/Reference.java | 121 --------------------- .../rankingexpression/evaluation/ArrayContext.java | 5 +- .../rankingexpression/evaluation/Context.java | 10 +- .../evaluation/DoubleOnlyArrayContext.java | 5 +- .../rankingexpression/evaluation/MapContext.java | 7 +- .../evaluation/MapTypeContext.java | 38 ------- .../evaluation/TypeMapContext.java | 32 ++++++ .../gbdtoptimization/GBDTForestNode.java | 3 +- .../evaluation/gbdtoptimization/GBDTNode.java | 3 +- .../rankingexpression/rule/Arguments.java | 18 +-- .../rankingexpression/rule/ArithmeticNode.java | 3 +- .../rankingexpression/rule/BooleanNode.java | 1 + .../rankingexpression/rule/ComparisonNode.java | 3 +- .../rankingexpression/rule/ConstantNode.java | 3 +- .../rankingexpression/rule/EmbracedNode.java | 3 +- .../rankingexpression/rule/ExpressionNode.java | 3 +- .../rankingexpression/rule/FunctionNode.java | 3 +- .../rule/FunctionReferenceContext.java | 74 ------------- .../rule/GeneratorLambdaFunctionNode.java | 3 +- .../searchlib/rankingexpression/rule/IfNode.java | 3 +- .../rankingexpression/rule/LambdaFunctionNode.java | 3 +- .../searchlib/rankingexpression/rule/NameNode.java | 4 +- .../rankingexpression/rule/NegativeNode.java | 3 +- .../searchlib/rankingexpression/rule/NotNode.java | 3 +- .../rankingexpression/rule/ReferenceNode.java | 111 ++++++++++--------- .../rule/SerializationContext.java | 33 +++++- .../rankingexpression/rule/SetMembershipNode.java | 3 +- .../rankingexpression/rule/TensorFunctionNode.java | 10 +- .../evaluation/EvaluationTestCase.java | 7 +- .../evaluation/TypeResolutionTestCase.java | 22 ++-- .../rankingexpression/rule/ArgumentsTestCase.java | 4 +- 34 files changed, 185 insertions(+), 401 deletions(-) delete mode 100644 searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java delete mode 100644 searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java create mode 100644 searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java delete mode 100644 searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java (limited to 'searchlib') 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 262aba89f27..2e2858da238 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/ExpressionFunction.java @@ -3,7 +3,6 @@ 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; @@ -12,9 +11,9 @@ import java.security.NoSuchAlgorithmException; import java.util.*; /** - * A function defined by a ranking expression + *

A function defined by a ranking expression

* - * @author Simon Thoresen + * @author Simon Thoresen * @author bratseth */ public class ExpressionFunction { @@ -24,7 +23,7 @@ public class ExpressionFunction { private final RankingExpression body; /** - * Constructs a new function + *

Constructs a new function

* * @param name the name of this function * @param arguments its argument names @@ -44,27 +43,28 @@ public class ExpressionFunction { public RankingExpression getBody() { return body; } /** - * Creates and returns an instance of this function based on the given - * arguments. If function calls are nested, this call may produce - * additional functions. + *

Create and return an instance of this function based on the given + * arguments. If function calls are nested, this call might produce + * additional scripts.

* * @param context the context used to expand this - * @param argumentValues the arguments to instantiate on. + * @param arguments 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 argumentValues, Deque path) { + public Instance expand(SerializationContext context, List arguments, Deque path) { Map argumentBindings = new HashMap<>(); - for (int i = 0; i < arguments.size() && i < arguments.size(); ++i) { - argumentBindings.put(arguments.get(i), argumentValues.get(i).toString(context, path, null)); + 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)); } - return new Instance(toSymbol(argumentBindings), body.getRoot().toString(context.withBindings(argumentBindings), path, null)); + return new Instance(toSymbol(argumentBindings), body.getRoot().toString(context.createBinding(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. + * representation of the argument expressions, so we might need to revisit + * this if we start seeing collisions. * * @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 { /** - * Returns a more unique hash code than what Java's own {@link - * String#hashCode()} method would produce. + *

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,5 +136,4 @@ 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 f0532d9d433..49466f1974d 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 { /** * Returns the feature at the given index. * - * @param i the index of the feature to return. - * @return the feature at the given index. + * @param i The index of the feature to return. + * @return The featuer at the given index. */ public ReferenceNode get(int i) { return features.get(i); @@ -137,5 +137,4 @@ public class FeatureList implements Iterable { public Iterator 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 6b2422d7cb2..c8d90e8c4e8 100755 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/RankingExpression.java @@ -244,6 +244,10 @@ public class RankingExpression implements Serializable { * @return a list of named rank properties required to implement this expression. */ public Map getRankProperties(List macros) { + Map arg = new HashMap<>(); + for (ExpressionFunction function : macros) { + arg.put(function.getName(), function); + } Deque path = new LinkedList<>(); SerializationContext context = new SerializationContext(macros); String serializedRoot = root.toString(context, path, null); @@ -268,7 +272,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 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 deleted file mode 100644 index 6277721e8f5..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/Reference.java +++ /dev/null @@ -1,121 +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; - -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 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 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 ee5952d9aea..5f8daa69ecf 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,7 +2,6 @@ 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; @@ -83,8 +82,8 @@ public class ArrayContext extends AbstractArrayContext implements Cloneable { } @Override - public TensorType getType(Reference reference) { - Integer index = nameToIndex().get(reference.toString()); + public TensorType getType(String name) { + Integer index = nameToIndex().get(name); 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 4e046df11ca..861f9565d66 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,11 +1,9 @@ // 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; @@ -16,7 +14,7 @@ import java.util.stream.Collectors; * * @author bratseth */ -public abstract class Context implements EvaluationContext { +public abstract class Context implements EvaluationContext { /** * Returns the value of a simple variable name. @@ -26,11 +24,6 @@ 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(); } @@ -53,7 +46,6 @@ 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 0004036da4b..0625e8506cc 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,7 +2,6 @@ package com.yahoo.searchlib.rankingexpression.evaluation; import com.yahoo.searchlib.rankingexpression.RankingExpression; -import com.yahoo.searchlib.rankingexpression.Reference; import com.yahoo.tensor.TensorType; /** @@ -69,9 +68,7 @@ public class DoubleOnlyArrayContext extends AbstractArrayContext { } @Override - public TensorType getType(Reference reference) { - return TensorType.empty; // Double only - } + public TensorType getType(String name) { return TensorType.empty; } /** 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 4ef24d60bba..a81d0c89f8f 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,7 +1,6 @@ // 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; @@ -16,7 +15,7 @@ import java.util.Set; */ public class MapContext extends Context { - private Map bindings = new HashMap<>(); // TODO: Change String to Reference + private Map bindings = new HashMap<>(); private boolean frozen = false; @@ -43,8 +42,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(Reference key) { - Value value = bindings.get(key.toString()); + public TensorType getType(String key) { + Value value = bindings.get(key); 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 deleted file mode 100644 index 2a42e2d92f7..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java +++ /dev/null @@ -1,38 +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.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 { - - private final Map 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 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 new file mode 100644 index 00000000000..ff2088263d8 --- /dev/null +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/TypeMapContext.java @@ -0,0 +1,32 @@ +// 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 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 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 649c70122f1..8ee4cdbf297 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,7 +1,6 @@ // 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; @@ -27,7 +26,7 @@ public class GBDTForestNode extends ExpressionNode { } @Override - public final TensorType type(TypeContext context) { return TensorType.empty; } + public final TensorType type(TypeContext 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 53a286f09f6..aac635b2545 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,7 +1,6 @@ // 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; @@ -52,7 +51,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 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 d3a12d0f312..fb9a7cb9ad7 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 a value object. + * This is immutable. * * @author bratseth */ @@ -22,11 +22,7 @@ public final class Arguments implements Serializable { private final ImmutableList expressions; public Arguments() { - this(ImmutableList.of()); - } - - public Arguments(ExpressionNode singleArgument) { - this(ImmutableList.of(singleArgument)); + this(null); } public Arguments(List expressions) { @@ -42,12 +38,9 @@ public final class Arguments implements Serializable { this.expressions = b.build(); } - /** Returns an unmodifiable list of the expressions in this, never null */ + /** Returns an unmodifiable list of the expressions in this */ public List 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()]; @@ -69,9 +62,8 @@ public final class Arguments implements Serializable { } @Override - public boolean equals(Object other) { - if (other == this) return true; - return other instanceof Arguments && expressions.equals(((Arguments)other).expressions); + public boolean equals(Object rhs) { + return rhs instanceof Arguments && expressions.equals(((Arguments)rhs).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 49c49bed9bd..fc6428a4c33 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,7 +2,6 @@ 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; @@ -81,7 +80,7 @@ public final class ArithmeticNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 cd4ddbcae55..1d7d9b1ecda 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,6 +5,7 @@ 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 eb328486045..7601c0e6180 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,7 +1,6 @@ // 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 +49,7 @@ public class ComparisonNode extends BooleanNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 3ddd7223349..1ea8d03f0eb 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,7 +1,6 @@ // 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 +49,7 @@ public final class ConstantNode extends ExpressionNode { } @Override - public TensorType type(TypeContext context) { return value.type(); } + public TensorType type(TypeContext 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 47c2897e4a4..fd9fab99db8 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,7 +1,6 @@ // 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; @@ -51,7 +50,7 @@ public final class EmbracedNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 6bb163590de..477f4db4981 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,7 +1,6 @@ // 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 +48,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 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 1da2210a39c..79515229019 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,7 +1,6 @@ // 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; @@ -68,7 +67,7 @@ public final class FunctionNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 deleted file mode 100644 index ed1e2838717..00000000000 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/FunctionReferenceContext.java +++ /dev/null @@ -1,74 +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.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 functions; - - /** Mapping from argument names to the expressions they resolve to */ - // TODO: Make private - public final Map 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 functions) { - this(toMap(functions), Collections.emptyMap()); - } - - public FunctionReferenceContext(Collection functions, Map bindings) { - this(toMap(functions), bindings); - } - - /** Create a context for a single serialization task */ - public FunctionReferenceContext(Map functions) { - this(functions.values()); - } - - /** Create a context for a single serialization task */ - public FunctionReferenceContext(Map functions, Map bindings) { - this.functions = ImmutableMap.copyOf(functions); - if (bindings != null) - this.bindings.putAll(bindings); - } - - private static ImmutableMap toMap(Collection list) { - ImmutableMap.Builder 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 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 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 c87eb0ace39..e42884ecc05 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,7 +1,6 @@ // 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; @@ -49,7 +48,7 @@ public class GeneratorLambdaFunctionNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { return type; } + public TensorType type(TypeContext 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 ee4edac4941..66b250736e8 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,7 +1,6 @@ // 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; @@ -76,7 +75,7 @@ public final class IfNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 61086f8182a..da946228291 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,7 +2,6 @@ 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; @@ -58,7 +57,7 @@ public class LambdaFunctionNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 f1adf331630..f55ed59b65c 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,7 +1,6 @@ // 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; @@ -15,7 +14,6 @@ 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; @@ -34,7 +32,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 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 fcc03dc4862..9cbe5f98c72 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,7 +1,6 @@ // 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; @@ -39,7 +38,7 @@ public class NegativeNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 a539f496ff5..e7041600635 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,7 +1,6 @@ // 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; @@ -39,7 +38,7 @@ public class NotNode extends BooleanNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 78f53b1593d..05a6773c5cb 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,7 +3,6 @@ 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; @@ -14,102 +13,114 @@ import java.util.Deque; import java.util.List; /** - * A node referring either to a value in the context or to a named ranking expression (function aka macro). + * A node referring either to a value in the context or to another named ranking expression. * * @author simon * @author bratseth */ public final class ReferenceNode extends CompositeNode { - private final Reference reference; + private final String name, output; + + private final Arguments arguments; - /* Creates a node with a simple identifier reference */ public ReferenceNode(String name) { this(name, null, null); } public ReferenceNode(String name, List arguments, String output) { - this.reference = new Reference(name, - arguments != null ? new Arguments(arguments) : new Arguments(), - output); - } - - public ReferenceNode(Reference reference) { - this.reference = reference; + this.name = name; + this.arguments = arguments != null ? new Arguments(arguments) : new Arguments(); + this.output = output; } public String getName() { - return reference.name(); + return name; } /** Returns the arguments, never null */ - public Arguments getArguments() { return reference.arguments(); } + public Arguments getArguments() { return arguments; } /** Returns a copy of this where the arguments are replaced by the given arguments */ public ReferenceNode setArguments(List arguments) { - return new ReferenceNode(reference.withArguments(new Arguments(arguments))); + return new ReferenceNode(name, arguments, output); } /** Returns the specific output this references, or null if none specified */ - public String getOutput() { return reference.output(); } + public String getOutput() { return output; } /** Returns a copy of this node with a modified output */ public ReferenceNode setOutput(String output) { - return new ReferenceNode(reference.withOutput(output)); + return new ReferenceNode(name, arguments.expressions(), output); } /** Returns an empty list as this has no children */ @Override - public List children() { return reference.arguments().expressions(); } + public List children() { return arguments.expressions(); } @Override public String toString(SerializationContext context, Deque path, CompositeNode parent) { - if (reference.isIdentifier() && context.getBinding(getName()) != null) { - // a bound identifier: replace by the value it is bound to - return context.getBinding(getName()); + if (path == null) + path = new ArrayDeque<>(); + String myName = this.name; + String myOutput = this.output; + List 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; + } } - - 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() + ")"; + // 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(")"); } - - // not resolved in this context: output as-is - return reference.toString(context, path, parent); + ret.append(myOutput != null ? "." + myOutput : ""); + return ret.toString(); } - /** Returns the reference of this node */ - public Reference reference() { return reference; } - @Override - public TensorType type(TypeContext context) { - TensorType type = context.getType(reference); - if (type == null) - throw new IllegalArgumentException("Unknown feature '" + toString() + "'"); - return type; + public TensorType type(TypeContext context) { + // Don't support outputs of different type, for simplicity + return context.getType(toString()); } @Override public Value evaluate(Context context) { - // TODO: Context should accept a Reference instead. - if (reference.isIdentifier()) - return context.get(reference.name()); - return context.get(getName(), getArguments(), getOutput()); + if (arguments.expressions().isEmpty() && output == null) + return context.get(name); + return context.get(name, arguments, output); } @Override public CompositeNode setChildren(List newChildren) { - return setArguments(newChildren); + return new ReferenceNode(name, newChildren, output); } } 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 796c13a8669..ba765d07094 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,11 +16,17 @@ import java.util.Map; * * @author bratseth */ -public class SerializationContext extends FunctionReferenceContext { +public class SerializationContext { - /** Serialized form of functions indexed by name */ + /** Expression functions indexed by name */ + private final ImmutableMap functions; + + /** A cache of already serialized expressions indexed by name */ private final Map serializedFunctions; + /** Mapping from argument names to the expressions they resolve to */ + public final Map bindings = new HashMap<>(); + /** Create a context for a single serialization task */ public SerializationContext() { this(Collections.emptyList()); @@ -71,10 +77,17 @@ public class SerializationContext extends FunctionReferenceContext { */ public SerializationContext(ImmutableMap functions, Map bindings, Map serializedFunctions) { - super(functions, bindings); + this.functions = functions; 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); @@ -85,9 +98,17 @@ public class SerializationContext extends FunctionReferenceContext { return serializedFunctions.get(name); } - @Override - public SerializationContext withBindings(Map bindings) { - return new SerializationContext(functions().values(), bindings, this.serializedFunctions); + /** + * 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 arguments) { + return new SerializationContext(this.functions, arguments, this.serializedFunctions); } public Map 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 cb31219579a..a7b82f4753f 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,7 +2,6 @@ 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; @@ -61,7 +60,7 @@ public class SetMembershipNode extends BooleanNode { } @Override - public TensorType type(TypeContext context) { + public TensorType type(TypeContext 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 6c9b6bb4a98..ec6af4bb413 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,7 +2,6 @@ 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; @@ -65,7 +64,7 @@ public class TensorFunctionNode extends CompositeNode { } @Override - public TensorType type(TypeContext context) { return function.type(context); } + public TensorType type(TypeContext context) { return function.type(context); } @Override public Value evaluate(Context context) { @@ -112,13 +111,12 @@ public class TensorFunctionNode extends CompositeNode { public PrimitiveTensorFunction toPrimitive() { return this; } @Override - @SuppressWarnings("unchecked") // Generics awkwardness - public TensorType type(TypeContext context) { - return expression.type((TypeContext)context); + public TensorType type(TypeContext context) { + return expression.type(context); } @Override - public Tensor evaluate(EvaluationContext context) { + public Tensor evaluate(EvaluationContext 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 f2122bb5da9..e9030cf5852 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 @@ -377,14 +377,9 @@ 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 a08d510eec4..c882c887c8d 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,7 +3,6 @@ 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; @@ -19,17 +18,12 @@ public class TypeResolutionTestCase { @Test public void testTypeResolution() { - 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])")); + 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])")); assertType("tensor(x[])", "query(x1)", context); assertType("tensor(x[])", "if (1>0, query(x1), query(x2))", context); @@ -37,7 +31,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 context) { try { assertEquals(TensorType.fromSpec(type), new RankingExpression(expression).type(context)); } @@ -46,7 +40,7 @@ public class TypeResolutionTestCase { } } - private void assertIncompatibleType(String expression, TypeContext context) { + private void assertIncompatibleType(String expression, TypeContext 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 303135888d8..867331e99ce 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 Simon Thoresen + * @author Simon Thoresen */ public class ArgumentsTestCase { @Test public void requireThatAccessorsWork() { - Arguments args = new Arguments(); + Arguments args = new Arguments(null); assertTrue(args.expressions().isEmpty()); args = new Arguments(Collections.emptyList()); -- cgit v1.2.3