diff options
author | Jon Bratseth <bratseth@oath.com> | 2018-02-14 09:42:46 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@oath.com> | 2018-02-14 09:42:46 +0100 |
commit | fa0bc59e2313aa6b6249ad88f7c1892a3a29553d (patch) | |
tree | f426c5657280a25c4599deecc5cca3be9378cab7 /searchlib/src/main/java/com/yahoo/searchlib/rankingexpression | |
parent | c17b1582face7c7f31fea7e151a5855908fe04f5 (diff) |
Handle argument bindings
Diffstat (limited to 'searchlib/src/main/java/com/yahoo/searchlib/rankingexpression')
7 files changed, 108 insertions, 18 deletions
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/evaluation/ArrayContext.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java index 5f8daa69ecf..486affe9371 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 @@ -82,8 +82,8 @@ public class ArrayContext extends AbstractArrayContext implements Cloneable { } @Override - public TensorType getType(String name) { - Integer index = nameToIndex().get(name); + public TensorType getType(Name name) { + Integer index = nameToIndex().get(name.toString()); if (index == null) return null; return values[index].type(); } 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..01b8bffe995 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 @@ -68,7 +68,7 @@ public class DoubleOnlyArrayContext extends AbstractArrayContext { } @Override - public TensorType getType(String name) { return TensorType.empty; } + public TensorType getType(Name 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 a81d0c89f8f..c7679ea9e55 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 @@ -42,7 +42,7 @@ 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) { + public TensorType getType(Name 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 index d461ae52cbe..2ddc8213d94 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/MapTypeContext.java @@ -15,18 +15,18 @@ import java.util.Map; */ public class MapTypeContext implements TypeContext { - private final Map<String, TensorType> featureTypes = new HashMap<>(); + private final Map<Name, TensorType> featureTypes = new HashMap<>(); public void setType(String name, TensorType type) { - featureTypes.put(name, type); + featureTypes.put(new Name(name), type); } @Override - public TensorType getType(String name) { + public TensorType getType(Name name) { return featureTypes.get(name); } /** Returns an unmodifiable map of the bindings in this */ - public Map<String, TensorType> bindings() { return Collections.unmodifiableMap(featureTypes); } + public Map<Name, TensorType> bindings() { return Collections.unmodifiableMap(featureTypes); } } 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..d7163fe9166 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,8 @@ 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 +23,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) { @@ -62,8 +67,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/ReferenceNode.java b/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/rule/ReferenceNode.java index ebfef21a815..e121fa12b5f 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 @@ -9,8 +9,13 @@ import com.yahoo.tensor.TensorType; import com.yahoo.tensor.evaluation.TypeContext; import java.util.ArrayDeque; +import java.util.Arrays; import java.util.Deque; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * A node referring either to a value in the context or to a named ranking expression (function aka macro). @@ -31,6 +36,7 @@ public final class ReferenceNode extends CompositeNode { } public ReferenceNode(String name, List<? extends ExpressionNode> arguments, String output) { + Objects.requireNonNull(name, "name cannot be null"); this.name = name; this.arguments = arguments != null ? new Arguments(arguments) : new Arguments(); this.output = output; @@ -119,11 +125,10 @@ public final class ReferenceNode extends CompositeNode { @Override public TensorType type(TypeContext context) { - String feature = toString(new SerializationContext(), null, false); - TensorType type = context.getType(feature); - // TensorType type = context.getType(name, arguments, output); TODO + TensorType type = context.getType(new Reference(name, arguments, output, + toString(new SerializationContext(), null, true))); if (type == null) - throw new IllegalArgumentException("Unknown feature '" + feature + "'"); + throw new IllegalArgumentException("Unknown feature '" + toString() + "'"); return type; } @@ -139,4 +144,82 @@ public final class ReferenceNode extends CompositeNode { return new ReferenceNode(name, newChildren, output); } + /** Wraps the content of this in a form which can be passed to a type context */ + // TODO: Extract to top level? + public static class Reference extends TypeContext.Name { + + private static final Pattern identifierRegexp = Pattern.compile("[A-Za-z0-9_][A-Za-z0-9_-]*"); + + 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, String stringForm) { + super(stringForm); + Objects.requireNonNull(name, "name cannot be null"); + Objects.requireNonNull(arguments, "arguments cannot be null"); + Objects.requireNonNull(stringForm, "stringForm 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, + name + "(" + quoteIfNecessary(argumentValue) + ")"); + } + + /** + * 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)); + } + + private static String quoteIfNecessary(String s) { + if (identifierRegexp.matcher(s).matches()) + return s; + else + return "\"" + s + "\""; + } + + @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); + } + + } + } |