diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /container-search/src/main/java/com/yahoo/search/grouping/request |
Publish
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/grouping/request')
110 files changed, 4213 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java new file mode 100644 index 00000000000..2f321a5854d --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents an add-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * result of adding the results of all arguments together in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AddFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public AddFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private AddFunction(List<GroupingExpression> args) { + super("add", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static AddFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new AddFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AggregatorNode.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AggregatorNode.java new file mode 100644 index 00000000000..0df204506c1 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AggregatorNode.java @@ -0,0 +1,53 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an aggregated value in a {@link GroupingExpression}. Because it operates on a list of data, it + * can not be used as a document-level expression (i.e. level 0, see {@link GroupingExpression#resolveLevel(int)}). The + * contained expression is evaluated at the level of the aggregator minus 1. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class AggregatorNode extends GroupingExpression { + + private final GroupingExpression exp; + + protected AggregatorNode(String image) { + super(image + "()"); + this.exp = null; + } + + protected AggregatorNode(String image, GroupingExpression exp) { + super(image + "(" + exp.toString() + ")"); + this.exp = exp; + } + + /** + * Returns the expression that this node aggregates on. + * + * @return The expression. + */ + public GroupingExpression getExpression() { + return exp; + } + + @Override + public void resolveLevel(int level) { + super.resolveLevel(level); + if (level < 1) { + throw new IllegalArgumentException("Expression '" + this + "' not applicable for " + + GroupingOperation.getLevelDesc(level) + "."); + } + if (exp != null) { + exp.resolveLevel(level - 1); + } + } + + @Override + public void visit(ExpressionVisitor visitor) { + super.visit(visitor); + if (exp != null) { + exp.visit(visitor); + } + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AllOperation.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AllOperation.java new file mode 100644 index 00000000000..e78be0c1c1a --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AllOperation.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This is a grouping operation that processes the input list as a whole, as opposed to {@link EachOperation} which + * processes each element of that list separately. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AllOperation extends GroupingOperation { + + /** + * Constructs a new instance of this class. + */ + public AllOperation() { + super("all"); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AndFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AndFunction.java new file mode 100644 index 00000000000..3053153e5a3 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AndFunction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents an and-function in a {@link GroupingExpression}. It evaluates to a long that equals the result + * of and'ing the results of all arguments together in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AndFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a long. + * @param arg2 The second compulsory argument, must evaluate to a long. + * @param argN The optional arguments, must evaluate to a long. + */ + public AndFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private AndFunction(List<GroupingExpression> args) { + super("and", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static AndFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new AndFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ArrayAtLookup.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ArrayAtLookup.java new file mode 100644 index 00000000000..1e613066bd4 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ArrayAtLookup.java @@ -0,0 +1,51 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import com.google.common.annotations.Beta; + +/** + * Represents access of array element in a document attribute in a {@link GroupingExpression}. + * + * The first argument should be the name of an array attribute in the + * input {@link com.yahoo.search.result.Hit}, while the second + * argument is evaluated as an integer and used as the index in that array. + * If the index argument is less than 0 returns the first array element; + * if the index is greater than or equal to size(array) returns the last array element; + * if the array is empty returns 0 (or NaN?). + * @author arnej27959 + */ +@Beta +public class ArrayAtLookup extends DocumentValue { + + private final String attributeName; + private final GroupingExpression arg2; + + /** + * Constructs a new instance of this class. + * + * @param attributeName The attribute name to assign to this. + */ + public ArrayAtLookup(String attributeName, GroupingExpression indexArg) { + super("array.at(" + attributeName + ", " + indexArg + ")"); + this.attributeName = attributeName; + this.arg2 = indexArg; + } + + /** + * Returns the name of the attribute to retrieve from the input hit. + * + * @return The attribute name. + */ + public String getAttributeName() { + return attributeName; + } + + /** + * get the expression to evaluate before indexing + * @return grouping expression argument + */ + public GroupingExpression getIndexArgument() { + return arg2; + } + +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeFunction.java new file mode 100644 index 00000000000..c16903ddca8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeFunction.java @@ -0,0 +1,32 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document attribute function in a {@link GroupingExpression}. It evaluates to the value of the + * named attribute in the input {@link com.yahoo.search.result.Hit}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AttributeFunction extends DocumentValue { + + private final String name; + + /** + * Constructs a new instance of this class. + * + * @param attributeName The attribute name to assign to this. + */ + public AttributeFunction(String attributeName) { + super("attribute(" + attributeName + ")"); + name = attributeName; + } + + /** + * Returns the name of the attribute to retrieve from the input hit. + * + * @return The attribute name. + */ + public String getAttributeName() { + return name; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeValue.java new file mode 100644 index 00000000000..135463bf108 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeValue.java @@ -0,0 +1,32 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document attribute value in a {@link GroupingExpression}. It evaluates to the value of the + * named attribute in the input {@link com.yahoo.search.result.Hit}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AttributeValue extends DocumentValue { + + private final String name; + + /** + * Constructs a new instance of this class. + * + * @param attributeName The attribute name to assign to this. + */ + public AttributeValue(String attributeName) { + super(attributeName); + name = attributeName; + } + + /** + * Returns the name of the attribute to retrieve from the input hit. + * + * @return The attribute name. + */ + public String getAttributeName() { + return name; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AvgAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AvgAggregator.java new file mode 100644 index 00000000000..749b419488f --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AvgAggregator.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an average-aggregator in a {@link GroupingExpression}. It evaluates to the average value that + * the contained expression evaluated to over all the inputs. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AvgAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to aggregate on. + */ + public AvgAggregator(GroupingExpression exp) { + super("avg", exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AvgFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AvgFunction.java new file mode 100644 index 00000000000..c0474064741 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AvgFunction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a min-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * average of the results of all arguments. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AvgFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public AvgFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private AvgFunction(List<GroupingExpression> args) { + super("avg", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static AvgFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new AvgFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/BooleanValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/BooleanValue.java new file mode 100644 index 00000000000..c41cfa4c4f2 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/BooleanValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a constant {@link Boolean} value in a {@link GroupingExpression}. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class BooleanValue extends ConstantValue<Boolean> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public BooleanValue(Boolean value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java new file mode 100644 index 00000000000..735347cde87 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java @@ -0,0 +1,121 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.LinkedList; +import java.util.List; + +/** + * This is a helper class for resolving buckets to a list of + * {@link GroupingExpression} objects. To resolve a list simply + * {@link #push(ConstantValue, boolean)} onto it, before calling + * {@link #resolve(GroupingExpression)} to retrieve the list of corresponding + * grouping expression object. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class BucketResolver { + + private final List<BucketValue> buckets = new LinkedList<>(); + private ConstantValue<?> prev = null; + private boolean previnclusive = false; + private int idx = 0; + + /** + * Pushes the given expression onto this bucket resolver. Once all buckets have been pushed using this method, call + * {@link #resolve(GroupingExpression)} to retrieve to combined grouping expression. + * + * @param val The expression to push. + * @param inclusive Whether or not the value is inclusive or not. + * @throws IllegalArgumentException Thrown if the expression is incompatible. + */ + public BucketResolver push(ConstantValue<?> val, boolean inclusive) { + if (prev == null) { + prev = val; + } else if (!(prev instanceof InfiniteValue || val instanceof InfiniteValue) + && !prev.getClass().equals(val.getClass())) { + throw new IllegalArgumentException("Bucket type mismatch, expected '" + prev.getClass().getSimpleName() + + "' got '" + val.getClass().getSimpleName() + "'."); + } else if (prev instanceof InfiniteValue && val instanceof InfiniteValue) { + throw new IllegalArgumentException("Bucket type mismatch, cannot both be infinity."); + } + if ((++idx % 2) == 0) { + ConstantValue<?> begin = previnclusive ? prev : nextValue(prev); + ConstantValue<?> end = inclusive ? nextValue(val) : val; + if (begin instanceof DoubleValue || end instanceof DoubleValue) { + buckets.add(new DoubleBucket(begin, end)); + } else if (begin instanceof LongValue || end instanceof LongValue) { + buckets.add(new LongBucket(begin, end)); + } else if (begin instanceof StringValue || end instanceof StringValue) { + buckets.add(new StringBucket(begin, end)); + } else if (begin instanceof RawValue || end instanceof RawValue) { + buckets.add(new RawBucket(begin, end)); + } else { + throw new UnsupportedOperationException("Bucket type '" + val.getClass() + "' not supported."); + } + } + prev = val; + previnclusive = inclusive; + return this; + } + + /** + * Resolves and returns the list of grouping expressions that correspond to the previously pushed buckets. + * + * @param exp The expression to assign to the function. + * @return The list corresponding to the pushed buckets. + */ + public PredefinedFunction resolve(GroupingExpression exp) { + if ((idx % 2) == 1) { + throw new IllegalStateException("Missing to-limit of last bucket."); + } + int len = buckets.size(); + if (len == 0) { + throw new IllegalStateException("Expected at least one bucket, got none."); + } + ConstantValue<?> begin = buckets.get(0).getFrom(); + ConstantValue<?> end = buckets.get(0).getTo(); + if (begin instanceof DoubleValue || end instanceof DoubleValue) { + if (len == 1) { + return new DoublePredefined(exp, (DoubleBucket)buckets.get(0)); + } else { + return new DoublePredefined(exp, (DoubleBucket)buckets.get(0), + buckets.subList(1, len).toArray(new DoubleBucket[len - 1])); + } + } else if (begin instanceof LongValue || end instanceof LongValue) { + if (len == 1) { + return new LongPredefined(exp, (LongBucket)buckets.get(0)); + } else { + return new LongPredefined(exp, (LongBucket)buckets.get(0), + buckets.subList(1, len).toArray(new LongBucket[len - 1])); + } + } else if (begin instanceof StringValue || end instanceof StringValue) { + if (len == 1) { + return new StringPredefined(exp, (StringBucket)buckets.get(0)); + } else { + return new StringPredefined(exp, (StringBucket)buckets.get(0), + buckets.subList(1, len).toArray(new StringBucket[len - 1])); + } + } else if (begin instanceof RawValue || end instanceof RawValue) { + if (len == 1) { + return new RawPredefined(exp, (RawBucket)buckets.get(0)); + } else { + return new RawPredefined(exp, (RawBucket)buckets.get(0), + buckets.subList(1, len).toArray(new RawBucket[len - 1])); + } + } + throw new UnsupportedOperationException("Bucket type '" + begin.getClass() + "' not supported."); + } + + private ConstantValue<?> nextValue(ConstantValue<?> value) { + if (value instanceof LongValue) { + return LongBucket.nextValue((LongValue)value); + } else if (value instanceof DoubleValue) { + return DoubleBucket.nextValue((DoubleValue)value); + } else if (value instanceof StringValue) { + return StringBucket.nextValue((StringValue)value); + } else if (value instanceof RawValue) { + return RawBucket.nextValue((RawValue)value); + } + return value; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/BucketValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketValue.java new file mode 100644 index 00000000000..858a44e2fe8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketValue.java @@ -0,0 +1,54 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a bucket in a {@link PredefinedFunction}. The generic T is the data type of the range values + * 'from' and 'to'. The range is inclusive-from and exclusive-to. All supported data types are represented as subclasses + * of this. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class BucketValue extends GroupingExpression implements Comparable<BucketValue> { + + private final ConstantValue<?> from; + private final ConstantValue<?> to; + private final ConstantValueComparator comparator = new ConstantValueComparator(); + + protected BucketValue(ConstantValue<?> inclusiveFrom, ConstantValue<?> exclusiveTo) { + super("bucket[" + asImage(inclusiveFrom) + ", " + asImage(exclusiveTo) + ">"); + if (comparator.compare(exclusiveTo, inclusiveFrom) < 0) { + throw new IllegalArgumentException("Bucket to-value can not be less than from-value."); + } + from = inclusiveFrom; + to = exclusiveTo; + } + + /** + * Returns the inclusive-from value of this bucket. + * + * @return The from-value. + */ + public ConstantValue<?> getFrom() { + return from; + } + + /** + * Returns the exclusive-to value of this bucket. + * + * @return The to-value. + */ + public ConstantValue<?> getTo() { + return to; + } + + @Override + public int compareTo(BucketValue rhs) { + if (comparator.compare(to, rhs.from) <= 0) { + return -1; + } + if (comparator.compare(from, rhs.to) >= 0) { + return 1; + } + return 0; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/CatFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/CatFunction.java new file mode 100644 index 00000000000..9bc276bda92 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/CatFunction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a cat-function in a {@link GroupingExpression}. It evaluates to a byte array that equals the + * concatenation of the binary result of all arguments in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class CatFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument. + * @param arg2 The second compulsory argument. + * @param argN The optional arguments. + */ + public CatFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private CatFunction(List<GroupingExpression> args) { + super("cat", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static CatFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new CatFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValue.java new file mode 100644 index 00000000000..8b8d92b5ae8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValue.java @@ -0,0 +1,29 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a constant value in a {@link GroupingExpression}. Because it does not operate on any input, + * this expression type can be used at any input level (see {@link GroupingExpression#resolveLevel(int)}). All supported + * data types are represented as subclasses of this. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +@SuppressWarnings("rawtypes") +public abstract class ConstantValue<T extends Comparable> extends GroupingExpression { + + private final T value; + + protected ConstantValue(T value) { + super(asImage(value)); + this.value = value; + } + + /** + * Returns the constant value of this. + * + * @return The value. + */ + public T getValue() { + return value; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValueComparator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValueComparator.java new file mode 100644 index 00000000000..e8017bbb796 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ConstantValueComparator.java @@ -0,0 +1,24 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Comparator; + +/** + * This class compares two constant values, and takes into account that one of + * the arguments may be the very special infinity value. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +@SuppressWarnings("rawtypes") +public class ConstantValueComparator implements Comparator<ConstantValue> { + @SuppressWarnings("unchecked") + @Override + public int compare(ConstantValue lhs, ConstantValue rhs) { + // Run infinite comparison method if one of the arguments are infinite. + if (rhs instanceof InfiniteValue) { + return (-1 * rhs.getValue().compareTo(lhs)); + } + return (lhs.getValue().compareTo(rhs.getValue())); + } + +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/CountAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/CountAggregator.java new file mode 100644 index 00000000000..f54d92cdbf5 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/CountAggregator.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an count-aggregator in a {@link GroupingExpression}. It evaluates to the number of elements + * there are in the input. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class CountAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + */ + public CountAggregator() { + super("count"); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DateFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DateFunction.java new file mode 100644 index 00000000000..3d416b31d95 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DateFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a timestamp-formatter function in a {@link GroupingExpression}. It evaluates to a string on the + * form "YYYY-MM-DD" of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DateFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public DateFunction(GroupingExpression exp) { + super("time.date", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfMonthFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfMonthFunction.java new file mode 100644 index 00000000000..4ead68cc8f1 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfMonthFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a day-of-month timestamp-function in a {@link GroupingExpression}. It evaluates to a long that + * equals the day of month (1-31) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DayOfMonthFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public DayOfMonthFunction(GroupingExpression exp) { + super("time.dayofmonth", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfWeekFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfWeekFunction.java new file mode 100644 index 00000000000..f91344e2e7b --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfWeekFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a day-of-week timestamp-function in a {@link GroupingExpression}. It evaluates to a long that + * equals the day of week (0 - 6) of the result of the argument, Monday being 0. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DayOfWeekFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public DayOfWeekFunction(GroupingExpression exp) { + super("time.dayofweek", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfYearFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfYearFunction.java new file mode 100644 index 00000000000..20313864493 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DayOfYearFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a day-of-year timestamp-function in a {@link GroupingExpression}. It evaluates to a long that + * equals the day of year (0-365) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DayOfYearFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public DayOfYearFunction(GroupingExpression exp) { + super("time.dayofyear", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DebugWaitFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DebugWaitFunction.java new file mode 100644 index 00000000000..c2f26e6b3b0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DebugWaitFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents debug_wait function in a {@link GroupingExpression}. For each hit evaluated, + * it waits for the time specified as the second argument. The third argument specifies if the wait + * should be a busy-wait or not. The first argument is then evaluated. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class DebugWaitFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, the expression to proxy. + * @param arg2 The second compulsory argument, must evaluate to a positive number. + * @param arg3 The third compulsory argument, specifying busy wait or not. + */ + public DebugWaitFunction(GroupingExpression arg1, DoubleValue arg2, BooleanValue arg3) { + super("debugwait", Arrays.asList(arg1, arg2, arg3)); + } + + /** + * Returns the time to wait when evaluating this function. + * + * @return the number of seconds to wait. + */ + public double getWaitTime() { + return ((DoubleValue)getArg(1)).getValue(); + } + + /** + * Returns whether or not the debug node should busy-wait. + * + * @return true if busy-wait, false if not. + */ + public boolean getBusyWait() { + return ((BooleanValue)getArg(2)).getValue(); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DivFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DivFunction.java new file mode 100644 index 00000000000..9ed263362fa --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DivFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a div-function in a {@link GroupingExpression}. It evaluates to a number that equals the result + * of dividing the results of all arguments in the order they were given to the constructor (divide first argument by + * second, result by third, ...). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DivFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public DivFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private DivFunction(List<GroupingExpression> args) { + super("div", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static DivFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new DivFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DocIdNsSpecificValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DocIdNsSpecificValue.java new file mode 100644 index 00000000000..02c8d66be5d --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DocIdNsSpecificValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document id specific value in a {@link GroupingExpression}. It evaluates to the namespace- + * specific value of the document id of the input {@link com.yahoo.search.result.Hit}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DocIdNsSpecificValue extends DocumentValue { + + /** + * Constructs a new instance of this class. + */ + public DocIdNsSpecificValue() { + super("docidnsspecific()"); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DocumentValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DocumentValue.java new file mode 100644 index 00000000000..98d5a6fe21f --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DocumentValue.java @@ -0,0 +1,24 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document value in a {@link GroupingExpression}. As such, the subclasses of this can only be + * used as document-level expressions (i.e. level 0, see {@link GroupingExpression#resolveLevel(int)}). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class DocumentValue extends GroupingExpression { + + protected DocumentValue(String image) { + super(image); + } + + @Override + public void resolveLevel(int level) { + if (level != 0) { + throw new IllegalArgumentException("Expression '" + this + "' not applicable for " + + GroupingOperation.getLevelDesc(level) + "."); + } + super.resolveLevel(level); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleBucket.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleBucket.java new file mode 100644 index 00000000000..4e12e96272e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleBucket.java @@ -0,0 +1,41 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; +import java.text.ChoiceFormat; + +/** + * This class represents a {@link Double} bucket in a {@link PredefinedFunction}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DoubleBucket extends BucketValue { + + /** + * Returns the next distinct value. + * + * @param value The base value. + * @return the next value. + */ + public static DoubleValue nextValue(DoubleValue value) { + return (new DoubleValue(ChoiceFormat.nextDouble(value.getValue()))); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public DoubleBucket(double from, double to) { + super(new DoubleValue(from), new DoubleValue(to)); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public DoubleBucket(ConstantValue<?> from, ConstantValue<?> to) { + super(from, to); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DoublePredefined.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DoublePredefined.java new file mode 100644 index 00000000000..59265359715 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DoublePredefined.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a predefined bucket-function in a {@link GroupingExpression} for expressions that evaluate to a + * double. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DoublePredefined extends PredefinedFunction { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a double. + * @param arg1 The compulsory bucket. + * @param argN The optional buckets. + */ + public DoublePredefined(GroupingExpression exp, DoubleBucket arg1, DoubleBucket... argN) { + this(exp, asList(arg1, argN)); + } + + private DoublePredefined(GroupingExpression exp, List<DoubleBucket> args) { + super(exp, args); + } + + @Override + public DoubleBucket getBucket(int i) { + return (DoubleBucket)getArg(i + 1); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param exp The expression to evaluate, must evaluate to a double. + * @param args The buckets to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the list of buckets is empty. + */ + public static DoublePredefined newInstance(GroupingExpression exp, List<DoubleBucket> args) { + if (args.isEmpty()) { + throw new IllegalArgumentException("Expected at least one bucket, got none."); + } + return new DoublePredefined(exp, args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleValue.java new file mode 100644 index 00000000000..682102533ff --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/DoubleValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a constant {@link Double} value in a {@link GroupingExpression}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DoubleValue extends ConstantValue<Double> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public DoubleValue(double value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/EachOperation.java b/container-search/src/main/java/com/yahoo/search/grouping/request/EachOperation.java new file mode 100644 index 00000000000..12f6df1f497 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/EachOperation.java @@ -0,0 +1,26 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This is a grouping operation that processes each element of the input list separately, as opposed to {@link + * AllOperation} which processes that list as a whole. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class EachOperation extends GroupingOperation { + + /** + * Constructs a new instance of this class. + */ + public EachOperation() { + super("each"); + } + + @Override + public void resolveLevel(int level) { + if (level == 0) { + throw new IllegalArgumentException("Operation '" + this + "' can not operate on " + getLevelDesc(level) + "."); + } + super.resolveLevel(level - 1); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ExpressionVisitor.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ExpressionVisitor.java new file mode 100644 index 00000000000..ba411ac45ce --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ExpressionVisitor.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This interface defines the necessary callback to recursively visit all {@link GroupingExpression} objects in a {@link + * GroupingOperation}. It is used by the {@link com.yahoo.search.grouping.GroupingValidator} to ensure that all + * referenced attributes are valid for the cluster being queried. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public interface ExpressionVisitor { + + /** + * This method is called for every {@link GroupingExpression} object in the targeted {@link GroupingOperation}. + * + * @param exp The expression being visited. + */ + public void visitExpression(GroupingExpression exp); +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/FixedWidthFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/FixedWidthFunction.java new file mode 100644 index 00000000000..9ac3870718b --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/FixedWidthFunction.java @@ -0,0 +1,34 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a fixed-width bucket-function in a {@link GroupingExpression}. It maps the input into the given + * number of buckets by the result of the argument expression. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class FixedWidthFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + * @param width The width of each bucket. + */ + public FixedWidthFunction(GroupingExpression exp, Number width) { + super("fixedwidth", Arrays.asList(exp, width instanceof Double ? new DoubleValue(width.doubleValue()) : new LongValue(width.longValue()))); + } + + /** + * Returns the number of buckets to divide the result into. + * + * @return The bucket count. + */ + public Number getWidth() { + GroupingExpression w = getArg(1); + return (w instanceof LongValue) ? ((LongValue)w).getValue() : ((DoubleValue)w).getValue(); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/FunctionNode.java b/container-search/src/main/java/com/yahoo/search/grouping/request/FunctionNode.java new file mode 100644 index 00000000000..3003ce69abe --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/FunctionNode.java @@ -0,0 +1,78 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.*; + +/** + * This class represents a function in a {@link GroupingExpression}. Because it operate on other expressions (as opposed + * to {@link AggregatorNode} and {@link DocumentValue} that operate on inputs), this expression type can be used at any + * input level (see {@link GroupingExpression#resolveLevel(int)}). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class FunctionNode extends GroupingExpression implements Iterable<GroupingExpression> { + + private final List<GroupingExpression> args = new ArrayList<>(); + + protected FunctionNode(String image, List<GroupingExpression> args) { + super(image + "(" + asString(args) + ")"); + this.args.addAll(args); + } + + /** + * Returns the number of arguments that were given to this function at construction. + * + * @return The argument count. + */ + public int getNumArgs() { + return args.size(); + } + + /** + * Returns the argument at the given index. + * + * @param i The index of the argument to return. + * @return The argument at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public GroupingExpression getArg(int i) { + return args.get(i); + } + + @Override + public Iterator<GroupingExpression> iterator() { + return Collections.unmodifiableList(args).iterator(); + } + + @Override + public void resolveLevel(int level) { + super.resolveLevel(level); + for (GroupingExpression arg : args) { + arg.resolveLevel(level); + } + } + + @Override + public void visit(ExpressionVisitor visitor) { + super.visit(visitor); + for (GroupingExpression arg : args) { + arg.visit(visitor); + } + } + + @SuppressWarnings("unchecked") + protected static <T> List<T> asList(T arg1, T... argN) { + return asList(Arrays.asList(arg1), Arrays.asList(argN)); + } + + @SuppressWarnings("unchecked") + protected static <T> List<T> asList(T arg1, T arg2, T... argN) { + return asList(Arrays.asList(arg1, arg2), Arrays.asList(argN)); + } + + protected static <T> List<T> asList(List<T> foo, List<T> bar) { + List<T> ret = new LinkedList<>(foo); + ret.addAll(bar); + return ret; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingExpression.java b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingExpression.java new file mode 100644 index 00000000000..6015557f81e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingExpression.java @@ -0,0 +1,100 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import com.yahoo.javacc.UnicodeUtilities; + +import java.util.List; + +/** + * This class represents an expression in a {@link GroupingOperation}. You may manually construct this expression, or + * you may use the {@link com.yahoo.search.grouping.request.parser.GroupingParser} to generate one from a query-string. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class GroupingExpression extends GroupingNode { + + private Integer level = null; + + protected GroupingExpression(String image) { + super(image); + } + + /** + * Resolves the conceptual level of this expression. This level represents the type of data that is consumed by this + * expression, where level 0 is a single hit, level 1 is a group, level 2 is a list of groups, and so forth. This + * method verifies the input level against the expression type, and recursively resolves the level of all argument + * expressions. + * + * @param level The level of the input data. + * @throws IllegalArgumentException Thrown if the level of this expression could not be resolved. + * @throws IllegalStateException Thrown if type failed to accept the number of arguments provided. + */ + public void resolveLevel(int level) { + if (level < 0) { + throw new IllegalArgumentException("Expression '" + this + "' recurses through a single hit."); + } + this.level = level; + } + + /** + * Returns the conceptual level of this expression. + * + * @return The level. + * @throws IllegalArgumentException Thrown if the level of this expression has not been resolved. + * @see #resolveLevel(int) + */ + public int getLevel() { + if (level == null) { + throw new IllegalStateException("Level for expression '" + this + "' has not been resolved."); + } + return level; + } + + /** + * Recursively calls {@link ExpressionVisitor#visitExpression(GroupingExpression)} for this expression and all of + * its argument expressions. + * + * @param visitor The visitor to call. + */ + public void visit(ExpressionVisitor visitor) { + visitor.visitExpression(this); + } + + /** + * Returns a string description of the given list of expressions. This is a comma-separated list of the expressions + * own {@link GroupingExpression#toString()} output. + * + * @param lst The list of expressions to output. + * @return The string description. + */ + public static String asString(List<GroupingExpression> lst) { + StringBuilder ret = new StringBuilder(); + for (int i = 0, len = lst.size(); i < len; ++i) { + ret.append(lst.get(i)); + if (i < len - 1) { + ret.append(", "); + } + } + return ret.toString(); + } + + /** + * Returns a string representation of an object that can be used in the 'image' constructor argument of {@link + * GroupingNode}. This method ensures that strings are quoted, and that all complex characters are escaped. + * + * @param obj The object to output. + * @return The string representation. + */ + public static String asImage(Object obj) { + if (!(obj instanceof String)) { + return obj.toString(); + } + return UnicodeUtilities.quote((String)obj, '"'); + } + + @Override + public GroupingExpression setLabel(String label) { + super.setLabel(label); + return this; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingNode.java b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingNode.java new file mode 100644 index 00000000000..b400dfe5737 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingNode.java @@ -0,0 +1,44 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This is the abstract super class of both {@link GroupingOperation} and {@link GroupingExpression}. All nodes can be + * assigned a {@link String} label which in turn can be used to identify the corresponding result objects. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class GroupingNode { + + private final String image; + private String label = null; + + protected GroupingNode(String image) { + this.image = image; + } + + /** + * Returns the label assigned to this grouping expression. + * + * @return The label string. + */ + public String getLabel() { + return label; + } + + /** + * Assigns a label to this grouping expression. The label is applied to the results of this expression so that they + * can be identified by the caller when processing the output. + * + * @param str The label to assign to this. + * @return This, to allow chaining. + */ + public GroupingNode setLabel(String str) { + label = str; + return this; + } + + @Override + public String toString() { + return image; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java new file mode 100644 index 00000000000..d49713ba9f2 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java @@ -0,0 +1,582 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import com.yahoo.collections.LazyMap; +import com.yahoo.collections.LazySet; +import com.yahoo.search.grouping.request.parser.GroupingParser; +import com.yahoo.search.grouping.request.parser.GroupingParserInput; +import com.yahoo.search.grouping.request.parser.ParseException; +import com.yahoo.search.grouping.request.parser.TokenMgrError; + +import java.util.*; + +/** + * This class represents a single node in a grouping operation tree. You may manually construct this tree, or you may + * use the {@link #fromString(String)} method to generate one from a query-string. To execute, assign it to a {@link + * com.yahoo.search.grouping.GroupingRequest} using the {@link com.yahoo.search.grouping.GroupingRequest#setRootOperation(GroupingOperation)} + * method. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class GroupingOperation extends GroupingNode { + + private final List<GroupingExpression> orderBy = new ArrayList<>(); + private final List<GroupingExpression> outputs = new ArrayList<>(); + private final List<GroupingOperation> children = new ArrayList<>(); + private final Map<String, GroupingExpression> alias = LazyMap.newHashMap(); + private final Set<String> hints = LazySet.newHashSet(); + + private GroupingExpression groupBy = null; + private GroupingOperation parent = null; + private String where = null; + private boolean forceSinglePass = false; + private double accuracy = 0.95; + private int precision = 0; + private int level = -1; + private int max = -1; + + protected GroupingOperation(String image) { + super(image); + } + + /** + * Registers an alias with this operation. An alias is made available to expressions in both this node and all child + * nodes. + * + * @param id The id of the alias to put. + * @param exp The expression to associate with the id. + * @return This, to allow chaining. + */ + public GroupingOperation putAlias(String id, GroupingExpression exp) { + alias.put(id, exp); + return this; + } + + /** + * Returns the alias associated with the given name. If no alias can be found in this node, this method queries its + * parent grouping node. If the alias still can not be found, this method returns null. + * + * @param id The id of the alias to return. + * @return The expression associated with the id. + */ + public GroupingExpression getAlias(String id) { + if (alias.containsKey(id)) { + return alias.get(id); + } else if (parent != null) { + return parent.getAlias(id); + } else { + return null; + } + } + + /** + * Adds a hint to this. + * + * @param hint The hint to add. + * @return This, to allow chaining. + */ + public GroupingOperation addHint(String hint) { + hints.add(hint); + return this; + } + + /** + * Returns whether or not the given hint has been added to this. + * + * @param hint The hint to check for. + * @return True if the hint has been added. + */ + public boolean containsHint(String hint) { + return hints.contains(hint); + } + + /** + * Returns an immutable view to the hint list of this node. + * + * @return The list. + */ + public Set<String> getHints() { + return Collections.unmodifiableSet(hints); + } + + /** + * Adds a child grouping node to this. This will also set the parent of the child so that it points to this node. + * + * @param op The child node to add. + * @return This, to allow chaining. + */ + public GroupingOperation addChild(GroupingOperation op) { + op.parent = this; + children.add(op); + return this; + } + + /** + * Convenience method to call {@link #addChild(GroupingOperation)} for each element in the given list. + * + * @param lst The list of operations to add. + * @return This, to allow chaining. + */ + public GroupingOperation addChildren(List<GroupingOperation> lst) { + for (GroupingOperation op : lst) { + addChild(op); + } + return this; + } + + /** + * Returns the number of child operations of this. + * + * @return The child count. + */ + public int getNumChildren() { + return children.size(); + } + + /** + * Returns the child operation at the given index. + * + * @param i The index of the child to return. + * @return The child at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public GroupingOperation getChild(int i) { + return children.get(i); + } + + /** + * Returns an immutable view to the child list of this node. + * + * @return The list. + */ + public List<GroupingOperation> getChildren() { + return Collections.unmodifiableList(children); + } + + /** + * Assigns an expressions as the group-by clause of this operation. + * + * @param exp The expression to assign to this. + * @return This, to allow chaining. + */ + public GroupingOperation setGroupBy(GroupingExpression exp) { + groupBy = exp; + return this; + } + + /** + * Returns the expression assigned as the group-by clause of this. + * + * @return The expression. + */ + public GroupingExpression getGroupBy() { + return groupBy; + } + + /** + * Returns the conceptual level of this node. + * + * @return The level, or -1 if not resolved. + * @see #resolveLevel(int) + */ + public int getLevel() { + return level; + } + + /** + * Resolves the conceptual level of this operation. This level represents the type of data that is consumed by this + * operation, where level 0 is a single hit, level 1 is a group, level 2 is a list of groups, and so forth. This + * method verifies the input level against the operation type, and recursively resolves the level of all argument + * expressions. + * + * @param level The level of the input data. + * @throws IllegalArgumentException Thrown if a contained expression is invalid for the given level. + */ + public void resolveLevel(int level) { + if (groupBy != null) { + if (level == 0) { + throw new IllegalArgumentException( + "Operation '" + this + "' can not group " + getLevelDesc(level) + "."); + } + groupBy.resolveLevel(level - 1); + ++level; + } + if (hasMax()) { + if (level == 0) { + throw new IllegalArgumentException( + "Operation '" + this + "' can not apply max to " + getLevelDesc(level) + "."); + } + } + this.level = level; + for (GroupingExpression exp : outputs) { + exp.resolveLevel(level); + } + if (!orderBy.isEmpty()) { + if (level == 0) { + throw new IllegalArgumentException( + "Operation '" + this + "' can not order " + getLevelDesc(level) + "."); + } + for (GroupingExpression exp : orderBy) { + exp.resolveLevel(level - 1); + } + } + for (GroupingOperation child : children) { + child.resolveLevel(level); + } + } + + public GroupingOperation setForceSinglePass(boolean forceSinglePass) { + this.forceSinglePass = forceSinglePass; + return this; + } + + public boolean getForceSinglePass() { + return forceSinglePass; + } + + /** + * Assigns the max clause of this. This is the maximum number of groups to return for this operation. + * + * @param max The expression to assign to this. + * @return This, to allow chaining. + * @see #setPrecision(int) + */ + public GroupingOperation setMax(int max) { + this.max = max; + return this; + } + + /** + * Returns the max clause of this. + * + * @return The expression. + * @see #setMax(int) + */ + public int getMax() { + return max; + } + + /** + * Indicates if the 'max' value has been set. + * + * @return true if max value is set. + */ + public boolean hasMax() { return max >= 0; } + + /** + * Assigns an accuracy value for this. This is a number between 0 and 1 describing the accuracy of the result, which + * again determines the speed of the grouping request. A low value will make sure the grouping operation runs fast, + * at the sacrifice if a (possible) imprecise result. + * + * @param accuracy The accuracy to assign to this. + * @return This, to allow chaining. + * @throws IllegalArgumentException If the accuracy is outside the allowed value range. + */ + public GroupingOperation setAccuracy(double accuracy) { + if (accuracy > 1.0 || accuracy < 0.0) { + throw new IllegalArgumentException("Illegal accuracy '" + accuracy + "'. Must be between 0 and 1."); + } + this.accuracy = accuracy; + return this; + } + + /** + * Return the accuracy of this. + * + * @return The accuracy value. + * @see #setAccuracy(double) + */ + public double getAccuracy() { + return accuracy; + } + + /** + * Adds an expression to the order-by clause of this operation. + * + * @param exp The expressions to add to this. + * @return This, to allow chaining. + */ + public GroupingOperation addOrderBy(GroupingExpression exp) { + orderBy.add(exp); + return this; + } + + /** + * Convenience method to call {@link #addOrderBy(GroupingExpression)} for each element in the given list. + * + * @param lst The list of expressions to add. + * @return This, to allow chaining. + */ + public GroupingOperation addOrderBy(List<GroupingExpression> lst) { + for (GroupingExpression exp : lst) { + addOrderBy(exp); + } + return this; + } + + /** + * Returns the number of expressions in the order-by clause of this. + * + * @return The expression count. + */ + public int getNumOrderBy() { + return orderBy.size(); + } + + /** + * Returns the group-by expression at the given index. + * + * @param i The index of the expression to return. + * @return The expression at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public GroupingExpression getOrderBy(int i) { + return orderBy.get(i); + } + + /** + * Returns an immutable view to the order-by clause of this. + * + * @return The expression list. + */ + public List<GroupingExpression> getOrderBy() { + return Collections.unmodifiableList(orderBy); + } + + /** + * Adds an expression to the output clause of this operation. + * + * @param exp The expressions to add to this. + * @return This, to allow chaining. + */ + public GroupingOperation addOutput(GroupingExpression exp) { + outputs.add(exp); + return this; + } + + /** + * Convenience method to call {@link #addOutput(GroupingExpression)} for each element in the given list. + * + * @param lst The list of expressions to add. + * @return This, to allow chaining. + */ + public GroupingOperation addOutputs(List<GroupingExpression> lst) { + for (GroupingExpression exp : lst) { + addOutput(exp); + } + return this; + } + + /** + * Returns the number of expressions in the output clause of this. + * + * @return The expression count. + */ + public int getNumOutputs() { + return outputs.size(); + } + + /** + * Returns the output expression at the given index. + * + * @param i The index of the expression to return. + * @return The expression at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public GroupingExpression getOutput(int i) { + return outputs.get(i); + } + + /** + * Returns an immutable view to the output clause of this. + * + * @return The expression list. + */ + public List<GroupingExpression> getOutputs() { + return Collections.unmodifiableList(outputs); + } + + /** + * Assigns the precision clause of this. This is the number of intermediate groups returned from each search-node + * during expression evaluation to give the dispatch-node more data to consider when selecting the N groups that are + * to be evaluated further. + * + * @param precision The precision to set. + * @return This, to allow chaining. + * @see #setMax(int) + */ + public GroupingOperation setPrecision(int precision) { + this.precision = precision; + return this; + } + + /** + * Returns the precision clause of this. + * + * @return The precision. + */ + public int getPrecision() { + return precision; + } + + /** + * Assigns a string as the where clause of this operation. + * + * @param str The string to assign to this. + * @return This, to allow chaining. + */ + public GroupingOperation setWhere(String str) { + where = str; + return this; + } + + /** + * Returns the where clause assigned to this operation. + * + * @return The where clause. + */ + public String getWhere() { + return where; + } + + /** + * Recursively calls {@link GroupingExpression#visit(ExpressionVisitor)} on all {@link GroupingExpression} objects + * in this operation and in all of its child operations. + * + * @param visitor The visitor to call. + */ + public void visitExpressions(ExpressionVisitor visitor) { + for (GroupingExpression exp : alias.values()) { + exp.visit(visitor); + } + for (GroupingExpression exp : outputs) { + exp.visit(visitor); + } + for (GroupingExpression exp : orderBy) { + exp.visit(visitor); + } + if (groupBy != null) { + groupBy.visit(visitor); + } + for (GroupingOperation op : children) { + op.visitExpressions(visitor); + } + } + + @Override + public GroupingOperation setLabel(String label) { + super.setLabel(label); + return this; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append(super.toString()).append("("); + if (groupBy != null) { + ret.append("group(").append(groupBy).append(") "); + } + for (String hint : hints) { + ret.append("hint(").append(hint).append(") "); + } + if (hasMax()) { + ret.append("max(").append(max).append(") "); + } + if (!orderBy.isEmpty()) { + ret.append("order("); + ret.append(GroupingExpression.asString(orderBy)); + ret.append(") "); + } + if (!outputs.isEmpty()) { + ret.append("output("); + for (int i = 0, len = outputs.size(); i < len; ++i) { + GroupingExpression exp = outputs.get(i); + ret.append(exp); + String label = exp.getLabel(); + if (label != null) { + ret.append(" as(").append(label).append(")"); + } + if (i < len - 1) { + ret.append(", "); + } + } + ret.append(") "); + } + if (precision != 0) { + ret.append("precision(").append(precision).append(") "); + } + if (where != null) { + ret.append("where(").append(where).append(") "); + } + for (GroupingOperation child : children) { + ret.append(child).append(" "); + } + int len = ret.length(); + if (ret.charAt(len - 1) == ' ') { + ret.setLength(len - 1); + } + ret.append(")"); + String label = getLabel(); + if (label != null) { + ret.append(" as(").append(label).append(")"); + } + return ret.toString(); + } + + /** + * Returns a description of the given level. This allows for more descriptive errors being passed back to the user. + * + * @param level The level to describe. + * @return A description of the given level. + */ + public static String getLevelDesc(int level) { + if (level <= 0) { + return "single hit"; + } else if (level == 1) { + return "single group"; + } else { + StringBuilder ret = new StringBuilder(); + for (int i = 1; i < level; ++i) { + ret.append("list of "); + } + ret.append("groups"); + return ret.toString(); + } + } + + /** + * Convenience method to call {@link #fromStringAsList(String)} and assert that the list contains exactly one + * grouping operation. + * + * @param str The string to parse. + * @return A grouping operation that corresponds to the string. + * @throws IllegalArgumentException Thrown if the string could not be parsed as a single operation. + */ + public static GroupingOperation fromString(String str) { + List<GroupingOperation> lst = fromStringAsList(str); + if (lst.size() != 1) { + throw new IllegalArgumentException("Expected 1 operation, got " + lst.size() + "."); + } + return lst.get(0); + } + + /** + * Parses the given string as a list of grouping operations. This method never returns null, it either returns a + * list of valid grouping requests or it throws an exception. + * + * @param str The string to parse. + * @return A list of grouping operations that corresponds to the string. + * @throws IllegalArgumentException Thrown if the string could not be parsed. + */ + public static List<GroupingOperation> fromStringAsList(String str) { + if (str == null || str.trim().length() == 0) { + return Collections.emptyList(); + } + GroupingParserInput input = new GroupingParserInput(str); + try { + return new GroupingParser(input).requestList(); + } catch (ParseException | TokenMgrError e) { + throw new IllegalArgumentException(input.formatException(e.getMessage()), e); + } + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/HourOfDayFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/HourOfDayFunction.java new file mode 100644 index 00000000000..5410ada6cf5 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/HourOfDayFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents an hour-of-day timestamp-function in a {@link GroupingExpression}. It evaluates to a long that + * equals the hour of day (0-23) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class HourOfDayFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public HourOfDayFunction(GroupingExpression exp) { + super("time.hourofday", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/Infinite.java b/container-search/src/main/java/com/yahoo/search/grouping/request/Infinite.java new file mode 100644 index 00000000000..dfee7d0e48a --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/Infinite.java @@ -0,0 +1,37 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an Infinite value that may be used as a bucket + * size specifier. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +@SuppressWarnings("rawtypes") +public class Infinite implements Comparable { + private final boolean negative; + + /** + * Create an Infinite object with positive or negative sign. + * @param negative the signedness. + */ + public Infinite(boolean negative) { + this.negative = negative; + } + + /** + * Override the toString method in order to be re-parseable. + */ + @Override + public String toString() { + return (negative ? "-inf" : "inf"); + } + + /** + * An infinity value is always less than or greater than. + */ + @Override + public int compareTo(Object rhs) { + return (negative ? -1 : 1); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/InfiniteValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/InfiniteValue.java new file mode 100644 index 00000000000..d20a9eb63f8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/InfiniteValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an infinite value in a {@link GroupingExpression}. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class InfiniteValue extends ConstantValue<Infinite> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public InfiniteValue(Infinite value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/InterpolatedLookup.java b/container-search/src/main/java/com/yahoo/search/grouping/request/InterpolatedLookup.java new file mode 100644 index 00000000000..a49ccdddbbc --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/InterpolatedLookup.java @@ -0,0 +1,51 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import com.google.common.annotations.Beta; + +/** + * This class represents a lookup in a multivalue document + * attribute in a {@link GroupingExpression}. It takes the + * attribute (assumed to contain a sorted array) from the input + * {@link com.yahoo.search.result.Hit} and finds the index that + * the second (lookup) argument expression would have, with linear + * interpolation when the lookup argument is between two array + * element values. + * + * @author arnej27959 + */ +@Beta +public class InterpolatedLookup extends DocumentValue { + + private final String attributeName; + private final GroupingExpression arg2; + + /** + * Constructs a new instance of this class. + * + * @param attributeName The attribute name the lookup should happen in + * @param lookupArg Expression giving a floating-point value for the lookup argument + */ + public InterpolatedLookup(String attributeName, GroupingExpression lookupArg) { + super("interpolatedlookup(" + attributeName + ", " + lookupArg + ")"); + this.attributeName = attributeName; + this.arg2 = lookupArg; + } + + /** + * Get the name of the attribute to be retrieved from the input hit. + * @return The attribute name. + */ + public String getAttributeName() { + return attributeName; + } + + /** + * Get the expression that will be evaluated before lookup. + * @return grouping expression argument + */ + public GroupingExpression getLookupArgument() { + return arg2; + } + +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/LongBucket.java b/container-search/src/main/java/com/yahoo/search/grouping/request/LongBucket.java new file mode 100644 index 00000000000..566ca31cb2e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/LongBucket.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a {@link Long} bucket in a {@link PredefinedFunction}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class LongBucket extends BucketValue { + + /** + * Gives the next distinct long value. + * + * @param value the base value. + * @return the nextt value. + */ + public static LongValue nextValue(LongValue value) { + long v = value.getValue(); + return new LongValue(v < Long.MAX_VALUE ? v + 1 : v); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public LongBucket(long from, long to) { + super(new LongValue(from), new LongValue(to)); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + @SuppressWarnings("rawtypes") + public LongBucket(ConstantValue from, ConstantValue to) { + super(from, to); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/LongPredefined.java b/container-search/src/main/java/com/yahoo/search/grouping/request/LongPredefined.java new file mode 100644 index 00000000000..486c8a9ddde --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/LongPredefined.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a predefined bucket-function in a {@link GroupingExpression} for expressions that evaluate to a + * long. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class LongPredefined extends PredefinedFunction { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @param arg1 The compulsory bucket. + * @param argN The optional buckets. + */ + public LongPredefined(GroupingExpression exp, LongBucket arg1, LongBucket... argN) { + this(exp, asList(arg1, argN)); + } + + private LongPredefined(GroupingExpression exp, List<LongBucket> args) { + super(exp, args); + } + + @Override + public LongBucket getBucket(int i) { + return (LongBucket)getArg(i + 1); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @param args The buckets to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the list of buckets is empty. + */ + public static LongPredefined newInstance(GroupingExpression exp, List<LongBucket> args) { + if (args.isEmpty()) { + throw new IllegalArgumentException("Expected at least one bucket, got none."); + } + return new LongPredefined(exp, args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/LongValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/LongValue.java new file mode 100644 index 00000000000..62a0cb01f08 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/LongValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a constant {@link Long} value in a {@link GroupingExpression}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class LongValue extends ConstantValue<Long> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public LongValue(long value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosFunction.java new file mode 100644 index 00000000000..637e0fdf57e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathACosFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathACosFunction(GroupingExpression exp) { + super("math.acos", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosHFunction.java new file mode 100644 index 00000000000..aa5677d90d4 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathACosHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathACosHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathACosHFunction(GroupingExpression exp) { + super("math.acosh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinFunction.java new file mode 100644 index 00000000000..c4b9c7a62d6 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathASinFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathASinFunction(GroupingExpression exp) { + super("math.asin", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinHFunction.java new file mode 100644 index 00000000000..f368aefe88a --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathASinHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathASinHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathASinHFunction(GroupingExpression exp) { + super("math.asinh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanFunction.java new file mode 100644 index 00000000000..ed9349c86e6 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathATanFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathATanFunction(GroupingExpression exp) { + super("math.atan", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanHFunction.java new file mode 100644 index 00000000000..ebcfd1895fa --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathATanHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathATanHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathATanHFunction(GroupingExpression exp) { + super("math.atanh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathCbrtFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCbrtFunction.java new file mode 100644 index 00000000000..78e2c3c9aa5 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCbrtFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathCbrtFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathCbrtFunction(GroupingExpression exp) { + super("math.cbrt", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosFunction.java new file mode 100644 index 00000000000..0ab35653607 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathCosFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathCosFunction(GroupingExpression exp) { + super("math.cos", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosHFunction.java new file mode 100644 index 00000000000..f4137c302e8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathCosHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathCosHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathCosHFunction(GroupingExpression exp) { + super("math.cosh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathExpFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathExpFunction.java new file mode 100644 index 00000000000..4be93d77c41 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathExpFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathExpFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathExpFunction(GroupingExpression exp) { + super("math.exp", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathFloorFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathFloorFunction.java new file mode 100644 index 00000000000..f105332e352 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathFloorFunction.java @@ -0,0 +1,16 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** represents the math.floor(expression) function */ +public class MathFloorFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathFloorFunction(GroupingExpression exp) { + super("math.floor", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathFunctions.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathFunctions.java new file mode 100644 index 00000000000..5fe5a971be9 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathFunctions.java @@ -0,0 +1,69 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public abstract class MathFunctions { + /** + * Defines the different types of math functions that are available. + */ + public enum Function { + EXP, // 0 + POW, // 1 + LOG, // 2 + LOG1P, // 3 + LOG10, // 4 + SIN, // 5 + ASIN, // 6 + COS, // 7 + ACOS, // 8 + TAN, // 9 + ATAN, // 10 + SQRT, // 11 + SINH, // 12 + ASINH, // 13 + COSH, // 14 + ACOSH, // 15 + TANH, // 16 + ATANH, // 17 + CBRT, // 18 + HYPOT, // 19 + FLOOR; // 20 + + static Function create(int tid) { + for(Function p : values()) { + if (tid == p.ordinal()) { + return p; + } + } + return null; + } + } + public static FunctionNode newInstance(Function type, GroupingExpression x, GroupingExpression y) { + switch (type) { + case EXP: return new MathExpFunction(x); + case POW: return new MathPowFunction(x, y); + case LOG: return new MathLogFunction(x); + case LOG1P: return new MathLog1pFunction(x); + case LOG10: return new MathLog10Function(x); + case SIN: return new MathSinFunction(x); + case ASIN: return new MathASinFunction(x); + case COS: return new MathCosFunction(x); + case ACOS: return new MathACosFunction(x); + case TAN: return new MathTanFunction(x); + case ATAN: return new MathATanFunction(x); + case SQRT: return new MathSqrtFunction(x); + case SINH: return new MathSinHFunction(x); + case ASINH: return new MathASinHFunction(x); + case COSH: return new MathCosHFunction(x); + case ACOSH: return new MathACosHFunction(x); + case TANH: return new MathTanHFunction(x); + case ATANH: return new MathATanHFunction(x); + case CBRT: return new MathCbrtFunction(x); + case HYPOT: return new MathHypotFunction(x, y); + case FLOOR: return new MathFloorFunction(x); + } + return null; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathHypotFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathHypotFunction.java new file mode 100644 index 00000000000..777a94f9107 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathHypotFunction.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathHypotFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param x The expression to evaluate for x, double value will be requested. + * @param y The expression to evaluate for y exponent, double value will be requested. + */ + public MathHypotFunction(GroupingExpression x, GroupingExpression y) { + super("math.hypot", Arrays.asList(x, y)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog10Function.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog10Function.java new file mode 100644 index 00000000000..444ea7a7349 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog10Function.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathLog10Function extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathLog10Function(GroupingExpression exp) { + super("math.log10", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog1pFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog1pFunction.java new file mode 100644 index 00000000000..3be6c799bf2 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLog1pFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathLog1pFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathLog1pFunction(GroupingExpression exp) { + super("math.log1p", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathLogFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLogFunction.java new file mode 100644 index 00000000000..4d3b43d45b0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathLogFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathLogFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathLogFunction(GroupingExpression exp) { + super("math.log", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathPowFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathPowFunction.java new file mode 100644 index 00000000000..09a9a28cbb0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathPowFunction.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathPowFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param x The expression to evaluate for base, double value will be requested. + * @param y The expression to evaluate for the exponent, double value will be requested. + */ + public MathPowFunction(GroupingExpression x, GroupingExpression y) { + super("math.pow", Arrays.asList(x,y)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathResolver.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathResolver.java new file mode 100644 index 00000000000..9410c6ea347 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathResolver.java @@ -0,0 +1,121 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +/** + * This is a helper class for resolving arithmetic operations over {@link GroupingExpression} objects. To resolve an + * operation simply push operator-expression pairs onto it, before calling {@link #resolve()} to retrieve the single + * corresponding grouping expression object. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MathResolver { + + public enum Type { + + ADD(0, "+"), + SUB(1, "-"), + DIV(2, "/"), + MOD(3, "%"), + MUL(4, "*"); + + private final int pre; + private final String image; + + private Type(int pre, String image) { + this.pre = pre; + this.image = image; + } + } + + private final List<Item> items = new LinkedList<>(); + + /** + * Pushes the given operator-expression pair onto this math resolver. Once all pairs have been pushed using this + * method, call {@link #resolve()} to retrieve to combined grouping expression. + * + * @param type The operator that appears before the expression being pushed. + * @param exp The expression to push. + */ + public void push(Type type, GroupingExpression exp) { + if (items.isEmpty() && type != Type.ADD) { + throw new IllegalArgumentException("First item in an arithmetic operation must be an addition."); + } + items.add(new Item(type, exp)); + } + + /** + * Converts the internal list of operator-expression pairs into a corresponding combined grouping expression. When + * this method returns there is no residue of the conversion, and this object can be reused. + * + * @return The grouping expression corresponding to the pushed arithmetic operations. + */ + public GroupingExpression resolve() { + if (items.size() == 1) { + return items.remove(0).exp; // optimize common case + } + Stack<Item> stack = new Stack<>(); + stack.push(items.remove(0)); + while (!items.isEmpty()) { + Item item = items.remove(0); + while (stack.size() > 1 && stack.peek().type.pre >= item.type.pre) { + pop(stack); + } + stack.push(item); + } + while (stack.size() > 1) { + pop(stack); + } + return stack.remove(0).exp; + } + + private void pop(Stack<Item> stack) { + Item rhs = stack.pop(); + Item lhs = stack.peek(); + switch (rhs.type) { + case ADD: + lhs.exp = new AddFunction(lhs.exp, rhs.exp); + break; + case DIV: + lhs.exp = new DivFunction(lhs.exp, rhs.exp); + break; + case MOD: + lhs.exp = new ModFunction(lhs.exp, rhs.exp); + break; + case MUL: + lhs.exp = new MulFunction(lhs.exp, rhs.exp); + break; + case SUB: + lhs.exp = new SubFunction(lhs.exp, rhs.exp); + break; + default: + throw new UnsupportedOperationException("Operator " + rhs.type + " not supported."); + } + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + for (int i = 0, len = items.size(); i < len; ++i) { + Item item = items.get(i); + if (i != 0) { + ret.append(" ").append(item.type.image).append(" "); + } + ret.append(item.exp.toString()); + } + return ret.toString(); + } + + private static class Item { + final Type type; + GroupingExpression exp; + + Item(Type type, GroupingExpression exp) { + this.type = type; + this.exp = exp; + } + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinFunction.java new file mode 100644 index 00000000000..66612e9d80a --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathSinFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathSinFunction(GroupingExpression exp) { + super("math.sin", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinHFunction.java new file mode 100644 index 00000000000..79d260f51a0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSinHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathSinHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathSinHFunction(GroupingExpression exp) { + super("math.sinh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathSqrtFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSqrtFunction.java new file mode 100644 index 00000000000..18c9396dd12 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathSqrtFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathSqrtFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathSqrtFunction(GroupingExpression exp) { + super("math.sqrt", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanFunction.java new file mode 100644 index 00000000000..67db7a9d834 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathTanFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathTanFunction(GroupingExpression exp) { + super("math.tan", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanHFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanHFunction.java new file mode 100644 index 00000000000..e111c1199d7 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MathTanHFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author balder + */ +public class MathTanHFunction extends FunctionNode { +/** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, double value will be requested. + */ + public MathTanHFunction(GroupingExpression exp) { + super("math.tanh", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MaxAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MaxAggregator.java new file mode 100644 index 00000000000..93f9e3c068e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MaxAggregator.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an maximum-aggregator in a {@link GroupingExpression}. It evaluates to the maximum value that + * the contained expression evaluated to over all the inputs. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MaxAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to aggregate on. + */ + public MaxAggregator(GroupingExpression exp) { + super("max", exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MaxFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MaxFunction.java new file mode 100644 index 00000000000..da80a627c27 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MaxFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a max-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * largest of the results of all arguments. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MaxFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public MaxFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private MaxFunction(List<GroupingExpression> args) { + super("max", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static MaxFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new MaxFunction(args); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/Md5Function.java b/container-search/src/main/java/com/yahoo/search/grouping/request/Md5Function.java new file mode 100644 index 00000000000..b2bd503c52f --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/Md5Function.java @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents an md5-function in a {@link GroupingExpression}. It evaluates to a long that equals the md5 of + * the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class Md5Function extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + * @param numBits The number of bits of the md5 to include. + */ + public Md5Function(GroupingExpression exp, int numBits) { + super("md5", Arrays.asList(exp, new LongValue(numBits))); + } + + /** + * Returns the number of bits of the md5 to include in the evaluated result. + * + * @return The bit count. + */ + public int getNumBits() { + return ((LongValue)getArg(1)).getValue().intValue(); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MinAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MinAggregator.java new file mode 100644 index 00000000000..5bb2f6675c8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MinAggregator.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an minimum-aggregator in a {@link GroupingExpression}. It evaluates to the minimum value that + * the contained expression evaluated to over all the inputs. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MinAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to aggregate on. + */ + public MinAggregator(GroupingExpression exp) { + super("min", exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MinFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MinFunction.java new file mode 100644 index 00000000000..f66e23b87c0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MinFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a min-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * smallest of the results of all arguments. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MinFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public MinFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private MinFunction(List<GroupingExpression> args) { + super("min", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static MinFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new MinFunction(args); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MinuteOfHourFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MinuteOfHourFunction.java new file mode 100644 index 00000000000..cb4b65f20b8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MinuteOfHourFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a minute-of-hour timestamp-function in a {@link GroupingExpression}. It evaluates to a long + * that equals the minute of hour (0-59) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MinuteOfHourFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public MinuteOfHourFunction(GroupingExpression exp) { + super("time.minuteofhour", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ModFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ModFunction.java new file mode 100644 index 00000000000..d3d2502b714 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ModFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a mod-function in a {@link GroupingExpression}. It evaluates to a number that equals the result + * of mod'ing the results of all arguments in the order they were given to the constructor (modulo first argument by + * second, result by third, ...). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class ModFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public ModFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private ModFunction(List<GroupingExpression> args) { + super("mod", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static ModFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new ModFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MonthOfYearFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MonthOfYearFunction.java new file mode 100644 index 00000000000..25f39892ee1 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MonthOfYearFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a month-of-year timestamp-function in a {@link GroupingExpression}. It evaluates to a long that + * equals the month of year (1-12) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MonthOfYearFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public MonthOfYearFunction(GroupingExpression exp) { + super("time.monthofyear", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/MulFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/MulFunction.java new file mode 100644 index 00000000000..d66361888b0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/MulFunction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a mul-function in a {@link GroupingExpression}. It evaluates to a number that equals the result + * of multiplying the results of all arguments together in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class MulFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public MulFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private MulFunction(List<GroupingExpression> args) { + super("mul", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static MulFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new MulFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/NegFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/NegFunction.java new file mode 100644 index 00000000000..7ea2b3a788b --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/NegFunction.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a negate-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * negative of the results of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class NegFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a number. + */ + public NegFunction(GroupingExpression exp) { + super("neg", Arrays.asList(exp)); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/NormalizeSubjectFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/NormalizeSubjectFunction.java new file mode 100644 index 00000000000..1eaad713383 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/NormalizeSubjectFunction.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + */ +public class NormalizeSubjectFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a string. + */ + public NormalizeSubjectFunction(GroupingExpression exp) { + super("normalizesubject", Arrays.asList(exp)); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/NowFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/NowFunction.java new file mode 100644 index 00000000000..f876ee9a1df --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/NowFunction.java @@ -0,0 +1,21 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Collections; + +/** + * This class represents a now-function in a {@link GroupingExpression}. It evaluates to a long that equals the number + * of seconds since midnight, January 1, 1970 UTC. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class NowFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + */ + public NowFunction() { + super("now", Collections.<GroupingExpression>emptyList()); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/OrFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/OrFunction.java new file mode 100644 index 00000000000..0a7ec7ecc06 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/OrFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents an or-function in a {@link GroupingExpression}. It evaluates to a long that equals the result + * of or'ing the results of all arguments together in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class OrFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a long. + * @param arg2 The second compulsory argument, must evaluate to a long. + * @param argN The optional arguments, must evaluate to a long. + */ + public OrFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private OrFunction(List<GroupingExpression> args) { + super("or", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static OrFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new OrFunction(args); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/PredefinedFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/PredefinedFunction.java new file mode 100644 index 00000000000..b00ee97452c --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/PredefinedFunction.java @@ -0,0 +1,58 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * This class represents a predefined bucket-function in a {@link GroupingExpression}. It maps the input into one of the + * given buckets by the result of the argument expression. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class PredefinedFunction extends FunctionNode { + + protected PredefinedFunction(GroupingExpression exp, List<? extends BucketValue> args) { + super("predefined", asList(exp, args)); + Iterator<? extends BucketValue> it = args.iterator(); + BucketValue prev = it.next(); + while (it.hasNext()) { + BucketValue arg = it.next(); + if (prev.compareTo(arg) >= 0) { + throw new IllegalArgumentException("Buckets must be monotonically increasing, got " + prev + + " before " + arg + "."); + } + prev = arg; + } + } + + /** + * Returns the number of buckets to divide the result into. + * + * @return The bucket count. + */ + public int getNumBuckets() { + return getNumArgs() - 1; + } + + /** + * Returns the bucket at the given index. + * + * @param i The index of the bucket to return. + * @return The bucket at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public BucketValue getBucket(int i) { + return (BucketValue)getArg(i + 1); + } + + private static + List<GroupingExpression> asList(GroupingExpression exp, List<? extends BucketValue> args) { + List<GroupingExpression> ret = new LinkedList<>(); + ret.add(exp); + ret.addAll(args); + return ret; + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/RawBucket.java b/container-search/src/main/java/com/yahoo/search/grouping/request/RawBucket.java new file mode 100644 index 00000000000..d13b8b6ca67 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/RawBucket.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a {@link RawValue} bucket in a {@link PredefinedFunction}. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class RawBucket extends BucketValue { + + /** + * Get the next distinct value. + * + * @param value The base value. + * @return the next value. + */ + public static RawValue nextValue(RawValue value) { + return new RawValue(value.getValue().clone().put((byte)0)); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public RawBucket(RawBuffer from, RawBuffer to) { + super(new RawValue(from), new RawValue(to)); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public RawBucket(ConstantValue<?> from, ConstantValue<?> to) { + super(from, to); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/RawBuffer.java b/container-search/src/main/java/com/yahoo/search/grouping/request/RawBuffer.java new file mode 100644 index 00000000000..00b9c899263 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/RawBuffer.java @@ -0,0 +1,123 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.ArrayList; + +/** + * This class represents a buffer of byte values to be used as a backing buffer + * for raw buckets. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class RawBuffer implements Comparable<RawBuffer>, Cloneable { + private final ArrayList<Byte> buffer; + + /** + * Create an empty buffer. + */ + public RawBuffer() { + this.buffer = new ArrayList<>(); + } + + /** + * Create a buffer with initial content. + * + * @param buffer A buffer of values to be assigned this buffer. + */ + public RawBuffer(ArrayList<Byte> buffer) { + this.buffer = buffer; + } + + /** + * Create a buffer with initial content. + * + * @param bytes A buffer of bytes to be assigned this buffer. + */ + public RawBuffer(byte[] bytes) { + buffer = new ArrayList<>(); + put(bytes); + } + + /** + * Insert a byte value into this buffer. + * + * @param value The value to add to the buffer. + * @return Reference to this. + */ + public RawBuffer put(byte value) { + buffer.add(value); + return this; + } + + /** + * Insert an array of byte values into this buffer. + * + * @param values The array to add to the buffer. + * @return Reference to this. + */ + public RawBuffer put(byte[] values) { + for (int i = 0; i < values.length; i++) { + buffer.add(values[i]); + } + return this; + } + + /** + * Create a copy of data in the internal buffer. + * + * @return A copy of the data. + */ + public byte[] getBytes() { + byte[] ret = new byte[buffer.size()]; + for (int i = 0; i < ret.length; i++) { + ret[i] = buffer.get(i); + } + return ret; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("{"); + for (int i = 0; i < buffer.size(); i++) { + s.append(buffer.get(i)); + if (i < buffer.size() - 1) { + s.append(","); + } + } + s.append("}"); + return s.toString(); + } + + @Override + public RawBuffer clone() { + return new RawBuffer(new ArrayList<>(buffer)); + } + + @Override + public int compareTo(RawBuffer rhs) { + Byte[] my = buffer.toArray(new Byte[0]); + Byte[] their = rhs.buffer.toArray(new Byte[0]); + for (int i = 0; i < my.length && i < their.length; i++) { + if (my[i] < their[i]) { + return -1; + } else if (my[i] > their[i]) { + return 1; + } + } + return (my.length < their.length ? -1 : (my.length > their.length ? 1 : 0)); + } + + @Override + public int hashCode() { + return buffer.hashCode(); + } + + @Override + public boolean equals(Object rhs) { + if (rhs instanceof RawBuffer) { + return (compareTo((RawBuffer)rhs) == 0); + } + return false; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/RawPredefined.java b/container-search/src/main/java/com/yahoo/search/grouping/request/RawPredefined.java new file mode 100644 index 00000000000..c2650346231 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/RawPredefined.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a predefined bucket-function in a {@link GroupingExpression} for expressions that evaluate to a + * raw. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class RawPredefined extends PredefinedFunction { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a string. + * @param arg1 The compulsory bucket. + * @param argN The optional buckets. + */ + public RawPredefined(GroupingExpression exp, RawBucket arg1, RawBucket... argN) { + this(exp, asList(arg1, argN)); + } + + private RawPredefined(GroupingExpression exp, List<RawBucket> args) { + super(exp, args); + } + + @Override + public RawBucket getBucket(int i) { + return (RawBucket)getArg(i + 1); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param exp The expression to evaluate, must evaluate to a string. + * @param args The buckets to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the list of buckets is empty. + */ + public static RawPredefined newInstance(GroupingExpression exp, List<RawBucket> args) { + if (args.isEmpty()) { + throw new IllegalArgumentException("Expected at least one bucket, got none."); + } + return new RawPredefined(exp, args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/RawValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/RawValue.java new file mode 100644 index 00000000000..a04944d7897 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/RawValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a raw value in a {@link GroupingExpression}. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class RawValue extends ConstantValue<RawBuffer> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public RawValue(RawBuffer value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/RelevanceValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/RelevanceValue.java new file mode 100644 index 00000000000..8a5d4dc75d1 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/RelevanceValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document relevance score in a {@link GroupingExpression}. It evaluates to the relevance of + * the input {@link com.yahoo.search.result.Hit}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class RelevanceValue extends DocumentValue { + + /** + * Constructs a new instance of this class. + */ + public RelevanceValue() { + super("relevance()"); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ReverseFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ReverseFunction.java new file mode 100644 index 00000000000..274bb20c9f7 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ReverseFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a reverse-function in a {@link GroupingExpression}. It evaluates to a list that equals the list + * result of the argument, sorted in descending order. + * + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ReverseFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a list. + */ + public ReverseFunction(GroupingExpression exp) { + super("reverse", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SecondOfMinuteFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SecondOfMinuteFunction.java new file mode 100644 index 00000000000..9443f862a16 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SecondOfMinuteFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a second-of-minute timestamp-function in a {@link GroupingExpression}. It evaluates to a long + * that equals the second of minute (0-59) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SecondOfMinuteFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public SecondOfMinuteFunction(GroupingExpression exp) { + super("time.secondofminute", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SizeFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SizeFunction.java new file mode 100644 index 00000000000..d445007a039 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SizeFunction.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a size-function in a {@link GroupingExpression}. It evaluates to a number that equals the + * number of elements in the result of the argument (e.g. the number of elements in an array). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SizeFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + */ + public SizeFunction(GroupingExpression exp) { + super("size", Arrays.asList(exp)); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SortFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SortFunction.java new file mode 100644 index 00000000000..2a8845f9847 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SortFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a sort-function in a {@link GroupingExpression}. It evaluates to a list that equals the list + * result of the argument, sorted in ascending order. + * + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class SortFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a list. + */ + public SortFunction(GroupingExpression exp) { + super("sort", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/StrCatFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/StrCatFunction.java new file mode 100644 index 00000000000..455f9dee917 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/StrCatFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a strcat-function in a {@link GroupingExpression}. It evaluates to a string that equals the + * contatenation of the string results of all arguments in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class StrCatFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a string. + * @param arg2 The second compulsory argument, must evaluate to a string. + * @param argN The optional arguments, must evaluate to a string. + */ + public StrCatFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private StrCatFunction(List<GroupingExpression> args) { + super("strcat", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static StrCatFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new StrCatFunction(args); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/StrLenFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/StrLenFunction.java new file mode 100644 index 00000000000..2ef53f53bf2 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/StrLenFunction.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a strcat-function in a {@link GroupingExpression}. It evaluates to a long that equals the + * number of bytes in the string result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class StrLenFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a string. + */ + public StrLenFunction(GroupingExpression exp) { + super("strlen", Arrays.asList(exp)); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/StringBucket.java b/container-search/src/main/java/com/yahoo/search/grouping/request/StringBucket.java new file mode 100644 index 00000000000..34c7b9f526a --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/StringBucket.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a {@link String} bucket in a {@link PredefinedFunction}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class StringBucket extends BucketValue { + + /** + * Get the next distinct value. + * + * @param value The base value. + * @return the next value. + */ + public static StringValue nextValue(StringValue value) { + return new StringValue(value.getValue() + " "); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public StringBucket(String from, String to) { + super(new StringValue(from), new StringValue(to)); + } + + /** + * Constructs a new instance of this class. + * + * @param from The from-value to assign to this. + * @param to The to-value to assign to this. + */ + public StringBucket(ConstantValue<?> from, ConstantValue<?> to) { + super(from, to); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/StringPredefined.java b/container-search/src/main/java/com/yahoo/search/grouping/request/StringPredefined.java new file mode 100644 index 00000000000..d3a469fdd7e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/StringPredefined.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a predefined bucket-function in a {@link GroupingExpression} for expressions that evaluate to a + * string. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class StringPredefined extends PredefinedFunction { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a string. + * @param arg1 The compulsory bucket. + * @param argN The optional buckets. + */ + public StringPredefined(GroupingExpression exp, StringBucket arg1, StringBucket... argN) { + this(exp, asList(arg1, argN)); + } + + private StringPredefined(GroupingExpression exp, List<StringBucket> args) { + super(exp, args); + } + + @Override + public StringBucket getBucket(int i) { + return (StringBucket)getArg(i + 1); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param exp The expression to evaluate, must evaluate to a string. + * @param args The buckets to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the list of buckets is empty. + */ + public static StringPredefined newInstance(GroupingExpression exp, List<StringBucket> args) { + if (args.isEmpty()) { + throw new IllegalArgumentException("Expected at least one bucket, got none."); + } + return new StringPredefined(exp, args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/StringValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/StringValue.java new file mode 100644 index 00000000000..87e818368d6 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/StringValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a constant {@link String} value in a {@link GroupingExpression}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class StringValue extends ConstantValue<String> { + + /** + * Constructs a new instance of this class. + * + * @param value The immutable value to assign to this. + */ + public StringValue(String value) { + super(value); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SubFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SubFunction.java new file mode 100644 index 00000000000..15e05c50f63 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SubFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents a div-function in a {@link GroupingExpression}. It evaluates to a number that equals the result + * of subtracting the results of all arguments in the order they were given to the constructor (subtract second argument + * from first, third from result, ...). + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SubFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a number. + * @param arg2 The second compulsory argument, must evaluate to a number. + * @param argN The optional arguments, must evaluate to a number. + */ + public SubFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private SubFunction(List<GroupingExpression> args) { + super("sub", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static SubFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new SubFunction(args); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SumAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SumAggregator.java new file mode 100644 index 00000000000..1ace1cfbba2 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SumAggregator.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an sum-aggregator in a {@link GroupingExpression}. It evaluates to the sum of the values that + * the contained expression evaluated to over all the inputs. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SumAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to aggregate on. + */ + public SumAggregator(GroupingExpression exp) { + super("sum", exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/SummaryValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/SummaryValue.java new file mode 100644 index 00000000000..72e4c6662d3 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/SummaryValue.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document summary in a {@link GroupingExpression}. It evaluates to the summary of the input + * {@link com.yahoo.search.result.Hit} that corresponds to the named summary class. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SummaryValue extends DocumentValue { + + private final String name; + + /** + * Constructs a new instance of this class, using the default summary class. + */ + public SummaryValue() { + super("summary()"); + name = null; + } + + /** + * Constructs a new instance of this class. + * + * @param summaryName The name of the summary class to assign to this. + */ + public SummaryValue(String summaryName) { + super("summary(" + summaryName + ")"); + name = summaryName; + } + + /** + * Returns the name of the summary class used to retrieve the hit from the search node. + * + * @return The summary name. + */ + public String getSummaryName() { + return name; + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/TimeFunctions.java b/container-search/src/main/java/com/yahoo/search/grouping/request/TimeFunctions.java new file mode 100644 index 00000000000..bde1c5831b5 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/TimeFunctions.java @@ -0,0 +1,148 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This abstract class is a factory for timestamp functions in a {@link GroupingExpression}. Apart from offering + * per-function factory methods, this class also contains a {@link #newInstance(com.yahoo.search.grouping.request.TimeFunctions.Type, + * GroupingExpression)} method which is useful for runtime construction of grouping requests. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class TimeFunctions { + + /** + * Defines the different types of timestamps-functions that are available. + */ + public enum Type { + DATE, + DAY_OF_MONTH, + DAY_OF_WEEK, + DAY_OF_YEAR, + HOUR_OF_DAY, + MINUTE_OF_HOUR, + MONTH_OF_YEAR, + SECOND_OF_MINUTE, + YEAR + } + + /** + * Creates a new timestamp-function of the specified type for the given {@link GroupingExpression}. + * + * @param type The type of function to create. + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static FunctionNode newInstance(Type type, GroupingExpression exp) { + switch (type) { + case DATE: + return newDate(exp); + case DAY_OF_MONTH: + return newDayOfMonth(exp); + case DAY_OF_WEEK: + return newDayOfWeek(exp); + case DAY_OF_YEAR: + return newDayOfYear(exp); + case HOUR_OF_DAY: + return newHourOfDay(exp); + case MINUTE_OF_HOUR: + return newMinuteOfHour(exp); + case MONTH_OF_YEAR: + return newMonthOfYear(exp); + case SECOND_OF_MINUTE: + return newSecondOfMinute(exp); + case YEAR: + return newYear(exp); + } + throw new UnsupportedOperationException("Time function '" + type + "' not supported."); + } + + /** + * Creates a new instance of {@link DateFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static DateFunction newDate(GroupingExpression exp) { + return new DateFunction(exp); + } + + /** + * Creates a new instance of {@link DayOfMonthFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static DayOfMonthFunction newDayOfMonth(GroupingExpression exp) { + return new DayOfMonthFunction(exp); + } + + /** + * Creates a new instance of {@link DayOfWeekFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static DayOfWeekFunction newDayOfWeek(GroupingExpression exp) { + return new DayOfWeekFunction(exp); + } + + /** + * Creates a new instance of {@link DayOfYearFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static DayOfYearFunction newDayOfYear(GroupingExpression exp) { + return new DayOfYearFunction(exp); + } + + /** + * Creates a new instance of {@link HourOfDayFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static HourOfDayFunction newHourOfDay(GroupingExpression exp) { + return new HourOfDayFunction(exp); + } + + /** + * Creates a new instance of {@link MinuteOfHourFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static MinuteOfHourFunction newMinuteOfHour(GroupingExpression exp) { + return new MinuteOfHourFunction(exp); + } + + /** + * Creates a new instance of {@link MonthOfYearFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static MonthOfYearFunction newMonthOfYear(GroupingExpression exp) { + return new MonthOfYearFunction(exp); + } + + /** + * Creates a new instance of {@link SecondOfMinuteFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static SecondOfMinuteFunction newSecondOfMinute(GroupingExpression exp) { + return new SecondOfMinuteFunction(exp); + } + + /** + * Creates a new instance of {@link YearFunction} for the given {@link GroupingExpression}. + * + * @param exp The expression to evaluate, must evaluate to a long. + * @return The created function node. + */ + public static YearFunction newYear(GroupingExpression exp) { + return new YearFunction(exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ToDoubleFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ToDoubleFunction.java new file mode 100644 index 00000000000..8eab2af8691 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ToDoubleFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a todouble-function in a {@link GroupingExpression}. It converts the result of the argument to + * a double. If the argument can not be converted, this function returns 0. + * + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ToDoubleFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + */ + public ToDoubleFunction(GroupingExpression exp) { + super("todouble", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ToLongFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ToLongFunction.java new file mode 100644 index 00000000000..c47a043eea0 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ToLongFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a tolong-function in a {@link GroupingExpression}. It converts the result of the argument to a + * long. If the argument can not be converted, this function returns 0. + * + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ToLongFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + */ + public ToLongFunction(GroupingExpression exp) { + super("tolong", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ToRawFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ToRawFunction.java new file mode 100644 index 00000000000..d1ba3afa28c --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ToRawFunction.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a toraw-function in a {@link GroupingExpression}. It + * converts the result of the argument to a raw type. If the argument can not + * be converted, this function returns null. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class ToRawFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + */ + public ToRawFunction(GroupingExpression exp) { + super("toraw", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ToStringFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ToStringFunction.java new file mode 100644 index 00000000000..364d9e5064d --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ToStringFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a tolong-function in a {@link GroupingExpression}. It converts the result of the argument to a + * long. If the argument can not be converted, this function returns 0. + * + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ToStringFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + */ + public ToStringFunction(GroupingExpression exp) { + super("tostring", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/UcaFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/UcaFunction.java new file mode 100644 index 00000000000..2e23f41f139 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/UcaFunction.java @@ -0,0 +1,63 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents an uca-function in a {@link GroupingExpression}. + * + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class UcaFunction extends FunctionNode { + + private final String locale; + private final String strength; + + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + * @param locale The locale to used for sorting. + */ + public UcaFunction(GroupingExpression exp, String locale) { + super("uca", Arrays.asList(exp, new StringValue(locale))); + this.locale = locale; + this.strength = "TERTIARY"; + } + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + * @param locale The locale to used for sorting. + * @param strength The strength level to use. + */ + public UcaFunction(GroupingExpression exp, String locale, String strength) { + super("uca", Arrays.asList(exp, new StringValue(locale), new StringValue(strength))); + if (!validStrength(strength)) { + throw new IllegalArgumentException("Not a valid UCA strength: " + strength); + } + this.locale = locale; + this.strength = strength; + } + + private boolean validStrength(String strength) { + return (strength.equals("PRIMARY") || + strength.equals("SECONDARY") || + strength.equals("TERTIARY") || + strength.equals("QUATERNARY") || + strength.equals("IDENTICAL")); + } + + public String getLocale() { + return locale; + } + + public String getStrength() { + return strength; + } +} + + + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/XorAggregator.java b/container-search/src/main/java/com/yahoo/search/grouping/request/XorAggregator.java new file mode 100644 index 00000000000..be0f092b929 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/XorAggregator.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents an xor-aggregator in a {@link GroupingExpression}. It evaluates to the xor of the values that + * the contained expression evaluated to over all the inputs. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class XorAggregator extends AggregatorNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to aggregate on. + */ + public XorAggregator(GroupingExpression exp) { + super("xor", exp); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/XorBitFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/XorBitFunction.java new file mode 100644 index 00000000000..304917bf905 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/XorBitFunction.java @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents an xor-function in a {@link GroupingExpression}. It evaluates to a long that equals the xor of + * 'width' bits over the binary representation of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class XorBitFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate. + * @param numBits The number of bits of the expression value to xor. + */ + public XorBitFunction(GroupingExpression exp, int numBits) { + super("xorbit", Arrays.asList(exp, new LongValue(numBits))); + } + + /** + * Returns the number of bits of the expression value to xor. + * + * @return The bit count. + */ + public int getNumBits() { + return ((LongValue)getArg(1)).getValue().intValue(); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/XorFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/XorFunction.java new file mode 100644 index 00000000000..dc47926ea51 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/XorFunction.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.List; + +/** + * This class represents an xor-function in a {@link GroupingExpression}. It evaluates to a long that equals the result + * of and'ing the results of all arguments together in the order they were given to the constructor. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class XorFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param arg1 The first compulsory argument, must evaluate to a long. + * @param arg2 The second compulsory argument, must evaluate to a long. + * @param argN The optional arguments, must evaluate to a long. + */ + public XorFunction(GroupingExpression arg1, GroupingExpression arg2, GroupingExpression... argN) { + this(asList(arg1, arg2, argN)); + } + + private XorFunction(List<GroupingExpression> args) { + super("xor", args); + } + + /** + * Constructs a new instance of this class from a list of arguments. + * + * @param args The arguments to pass to the constructor. + * @return The created instance. + * @throws IllegalArgumentException Thrown if the number of arguments is less than 2. + */ + public static XorFunction newInstance(List<GroupingExpression> args) { + if (args.size() < 2) { + throw new IllegalArgumentException("Expected 2 or more arguments, got " + args.size() + "."); + } + return new XorFunction(args); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/YearFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/YearFunction.java new file mode 100644 index 00000000000..2115d99140d --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/YearFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * This class represents a year timestamp-function in a {@link GroupingExpression}. It evaluates to a long that equals + * the full year (e.g. 2010) of the result of the argument. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class YearFunction extends FunctionNode { + + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long. + */ + public YearFunction(GroupingExpression exp) { + super("time.year", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/YmumValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/YmumValue.java new file mode 100644 index 00000000000..5754edd8155 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/YmumValue.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +/** + * This class represents a document checksum in a {@link GroupingExpression}. It evaluates to the YMUM checksum of the + * input {@link com.yahoo.search.result.Hit}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class YmumValue extends DocumentValue { + + /** + * Constructs a new instance of this class. + */ + public YmumValue() { + super("ymum()"); + } +} + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveXFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveXFunction.java new file mode 100644 index 00000000000..b4790b912e7 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveXFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ZCurveXFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long or long[]. + */ + public ZCurveXFunction(GroupingExpression exp) { + super("zcurve.x", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveYFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveYFunction.java new file mode 100644 index 00000000000..e9a011f2193 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/ZCurveYFunction.java @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request; + +import java.util.Arrays; + +/** + * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a> + */ +public class ZCurveYFunction extends FunctionNode { + /** + * Constructs a new instance of this class. + * + * @param exp The expression to evaluate, must evaluate to a long or long[]. + */ + public ZCurveYFunction(GroupingExpression exp) { + super("zcurve.y", Arrays.asList(exp)); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/package-info.java b/container-search/src/main/java/com/yahoo/search/grouping/request/package-info.java new file mode 100644 index 00000000000..ff30ef2b939 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/package-info.java @@ -0,0 +1,7 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +@PublicApi +package com.yahoo.search.grouping.request; + +import com.yahoo.api.annotations.PublicApi; +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/parser/GroupingParserInput.java b/container-search/src/main/java/com/yahoo/search/grouping/request/parser/GroupingParserInput.java new file mode 100644 index 00000000000..e87291fba18 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/grouping/request/parser/GroupingParserInput.java @@ -0,0 +1,14 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.grouping.request.parser; + +import com.yahoo.javacc.FastCharStream; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class GroupingParserInput extends FastCharStream implements CharStream { + + public GroupingParserInput(String input) { + super(input); + } +} |