diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2017-06-14 14:41:18 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2017-06-14 14:41:18 +0200 |
commit | 6ff3df19226036b8ee1bb559f9d73cab40e8d2a0 (patch) | |
tree | 355a7b0623b58983ba655b868341fe479a22eb3d /document | |
parent | b7f9e7ceaef72489d76683537973b639f8895b84 (diff) |
Remove carriage return
Diffstat (limited to 'document')
24 files changed, 2249 insertions, 2249 deletions
diff --git a/document/src/main/java/com/yahoo/document/BucketDistribution.java b/document/src/main/java/com/yahoo/document/BucketDistribution.java index bb4792b5982..28ae01dd957 100644 --- a/document/src/main/java/com/yahoo/document/BucketDistribution.java +++ b/document/src/main/java/com/yahoo/document/BucketDistribution.java @@ -1,205 +1,205 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document;
-
-import com.yahoo.document.BucketId;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class BucketDistribution {
-
- // A logger object to enable proper logging.
- private static Logger log = Logger.getLogger(BucketDistribution.class.getName());
-
- // A map from bucket id to column index.
- private int[] bucketToColumn;
-
- // The number of columns to distribute to.
- private int numColumns;
-
- // The number of bits to use for bucket identification.
- private int numBucketBits;
-
- /**
- * Constructs a new bucket distribution object with a given number of columns and buckets.
- *
- * @param numColumns The number of columns to distribute to.
- * @param numBucketBits The number of bits to use for bucket id.
- */
- public BucketDistribution(int numColumns, int numBucketBits) {
- this.numBucketBits = numBucketBits;
- bucketToColumn = new int[getNumBuckets()];
- reset();
- setNumColumns(numColumns);
- }
-
- /**
- * Constructs a new bucket distribution object as a copy of another.
- *
- * @param other The distribution object to copy.
- */
- public BucketDistribution(BucketDistribution other) {
- bucketToColumn = other.bucketToColumn.clone();
- numColumns = other.numColumns;
- numBucketBits = other.numBucketBits;
- }
-
- /**
- * Returns the number of buckets that the given number of bucket bits will allow.
- *
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The number of buckets allowed.
- */
- private static int getNumBuckets(int numBucketBits) {
- return 1 << numBucketBits;
- }
-
- /**
- * This method returns a list that contains the distributions of the given number of buckets over the given number
- * of columns.
- *
- * @param numColumns The number of columns to distribute to.
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The bucket distribution.
- */
- private static List<Integer> getBucketCount(int numColumns, int numBucketBits) {
- List<Integer> ret = new ArrayList<Integer>(numColumns);
- int cnt = getNumBuckets(numBucketBits) / numColumns;
- int rst = getNumBuckets(numBucketBits) % numColumns;
- for (int i = 0; i < numColumns; ++i) {
- ret.add(cnt + (i < rst ? 1 : 0));
- }
- return ret;
- }
-
- /**
- * This method returns a list similar to {@link BucketDistribution#getBucketCount(int, int)}, except that the returned list
- * contains the number of buckets that will have to be migrated from each column if an additional column was added.
- *
- * @param numColumns The original number of columns.
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The number of buckets to migrate, one value per column.
- */
- private static List<Integer> getBucketMigrateCount(int numColumns, int numBucketBits) {
- List<Integer> ret = getBucketCount(numColumns++, numBucketBits);
- int cnt = getNumBuckets(numBucketBits) / numColumns;
- int rst = getNumBuckets(numBucketBits) % numColumns;
- for (int i = 0; i < numColumns - 1; ++i) {
- ret.set(i, ret.get(i) - (cnt + (i < rst ? 1 : 0)));
- }
- return ret;
- }
-
- /**
- * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so
- * that it all buckets point to that single column.
- */
- public void reset() {
- for (int i = 0; i < bucketToColumn.length; ++i) {
- bucketToColumn[i] = 0;
- }
- numColumns = 1;
- }
-
- /**
- * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so
- * that it takes into account the new column.
- */
- private void addColumn() {
- int newColumns = numColumns + 1;
- List<Integer> migrate = getBucketMigrateCount(numColumns, numBucketBits);
- int numBuckets = getNumBuckets(numBucketBits);
- for (int i = 0; i < numBuckets; ++i) {
- int old = bucketToColumn[i];
- if (migrate.get(old) > 0) {
- bucketToColumn[i] = numColumns; // move this bucket to the new column
- migrate.set(old, migrate.get(old) - 1);
- }
- }
- numColumns = newColumns;
- }
-
- /**
- * Sets the number of columns to use for this document distribution object. This will reset and setup this object
- * from scratch. The original number of buckets is maintained.
- *
- * @param numColumns The new number of columns to distribute to.
- */
- public synchronized void setNumColumns(int numColumns) {
- if (numColumns < this.numColumns) {
- reset();
- }
- if (numColumns == this.numColumns) {
- return;
- }
- for (int i = numColumns - this.numColumns; --i >= 0; ) {
- addColumn();
- }
- }
-
- /**
- * Returns the number of columns to distribute to.
- *
- * @return The number of columns.
- */
- public int getNumColumns() {
- return numColumns;
- }
-
- /**
- * Sets the number of buckets to use for this document distribution object. This will reset and setup this object
- * from scratch. The original number of columns is maintained.
- *
- * @param numBucketBits The new number of bits to use for bucket id.
- */
- public synchronized void setNumBucketBits(int numBucketBits) {
- if (numBucketBits == this.numBucketBits) {
- return;
- }
- this.numBucketBits = numBucketBits;
- bucketToColumn = new int[getNumBuckets(numBucketBits)];
- int numColumns = this.numColumns;
- reset();
- setNumColumns(numColumns);
- }
-
- /**
- * Returns the number of bits used for bucket identifiers.
- *
- * @return The number of bits.
- */
- public int getNumBucketBits() {
- return numBucketBits;
- }
-
- /**
- * Returns the number of buckets available using the configured number of bucket bits.
- *
- * @return The number of buckets.
- */
- public int getNumBuckets() {
- return getNumBuckets(numBucketBits);
- }
-
- /**
- * This method maps the given bucket id to its corresponding column.
- *
- * @param bucketId The bucket whose column to lookup.
- * @return The column to distribute the bucket to.
- */
- public int getColumn(BucketId bucketId) {
- int ret = (int)(bucketId.getId() & (getNumBuckets(numBucketBits) - 1));
- if (ret >= bucketToColumn.length) {
- log.log(Level.SEVERE,
- "The bucket distribution map is not in sync with the number of bucket bits. " +
- "This should never happen! Distribution is broken!!");
- return 0;
- }
- return bucketToColumn[ret];
- }
-}
+package com.yahoo.document; + +import com.yahoo.document.BucketId; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class BucketDistribution { + + // A logger object to enable proper logging. + private static Logger log = Logger.getLogger(BucketDistribution.class.getName()); + + // A map from bucket id to column index. + private int[] bucketToColumn; + + // The number of columns to distribute to. + private int numColumns; + + // The number of bits to use for bucket identification. + private int numBucketBits; + + /** + * Constructs a new bucket distribution object with a given number of columns and buckets. + * + * @param numColumns The number of columns to distribute to. + * @param numBucketBits The number of bits to use for bucket id. + */ + public BucketDistribution(int numColumns, int numBucketBits) { + this.numBucketBits = numBucketBits; + bucketToColumn = new int[getNumBuckets()]; + reset(); + setNumColumns(numColumns); + } + + /** + * Constructs a new bucket distribution object as a copy of another. + * + * @param other The distribution object to copy. + */ + public BucketDistribution(BucketDistribution other) { + bucketToColumn = other.bucketToColumn.clone(); + numColumns = other.numColumns; + numBucketBits = other.numBucketBits; + } + + /** + * Returns the number of buckets that the given number of bucket bits will allow. + * + * @param numBucketBits The number of bits to use for bucket id. + * @return The number of buckets allowed. + */ + private static int getNumBuckets(int numBucketBits) { + return 1 << numBucketBits; + } + + /** + * This method returns a list that contains the distributions of the given number of buckets over the given number + * of columns. + * + * @param numColumns The number of columns to distribute to. + * @param numBucketBits The number of bits to use for bucket id. + * @return The bucket distribution. + */ + private static List<Integer> getBucketCount(int numColumns, int numBucketBits) { + List<Integer> ret = new ArrayList<Integer>(numColumns); + int cnt = getNumBuckets(numBucketBits) / numColumns; + int rst = getNumBuckets(numBucketBits) % numColumns; + for (int i = 0; i < numColumns; ++i) { + ret.add(cnt + (i < rst ? 1 : 0)); + } + return ret; + } + + /** + * This method returns a list similar to {@link BucketDistribution#getBucketCount(int, int)}, except that the returned list + * contains the number of buckets that will have to be migrated from each column if an additional column was added. + * + * @param numColumns The original number of columns. + * @param numBucketBits The number of bits to use for bucket id. + * @return The number of buckets to migrate, one value per column. + */ + private static List<Integer> getBucketMigrateCount(int numColumns, int numBucketBits) { + List<Integer> ret = getBucketCount(numColumns++, numBucketBits); + int cnt = getNumBuckets(numBucketBits) / numColumns; + int rst = getNumBuckets(numBucketBits) % numColumns; + for (int i = 0; i < numColumns - 1; ++i) { + ret.set(i, ret.get(i) - (cnt + (i < rst ? 1 : 0))); + } + return ret; + } + + /** + * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so + * that it all buckets point to that single column. + */ + public void reset() { + for (int i = 0; i < bucketToColumn.length; ++i) { + bucketToColumn[i] = 0; + } + numColumns = 1; + } + + /** + * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so + * that it takes into account the new column. + */ + private void addColumn() { + int newColumns = numColumns + 1; + List<Integer> migrate = getBucketMigrateCount(numColumns, numBucketBits); + int numBuckets = getNumBuckets(numBucketBits); + for (int i = 0; i < numBuckets; ++i) { + int old = bucketToColumn[i]; + if (migrate.get(old) > 0) { + bucketToColumn[i] = numColumns; // move this bucket to the new column + migrate.set(old, migrate.get(old) - 1); + } + } + numColumns = newColumns; + } + + /** + * Sets the number of columns to use for this document distribution object. This will reset and setup this object + * from scratch. The original number of buckets is maintained. + * + * @param numColumns The new number of columns to distribute to. + */ + public synchronized void setNumColumns(int numColumns) { + if (numColumns < this.numColumns) { + reset(); + } + if (numColumns == this.numColumns) { + return; + } + for (int i = numColumns - this.numColumns; --i >= 0; ) { + addColumn(); + } + } + + /** + * Returns the number of columns to distribute to. + * + * @return The number of columns. + */ + public int getNumColumns() { + return numColumns; + } + + /** + * Sets the number of buckets to use for this document distribution object. This will reset and setup this object + * from scratch. The original number of columns is maintained. + * + * @param numBucketBits The new number of bits to use for bucket id. + */ + public synchronized void setNumBucketBits(int numBucketBits) { + if (numBucketBits == this.numBucketBits) { + return; + } + this.numBucketBits = numBucketBits; + bucketToColumn = new int[getNumBuckets(numBucketBits)]; + int numColumns = this.numColumns; + reset(); + setNumColumns(numColumns); + } + + /** + * Returns the number of bits used for bucket identifiers. + * + * @return The number of bits. + */ + public int getNumBucketBits() { + return numBucketBits; + } + + /** + * Returns the number of buckets available using the configured number of bucket bits. + * + * @return The number of buckets. + */ + public int getNumBuckets() { + return getNumBuckets(numBucketBits); + } + + /** + * This method maps the given bucket id to its corresponding column. + * + * @param bucketId The bucket whose column to lookup. + * @return The column to distribute the bucket to. + */ + public int getColumn(BucketId bucketId) { + int ret = (int)(bucketId.getId() & (getNumBuckets(numBucketBits) - 1)); + if (ret >= bucketToColumn.length) { + log.log(Level.SEVERE, + "The bucket distribution map is not in sync with the number of bucket bits. " + + "This should never happen! Distribution is broken!!"); + return 0; + } + return bucketToColumn[ret]; + } +} diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java index 96a3fadc66c..3e911afb305 100644 --- a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java +++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java @@ -52,4 +52,4 @@ public class RemoveFieldPathUpdate extends FieldPathUpdate { public String toString() { return "Remove: " + super.toString(); } -}
\ No newline at end of file +} diff --git a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java index 1c5e6efdda6..36dbacfcde1 100644 --- a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java +++ b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java @@ -407,4 +407,4 @@ public class DocumentUpdateJsonSerializer return this; } } -}
\ No newline at end of file +} diff --git a/document/src/main/java/com/yahoo/document/select/BucketSet.java b/document/src/main/java/com/yahoo/document/select/BucketSet.java index e7bb4ac7807..286c66969d9 100644 --- a/document/src/main/java/com/yahoo/document/select/BucketSet.java +++ b/document/src/main/java/com/yahoo/document/select/BucketSet.java @@ -1,72 +1,72 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select;
-
-import com.yahoo.document.BucketId;
-
-import java.util.HashSet;
-
-/**
- * A set of bucket ids covered by a document selector.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class BucketSet extends HashSet<BucketId> {
-
- /**
- * Constructs a new bucket set that contains no ids.
- */
- public BucketSet() {
- // empty
- }
-
- /**
- * Constructs a new bucket set that contains a single id.
- *
- * @param id The id to add to this as initial value.
- */
- public BucketSet(BucketId id) {
- add(id);
- }
-
- /**
- * Constructs a new bucket set that is a copy of another.
- *
- * @param set The set to copy.
- */
- public BucketSet(BucketSet set) {
- this.addAll(set);
- }
-
- /**
- * Returns the intersection between this bucket set and another.
- *
- * @param rhs The set to form an intersection with.
- * @return The intersection.
- */
- public BucketSet intersection(BucketSet rhs) {
- if (rhs == null) {
- return new BucketSet(this); // The other has all buckets marked, this is the smaller.
- } else {
- BucketSet ret = new BucketSet(this);
- ret.retainAll(rhs);
- return ret;
- }
- }
-
- /**
- * Returns the union between this bucket set and another.
- *
- * @param rhs The set to form a union with.
- * @return The union.
- */
- public BucketSet union(BucketSet rhs) {
- if (rhs == null) {
- return null;
- } else {
- BucketSet ret = new BucketSet(this);
- ret.addAll(rhs);
- return ret;
- }
- }
-
-}
+package com.yahoo.document.select; + +import com.yahoo.document.BucketId; + +import java.util.HashSet; + +/** + * A set of bucket ids covered by a document selector. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class BucketSet extends HashSet<BucketId> { + + /** + * Constructs a new bucket set that contains no ids. + */ + public BucketSet() { + // empty + } + + /** + * Constructs a new bucket set that contains a single id. + * + * @param id The id to add to this as initial value. + */ + public BucketSet(BucketId id) { + add(id); + } + + /** + * Constructs a new bucket set that is a copy of another. + * + * @param set The set to copy. + */ + public BucketSet(BucketSet set) { + this.addAll(set); + } + + /** + * Returns the intersection between this bucket set and another. + * + * @param rhs The set to form an intersection with. + * @return The intersection. + */ + public BucketSet intersection(BucketSet rhs) { + if (rhs == null) { + return new BucketSet(this); // The other has all buckets marked, this is the smaller. + } else { + BucketSet ret = new BucketSet(this); + ret.retainAll(rhs); + return ret; + } + } + + /** + * Returns the union between this bucket set and another. + * + * @param rhs The set to form a union with. + * @return The union. + */ + public BucketSet union(BucketSet rhs) { + if (rhs == null) { + return null; + } else { + BucketSet ret = new BucketSet(this); + ret.addAll(rhs); + return ret; + } + } + +} diff --git a/document/src/main/java/com/yahoo/document/select/Result.java b/document/src/main/java/com/yahoo/document/select/Result.java index 3f1fa75d4ef..e0b8f02c47b 100644 --- a/document/src/main/java/com/yahoo/document/select/Result.java +++ b/document/src/main/java/com/yahoo/document/select/Result.java @@ -1,53 +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.document.select;
-
-import com.yahoo.document.select.rule.AttributeNode;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public enum Result {
-
- /**
- * Defines all enumeration constants.
- */
- TRUE,
- FALSE,
- INVALID;
-
- // Inherit doc from Object.
- public String toString() {
- return name().toLowerCase();
- }
-
- /**
- * Inverts the result value to the appropriate value. True → False, False → True and Invalid → Invalid.
- * @return inverted result
- */
- public static Result invert(Result result) {
- if (result == Result.TRUE) return Result.FALSE;
- if (result == Result.FALSE) return Result.TRUE;
- return Result.INVALID;
- }
-
- /**
- * Converts the given object value into an instance of this Result enumeration.
- *
- * @param value The object to convert.
- * @return The corresponding result value.
- */
- public static Result toResult(Object value) {
- if (value == null || value == Result.FALSE || value == Boolean.FALSE ||
- (Number.class.isInstance(value) && ((Number)value).doubleValue() == 0)) {
- return Result.FALSE;
- } else if (value == INVALID) {
- return Result.INVALID;
- } else if (value instanceof AttributeNode.VariableValueList) {
- return ((AttributeNode.VariableValueList)value).isEmpty() ? Result.FALSE : Result.TRUE;
- } else if (value instanceof ResultList) {
- return ((ResultList)value).toResult();
- } else {
- return Result.TRUE;
- }
- }
-}
+package com.yahoo.document.select; + +import com.yahoo.document.select.rule.AttributeNode; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public enum Result { + + /** + * Defines all enumeration constants. + */ + TRUE, + FALSE, + INVALID; + + // Inherit doc from Object. + public String toString() { + return name().toLowerCase(); + } + + /** + * Inverts the result value to the appropriate value. True → False, False → True and Invalid → Invalid. + * @return inverted result + */ + public static Result invert(Result result) { + if (result == Result.TRUE) return Result.FALSE; + if (result == Result.FALSE) return Result.TRUE; + return Result.INVALID; + } + + /** + * Converts the given object value into an instance of this Result enumeration. + * + * @param value The object to convert. + * @return The corresponding result value. + */ + public static Result toResult(Object value) { + if (value == null || value == Result.FALSE || value == Boolean.FALSE || + (Number.class.isInstance(value) && ((Number)value).doubleValue() == 0)) { + return Result.FALSE; + } else if (value == INVALID) { + return Result.INVALID; + } else if (value instanceof AttributeNode.VariableValueList) { + return ((AttributeNode.VariableValueList)value).isEmpty() ? Result.FALSE : Result.TRUE; + } else if (value instanceof ResultList) { + return ((ResultList)value).toResult(); + } else { + return Result.TRUE; + } + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java b/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java index 2fe4609b4e6..3bb558c2eb2 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java @@ -1,209 +1,209 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.datatypes.NumericFieldValue;
-import com.yahoo.document.select.*;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Stack;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class ArithmeticNode implements ExpressionNode {
-
- public static final int NOP = 0;
- public static final int ADD = 1;
- public static final int SUB = 2;
- public static final int MOD = 3;
- public static final int DIV = 4;
- public static final int MUL = 5;
-
- private final List<NodeItem> items = new ArrayList<NodeItem>();
-
- public ArithmeticNode() {
- // empty
- }
-
- public ArithmeticNode add(String operator, ExpressionNode node) {
- items.add(new NodeItem(stringToOperator(operator), node));
- return this;
- }
-
- public List<NodeItem> getItems() {
- return items;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- StringBuilder ret = null;
- Stack<ValueItem> buf = new Stack<ValueItem>();
- for (int i = 0; i < items.size(); ++i) {
- NodeItem item = items.get(i);
- Object val = item.node.evaluate(context);
-
- if (val == null) {
- throw new IllegalStateException("Null value found!");
- }
-
- if (val instanceof AttributeNode.VariableValueList) {
- AttributeNode.VariableValueList value = (AttributeNode.VariableValueList)val;
- if (value.size() == 0) {
- throw new IllegalArgumentException("Can not perform arithmetic on missing field: "
- + item.node.toString());
- } else if (value.size() != 1) {
- throw new IllegalStateException("Arithmetic is only valid for single values.");
- } else {
- val = value.get(0).getValue();
- }
- }
-
- if (val instanceof NumericFieldValue) {
- val = ((NumericFieldValue)val).getNumber();
- }
-
- if (val instanceof String) {
- if (i == 0) {
- ret = new StringBuilder();
- }
- if (ret != null) {
- ret.append(val);
- continue;
- }
- } else if (Number.class.isInstance(val)) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- popOffTheTop(buf);
- }
- }
- buf.push(new ValueItem(item.operator, (Number)val));
- continue;
- }
- throw new IllegalStateException("Term '" + item.node + " with class " + val.getClass() + "' does not evaluate to a number.");
- }
- if (ret != null) {
- return ret.toString();
- }
- while (buf.size() > 1) {
- popOffTheTop(buf);
- }
- return buf.pop().value;
- }
-
- private void popOffTheTop(Stack<ValueItem> buf) {
- ValueItem rhs = buf.pop();
- ValueItem lhs = buf.pop();
- switch (rhs.operator) {
- case ADD:
- lhs.value = lhs.value.doubleValue() + rhs.value.doubleValue();
- break;
- case SUB:
- lhs.value = lhs.value.doubleValue() - rhs.value.doubleValue();
- break;
- case DIV:
- lhs.value = lhs.value.doubleValue() / rhs.value.doubleValue();
- break;
- case MUL:
- lhs.value = lhs.value.doubleValue() * rhs.value.doubleValue();
- break;
- case MOD:
- lhs.value = lhs.value.longValue() % rhs.value.longValue();
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- buf.push(lhs);
- }
-
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- for (NodeItem item : items) {
- if (item.operator != NOP) {
- ret.append(" ").append(operatorToString(item.operator)).append(" ");
- }
- ret.append(item.node);
- }
- return ret.toString();
- }
-
- public String operatorToString(int operator) {
- switch (operator) {
- case NOP:
- return null;
- case ADD:
- return "+";
- case SUB:
- return "-";
- case MOD:
- return "%";
- case DIV:
- return "/";
- case MUL:
- return "*";
- default:
- throw new IllegalStateException("Arithmetic operator " + operator + " not supported.");
- }
- }
-
- private int stringToOperator(String operator) {
- if (operator == null) {
- return NOP;
- } else if (operator.equals("+")) {
- return ADD;
- } else if (operator.equals("-")) {
- return SUB;
- } else if (operator.equals("%")) {
- return MOD;
- } else if (operator.equals("/")) {
- return DIV;
- } else if (operator.equals("*")) {
- return MUL;
- } else {
- throw new IllegalStateException("Arithmetic operator '" + operator + "' not supported.");
- }
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- private class ValueItem {
- public int operator;
- public Number value;
-
- public ValueItem(int operator, Number value) {
- this.operator = operator;
- this.value = value;
- }
- }
-
- public static class NodeItem {
- private int operator;
- private ExpressionNode node;
-
- public NodeItem(int operator, ExpressionNode node) {
- this.operator = operator;
- this.node = node;
- }
-
- public int getOperator() {
- return operator;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.datatypes.NumericFieldValue; +import com.yahoo.document.select.*; + +import java.util.List; +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class ArithmeticNode implements ExpressionNode { + + public static final int NOP = 0; + public static final int ADD = 1; + public static final int SUB = 2; + public static final int MOD = 3; + public static final int DIV = 4; + public static final int MUL = 5; + + private final List<NodeItem> items = new ArrayList<NodeItem>(); + + public ArithmeticNode() { + // empty + } + + public ArithmeticNode add(String operator, ExpressionNode node) { + items.add(new NodeItem(stringToOperator(operator), node)); + return this; + } + + public List<NodeItem> getItems() { + return items; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + StringBuilder ret = null; + Stack<ValueItem> buf = new Stack<ValueItem>(); + for (int i = 0; i < items.size(); ++i) { + NodeItem item = items.get(i); + Object val = item.node.evaluate(context); + + if (val == null) { + throw new IllegalStateException("Null value found!"); + } + + if (val instanceof AttributeNode.VariableValueList) { + AttributeNode.VariableValueList value = (AttributeNode.VariableValueList)val; + if (value.size() == 0) { + throw new IllegalArgumentException("Can not perform arithmetic on missing field: " + + item.node.toString()); + } else if (value.size() != 1) { + throw new IllegalStateException("Arithmetic is only valid for single values."); + } else { + val = value.get(0).getValue(); + } + } + + if (val instanceof NumericFieldValue) { + val = ((NumericFieldValue)val).getNumber(); + } + + if (val instanceof String) { + if (i == 0) { + ret = new StringBuilder(); + } + if (ret != null) { + ret.append(val); + continue; + } + } else if (Number.class.isInstance(val)) { + if (!buf.isEmpty()) { + while (buf.peek().operator > item.operator) { + popOffTheTop(buf); + } + } + buf.push(new ValueItem(item.operator, (Number)val)); + continue; + } + throw new IllegalStateException("Term '" + item.node + " with class " + val.getClass() + "' does not evaluate to a number."); + } + if (ret != null) { + return ret.toString(); + } + while (buf.size() > 1) { + popOffTheTop(buf); + } + return buf.pop().value; + } + + private void popOffTheTop(Stack<ValueItem> buf) { + ValueItem rhs = buf.pop(); + ValueItem lhs = buf.pop(); + switch (rhs.operator) { + case ADD: + lhs.value = lhs.value.doubleValue() + rhs.value.doubleValue(); + break; + case SUB: + lhs.value = lhs.value.doubleValue() - rhs.value.doubleValue(); + break; + case DIV: + lhs.value = lhs.value.doubleValue() / rhs.value.doubleValue(); + break; + case MUL: + lhs.value = lhs.value.doubleValue() * rhs.value.doubleValue(); + break; + case MOD: + lhs.value = lhs.value.longValue() % rhs.value.longValue(); + break; + default: + throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported."); + } + buf.push(lhs); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + for (NodeItem item : items) { + if (item.operator != NOP) { + ret.append(" ").append(operatorToString(item.operator)).append(" "); + } + ret.append(item.node); + } + return ret.toString(); + } + + public String operatorToString(int operator) { + switch (operator) { + case NOP: + return null; + case ADD: + return "+"; + case SUB: + return "-"; + case MOD: + return "%"; + case DIV: + return "/"; + case MUL: + return "*"; + default: + throw new IllegalStateException("Arithmetic operator " + operator + " not supported."); + } + } + + private int stringToOperator(String operator) { + if (operator == null) { + return NOP; + } else if (operator.equals("+")) { + return ADD; + } else if (operator.equals("-")) { + return SUB; + } else if (operator.equals("%")) { + return MOD; + } else if (operator.equals("/")) { + return DIV; + } else if (operator.equals("*")) { + return MUL; + } else { + throw new IllegalStateException("Arithmetic operator '" + operator + "' not supported."); + } + } + + public OrderingSpecification getOrdering(int order) { + return null; + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + private class ValueItem { + public int operator; + public Number value; + + public ValueItem(int operator, Number value) { + this.operator = operator; + this.value = value; + } + } + + public static class NodeItem { + private int operator; + private ExpressionNode node; + + public NodeItem(int operator, ExpressionNode node) { + this.operator = operator; + this.node = node; + } + + public int getOperator() { + return operator; + } + + public ExpressionNode getNode() { + return node; + } + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java b/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java index 048eb70ac94..7e51834d871 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java @@ -1,205 +1,205 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.collections.BobHash;
-import com.yahoo.document.*;
-import com.yahoo.document.datatypes.FieldPathIteratorHandler;
-import com.yahoo.document.datatypes.FieldValue;
-import com.yahoo.document.select.*;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class AttributeNode implements ExpressionNode {
-
- private ExpressionNode value;
- private final List<Item> items = new ArrayList<Item>();
-
- public AttributeNode(ExpressionNode value, List items) {
- this.value = value;
- for (Object obj : items) {
- if (obj instanceof Item) {
- this.items.add((Item)obj);
- } else {
- throw new IllegalStateException("Can not add an instance of " + obj.getClass().getName() +
- " as a function item.");
- }
- }
- }
-
- public ExpressionNode getValue() {
- return value;
- }
-
- public AttributeNode setValue(ExpressionNode value) {
- this.value = value;
- return this;
- }
-
- public List<Item> getItems() {
- return items;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- String pos = value.toString();
- Object obj = value.evaluate(context);
-
- StringBuilder builder = new StringBuilder();
- for (Item item : items) {
- if (obj == null) {
- throw new IllegalStateException("Can not invoke '" + item + "' on '" + pos + "' because that term " +
- "evaluated to null.");
- }
- if (item.getType() != Item.FUNCTION) {
- if (builder.length() > 0) {
- builder.append(".");
- }
-
- builder.append(item.getName());
- } else {
- if (builder.length() > 0) {
- obj = evaluateFieldPath(builder.toString(), obj);
- builder = new StringBuilder();
- }
-
- obj = evaluateFunction(item.getName(), obj);
- }
-
- pos = pos + "." + item;
- }
-
- if (builder.length() > 0) {
- obj = evaluateFieldPath(builder.toString(), obj);
- }
- return obj;
- }
-
- public static class VariableValueList extends ArrayList<ResultList.VariableValue> {
-
- }
-
- static class IteratorHandler extends FieldPathIteratorHandler {
- VariableValueList values = new VariableValueList();
-
- @Override
- public void onPrimitive(FieldValue fv) {
- values.add(new ResultList.VariableValue((VariableMap)getVariables().clone(), fv));
- }
- }
-
- private static Object applyFunction(String function, Object value) {
- if (function.equalsIgnoreCase("abs")) {
- if (Number.class.isInstance(value)) {
- Number nValue = (Number)value;
- if (value instanceof Double) {
- return nValue.doubleValue() * (nValue.doubleValue() < 0 ? -1 : 1);
- } else if (value instanceof Float) {
- return nValue.floatValue() * (nValue.floatValue() < 0 ? -1 : 1);
- } else if (value instanceof Long) {
- return nValue.longValue() * (nValue.longValue() < 0 ? -1 : 1);
- } else if (value instanceof Integer) {
- return nValue.intValue() * (nValue.intValue() < 0 ? -1 : 1);
- }
- }
- throw new IllegalStateException("Function 'abs' is only available for numerical values.");
- } else if (function.equalsIgnoreCase("hash")) {
- return BobHash.hash(value.toString());
- } else if (function.equalsIgnoreCase("lowercase")) {
- return value.toString().toLowerCase();
- } else if (function.equalsIgnoreCase("uppercase")) {
- return value.toString().toUpperCase();
- }
- throw new IllegalStateException("Function '" + function + "' is not supported.");
- }
-
- private static Object evaluateFieldPath(String fieldPth, Object value) {
- if (value instanceof DocumentPut) {
- final Document doc = ((DocumentPut) value).getDocument();
- FieldPath fieldPath = doc.getDataType().buildFieldPath(fieldPth);
- IteratorHandler handler = new IteratorHandler();
- doc.iterateNested(fieldPath, 0, handler);
- return handler.values;
- } else if (value instanceof DocumentUpdate) {
- return Result.INVALID;
- }
- return Result.FALSE;
- //throw new IllegalStateException("Attributes are only available for document types for value '" + value + "'. Looking for " + fieldPth);
- }
-
- private static Object evaluateFunction(String function, Object value) {
- if (value instanceof VariableValueList) {
- VariableValueList retVal = new VariableValueList();
-
- for (ResultList.VariableValue val : ((VariableValueList)value)) {
- retVal.add(new ResultList.VariableValue(
- (FieldPathIteratorHandler.VariableMap)val.getVariables().clone(),
- applyFunction(function, val.getValue())));
- }
-
- return retVal;
- }
-
- return applyFunction(function, value);
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- ret.append(value);
- for (Item item : items) {
- ret.append(".").append(item);
- }
- return ret.toString();
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public static class Item {
- public static final int ATTRIBUTE = 0;
- public static final int FUNCTION = 1;
-
- private String name;
- private int type = ATTRIBUTE;
-
- public Item(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public Item setName(String name) {
- this.name = name;
- return this;
- }
-
- public int getType() {
- return type;
- }
-
- public Item setType(int type) {
- this.type = type;
- return this;
- }
-
- @Override public String toString() {
- return name + (type == FUNCTION ? "()" : "");
- }
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.collections.BobHash; +import com.yahoo.document.*; +import com.yahoo.document.datatypes.FieldPathIteratorHandler; +import com.yahoo.document.datatypes.FieldValue; +import com.yahoo.document.select.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class AttributeNode implements ExpressionNode { + + private ExpressionNode value; + private final List<Item> items = new ArrayList<Item>(); + + public AttributeNode(ExpressionNode value, List items) { + this.value = value; + for (Object obj : items) { + if (obj instanceof Item) { + this.items.add((Item)obj); + } else { + throw new IllegalStateException("Can not add an instance of " + obj.getClass().getName() + + " as a function item."); + } + } + } + + public ExpressionNode getValue() { + return value; + } + + public AttributeNode setValue(ExpressionNode value) { + this.value = value; + return this; + } + + public List<Item> getItems() { + return items; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + String pos = value.toString(); + Object obj = value.evaluate(context); + + StringBuilder builder = new StringBuilder(); + for (Item item : items) { + if (obj == null) { + throw new IllegalStateException("Can not invoke '" + item + "' on '" + pos + "' because that term " + + "evaluated to null."); + } + if (item.getType() != Item.FUNCTION) { + if (builder.length() > 0) { + builder.append("."); + } + + builder.append(item.getName()); + } else { + if (builder.length() > 0) { + obj = evaluateFieldPath(builder.toString(), obj); + builder = new StringBuilder(); + } + + obj = evaluateFunction(item.getName(), obj); + } + + pos = pos + "." + item; + } + + if (builder.length() > 0) { + obj = evaluateFieldPath(builder.toString(), obj); + } + return obj; + } + + public static class VariableValueList extends ArrayList<ResultList.VariableValue> { + + } + + static class IteratorHandler extends FieldPathIteratorHandler { + VariableValueList values = new VariableValueList(); + + @Override + public void onPrimitive(FieldValue fv) { + values.add(new ResultList.VariableValue((VariableMap)getVariables().clone(), fv)); + } + } + + private static Object applyFunction(String function, Object value) { + if (function.equalsIgnoreCase("abs")) { + if (Number.class.isInstance(value)) { + Number nValue = (Number)value; + if (value instanceof Double) { + return nValue.doubleValue() * (nValue.doubleValue() < 0 ? -1 : 1); + } else if (value instanceof Float) { + return nValue.floatValue() * (nValue.floatValue() < 0 ? -1 : 1); + } else if (value instanceof Long) { + return nValue.longValue() * (nValue.longValue() < 0 ? -1 : 1); + } else if (value instanceof Integer) { + return nValue.intValue() * (nValue.intValue() < 0 ? -1 : 1); + } + } + throw new IllegalStateException("Function 'abs' is only available for numerical values."); + } else if (function.equalsIgnoreCase("hash")) { + return BobHash.hash(value.toString()); + } else if (function.equalsIgnoreCase("lowercase")) { + return value.toString().toLowerCase(); + } else if (function.equalsIgnoreCase("uppercase")) { + return value.toString().toUpperCase(); + } + throw new IllegalStateException("Function '" + function + "' is not supported."); + } + + private static Object evaluateFieldPath(String fieldPth, Object value) { + if (value instanceof DocumentPut) { + final Document doc = ((DocumentPut) value).getDocument(); + FieldPath fieldPath = doc.getDataType().buildFieldPath(fieldPth); + IteratorHandler handler = new IteratorHandler(); + doc.iterateNested(fieldPath, 0, handler); + return handler.values; + } else if (value instanceof DocumentUpdate) { + return Result.INVALID; + } + return Result.FALSE; + //throw new IllegalStateException("Attributes are only available for document types for value '" + value + "'. Looking for " + fieldPth); + } + + private static Object evaluateFunction(String function, Object value) { + if (value instanceof VariableValueList) { + VariableValueList retVal = new VariableValueList(); + + for (ResultList.VariableValue val : ((VariableValueList)value)) { + retVal.add(new ResultList.VariableValue( + (FieldPathIteratorHandler.VariableMap)val.getVariables().clone(), + applyFunction(function, val.getValue()))); + } + + return retVal; + } + + return applyFunction(function, value); + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append(value); + for (Item item : items) { + ret.append(".").append(item); + } + return ret.toString(); + } + + public OrderingSpecification getOrdering(int order) { + return null; + } + + public static class Item { + public static final int ATTRIBUTE = 0; + public static final int FUNCTION = 1; + + private String name; + private int type = ATTRIBUTE; + + public Item(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Item setName(String name) { + this.name = name; + return this; + } + + public int getType() { + return type; + } + + public Item setType(int type) { + this.type = type; + return this; + } + + @Override public String toString() { + return name + (type == FUNCTION ? "()" : ""); + } + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java b/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java index b0d5030978e..9db5ff0384b 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java @@ -1,435 +1,435 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketId;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.DocumentId;
-import com.yahoo.document.datatypes.FieldPathIteratorHandler;
-import com.yahoo.document.datatypes.NumericFieldValue;
-import com.yahoo.document.idstring.GroupDocIdString;
-import com.yahoo.document.select.*;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class ComparisonNode implements ExpressionNode {
-
- // The left- and right-hand-side of this comparison.
- private ExpressionNode lhs, rhs;
-
- // The operator string for this.
- private String operator;
-
- /**
- * Constructs a new comparison node.
- *
- * @param lhs The left-hand-side of the comparison.
- * @param operator The comparison operator.
- * @param rhs The right-hand-side of the comparison.
- */
- public ComparisonNode(ExpressionNode lhs, String operator, ExpressionNode rhs) {
- this.lhs = lhs;
- this.operator = operator;
- this.rhs = rhs;
- }
-
- /**
- * Returns the left hand side of this comparison.
- *
- * @return The left hand side expression.
- */
- public ExpressionNode getLHS() {
- return lhs;
- }
-
- /**
- * Sets the left hand side of this comparison.
- *
- * @param lhs The new left hand side.
- * @return This, to allow chaining.
- */
- public ComparisonNode setLHS(ExpressionNode lhs) {
- this.lhs = lhs;
- return this;
- }
-
- /**
- * Returns the comparison operator of this.
- *
- * @return The operator.
- */
- public String getOperator() {
- return operator;
- }
-
- /**
- * Sets the comparison operator of this.
- *
- * @param operator The operator string.
- * @return This, to allow chaining.
- */
- public ComparisonNode setOperator(String operator) {
- this.operator = operator;
- return this;
- }
-
- /**
- * Returns the right hand side of this comparison.
- *
- * @return The right hand side expression.
- */
- public ExpressionNode getRHS() {
- return rhs;
- }
-
- /**
- * Sets the right hand side of this comparison.
- *
- * @param rhs The new right hand side.
- * @return This, to allow chaining.
- */
- public ComparisonNode setRHS(ExpressionNode rhs) {
- this.rhs = rhs;
- return this;
- }
-
- public OrderingSpecification getOrdering(IdNode lhs, LiteralNode rhs, String operator, int order) {
- if (lhs.getWidthBits() == -1 || lhs.getDivisionBits() == -1 || !(rhs.getValue() instanceof Long)) {
- return null;
- }
-
- if (operator.equals("==") || operator.equals("=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
-
- if (order == OrderingSpecification.ASCENDING) {
- if ((operator.equals("<") || operator.equals("<="))) {
- return new OrderingSpecification(order, 0, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals(">")) {
- return new OrderingSpecification(order, (Long)rhs.getValue() + 1, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals(">=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
- } else {
- if (operator.equals("<")) {
- return new OrderingSpecification(order, (Long)rhs.getValue() - 1, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals("<=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
- }
- return null;
- }
-
- public OrderingSpecification getOrdering(int order) {
- if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
- return getOrdering((IdNode)lhs, (LiteralNode)rhs, operator, order);
- } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
- return getOrdering((IdNode)rhs, (LiteralNode)rhs, operator, order);
- }
-
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- if (operator.equals("==") || operator.equals("=")) {
- if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
- return compare(factory, (IdNode)lhs, (LiteralNode)rhs, operator);
- } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
- return compare(factory, (IdNode)rhs, (LiteralNode)lhs, operator);
- } else if (lhs instanceof SearchColumnNode && rhs instanceof LiteralNode) {
- return compare(factory, (SearchColumnNode)lhs, (LiteralNode)rhs);
- } else if (rhs instanceof SearchColumnNode && lhs instanceof LiteralNode) {
- return compare(factory, (SearchColumnNode)rhs, (LiteralNode)lhs);
- }
- }
- return null;
- }
-
- /**
- * Compares a search column node with a literal node.
- *
- * @param factory The bucket id factory used.
- * @param node The search column node.
- * @param literal The literal node to compare to.
- * @return The bucket set containing the buckets covered.
- */
- private BucketSet compare(BucketIdFactory factory, SearchColumnNode node, LiteralNode literal) {
- Object value = literal.getValue();
- int bucketCount = (int) Math.pow(2, 16);
- if (value instanceof Long) {
- BucketSet ret = new BucketSet();
- for (int i = 0; i < bucketCount; i++) {
- BucketId id = new BucketId(16, i);
- if ((Long)value == node.getDistribution().getColumn(id)) {
- ret.add(new BucketId(16, i));
- }
- }
- return ret;
- }
- return null;
- }
-
- private BucketSet compare(BucketIdFactory factory, IdNode id, LiteralNode literal, String operator) {
- String field = id.getField();
- Object value = literal.getValue();
- if (field == null) {
- if (value instanceof String) {
- String name = (String)value;
- if ((operator.equals("=") && name.contains("*")) ||
- (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
- {
- return null; // no idea
- }
- return new BucketSet(factory.getBucketId(new DocumentId(name)));
- }
- } else if (field.equalsIgnoreCase("user")) {
- if (value instanceof Long) {
- return new BucketSet(new BucketId(factory.getLocationBitCount(), (Long)value));
- }
- } else if (field.equalsIgnoreCase("group")) {
- if (value instanceof String) {
- String name = (String)value;
- if ((operator.equals("=") && name.contains("*")) ||
- (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
- {
- return null; // no idea
- }
- return new BucketSet(new BucketId(factory.getLocationBitCount(), new GroupDocIdString("", name, "").getLocation()));
- }
- } else if (field.equalsIgnoreCase("bucket")) {
- if (value instanceof Long) {
- return new BucketSet(new BucketId((Long)value));
- }
- }
- return null;
- }
-
- // Inherit doc from Node.
- public Object evaluate(Context context) {
- Object oLeft = lhs.evaluate(context);
- Object oRight = rhs.evaluate(context);
- if (oLeft == null && oRight == null) {
- return new ResultList(Result.TRUE);
- }
- if (oLeft == Result.INVALID || oRight == Result.INVALID) {
- return new ResultList(Result.INVALID);
- }
- if (oLeft instanceof AttributeNode.VariableValueList && oRight instanceof AttributeNode.VariableValueList) {
- if (operator.equals("==")) {
- return evaluateListsTrue((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
- } else if (operator.equals("!=")) {
- return evaluateListsFalse((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
- } else {
- return new ResultList(Result.INVALID);
- }
- } else if (oLeft instanceof AttributeNode.VariableValueList) {
- return evaluateListAndSingle((AttributeNode.VariableValueList)oLeft, oRight);
- } else if (oRight instanceof AttributeNode.VariableValueList) {
- return evaluateListAndSingle((AttributeNode.VariableValueList)oRight, oLeft);
- }
- return new ResultList(evaluateBool(oLeft, oRight));
- }
-
- public ResultList evaluateListsTrue(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
- if (lhs.size() != rhs.size()) {
- return new ResultList(Result.FALSE);
- }
-
- for (int i = 0; i < lhs.size(); i++) {
- if (!lhs.get(i).getVariables().equals(rhs.get(i).getVariables())) {
- return new ResultList(Result.FALSE);
- }
-
- if (evaluateEquals(lhs.get(i).getValue(), rhs.get(i).getValue()) == Result.FALSE) {
- return new ResultList(Result.FALSE);
- }
- }
-
- return new ResultList(Result.TRUE);
- }
-
- public ResultList evaluateListsFalse(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
- ResultList lst = evaluateListsTrue(lhs, rhs);
- if (lst.toResult() == Result.TRUE) {
- return new ResultList(Result.FALSE);
- } else if (lst.toResult() == Result.FALSE) {
- return new ResultList(Result.TRUE);
- } else {
- return lst;
- }
- }
-
- public ResultList evaluateListAndSingle(AttributeNode.VariableValueList lhs, Object rhs) {
- if (rhs == null && lhs == null) {
- return new ResultList(Result.TRUE);
- }
-
- if (rhs == null || lhs == null) {
- return new ResultList(Result.FALSE);
- }
-
- ResultList retVal = new ResultList();
- for (int i = 0; i < lhs.size(); i++) {
- Result result = evaluateBool(lhs.get(i).getValue(), rhs);
- retVal.add((FieldPathIteratorHandler.VariableMap)lhs.get(i).getVariables().clone(), result);
- }
-
- return retVal;
- }
-
- /**
- * Evaluate this expression on two operands, given that they are not invalid.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateBool(Object lhs, Object rhs) {
- if (operator.equals("==")) {
- return evaluateEquals(lhs, rhs);
- } else if (operator.equals("!=")) {
- return Result.invert(evaluateEquals(lhs, rhs));
- } else if (operator.equals("<") || operator.equals("<=") ||
- operator.equals(">") || operator.equals(">=")) {
- return evaluateNumber(lhs, rhs);
- } else if (operator.equals("=~") || operator.equals("=")) {
- return evaluateString(lhs, rhs);
- }
- throw new IllegalStateException("Comparison operator '" + operator + "' is not supported.");
- }
-
- /**
- * Compare two operands for equality.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return Wether or not the two operands are equal.
- */
- private Result evaluateEquals(Object lhs, Object rhs) {
- if (lhs == null || rhs == null) {
- return Result.toResult(lhs == rhs);
- }
-
- double a = getAsNumber(lhs);
- double b = getAsNumber(rhs);
- if (Double.isNaN(a) || Double.isNaN(b)) {
- return Result.toResult(lhs.toString().equals(rhs.toString()));
- }
- return Result.toResult(a == b); // Ugh, comparing doubles? Should be converted to long value perhaps...
- }
-
- private double getAsNumber(Object value) {
- if (value instanceof Number) {
- return ((Number)value).doubleValue();
- } else if (value instanceof NumericFieldValue) {
- return getAsNumber(((NumericFieldValue)value).getNumber());
- } else {
- return Double.NaN; //new IllegalStateException("Term '" + value + "' (" + value.getClass() + ") does not evaluate to a number.");
- }
- }
-
- /**
- * Evalutes the value of this term over a document, given that both operands must be numbers.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateNumber(Object lhs, Object rhs) {
- double a = getAsNumber(lhs);
- double b = getAsNumber(rhs);
- if (Double.isNaN(a) || Double.isNaN(b)) {
- return Result.INVALID;
- }
- if (operator.equals("<")) {
- return Result.toResult(a < b);
- } else if (operator.equals("<=")) {
- return Result.toResult(a <= b);
- } else if (operator.equals(">")) {
- return Result.toResult(a > b);
- } else {
- return Result.toResult(a >= b);
- }
- }
-
- /**
- * Evalutes the value of this term over a document, given that both operands must be strings.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateString(Object lhs, Object rhs) {
- String left = "" + lhs; // Allows null objects to evaluate to string.
- String right = "" + rhs;
- if (operator.equals("=~")) {
- return Result.toResult(Pattern.compile(right).matcher(left).find());
- } else {
- return Result.toResult(Pattern.compile(globToRegex(right)).matcher(left).find());
- }
- }
-
- /**
- * Converts a glob pattern to a corresponding regular expression string.
- *
- * @param glob The glob pattern.
- * @return The regex string.
- */
- private String globToRegex(String glob) {
- StringBuilder ret = new StringBuilder();
- ret.append("^");
- for (int i = 0; i < glob.length(); i++) {
- ret.append(globToRegex(glob.charAt(i)));
- }
- ret.append("$");
-
- return ret.toString();
- }
-
- /**
- * Converts a single character in a glob expression to the corresponding regular expression string.
- *
- * @param glob The glob character.
- * @return The regex string.
- */
- private String globToRegex(char glob) {
- switch (glob) {
- case'*':
- return ".*";
- case'?':
- return ".";
- case'^':
- case'$':
- case'|':
- case'{':
- case'}':
- case'(':
- case')':
- case'[':
- case']':
- case'\\':
- case'+':
- case'.':
- return "\\" + glob;
- default:
- return "" + glob;
- }
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- // Inherit doc from Object.
- @Override
- public String toString() {
- return lhs + " " + operator + " " + rhs;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketId; +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.DocumentId; +import com.yahoo.document.datatypes.FieldPathIteratorHandler; +import com.yahoo.document.datatypes.NumericFieldValue; +import com.yahoo.document.idstring.GroupDocIdString; +import com.yahoo.document.select.*; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class ComparisonNode implements ExpressionNode { + + // The left- and right-hand-side of this comparison. + private ExpressionNode lhs, rhs; + + // The operator string for this. + private String operator; + + /** + * Constructs a new comparison node. + * + * @param lhs The left-hand-side of the comparison. + * @param operator The comparison operator. + * @param rhs The right-hand-side of the comparison. + */ + public ComparisonNode(ExpressionNode lhs, String operator, ExpressionNode rhs) { + this.lhs = lhs; + this.operator = operator; + this.rhs = rhs; + } + + /** + * Returns the left hand side of this comparison. + * + * @return The left hand side expression. + */ + public ExpressionNode getLHS() { + return lhs; + } + + /** + * Sets the left hand side of this comparison. + * + * @param lhs The new left hand side. + * @return This, to allow chaining. + */ + public ComparisonNode setLHS(ExpressionNode lhs) { + this.lhs = lhs; + return this; + } + + /** + * Returns the comparison operator of this. + * + * @return The operator. + */ + public String getOperator() { + return operator; + } + + /** + * Sets the comparison operator of this. + * + * @param operator The operator string. + * @return This, to allow chaining. + */ + public ComparisonNode setOperator(String operator) { + this.operator = operator; + return this; + } + + /** + * Returns the right hand side of this comparison. + * + * @return The right hand side expression. + */ + public ExpressionNode getRHS() { + return rhs; + } + + /** + * Sets the right hand side of this comparison. + * + * @param rhs The new right hand side. + * @return This, to allow chaining. + */ + public ComparisonNode setRHS(ExpressionNode rhs) { + this.rhs = rhs; + return this; + } + + public OrderingSpecification getOrdering(IdNode lhs, LiteralNode rhs, String operator, int order) { + if (lhs.getWidthBits() == -1 || lhs.getDivisionBits() == -1 || !(rhs.getValue() instanceof Long)) { + return null; + } + + if (operator.equals("==") || operator.equals("=")) { + return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits()); + } + + if (order == OrderingSpecification.ASCENDING) { + if ((operator.equals("<") || operator.equals("<="))) { + return new OrderingSpecification(order, 0, lhs.getWidthBits(), lhs.getDivisionBits()); + } + if (operator.equals(">")) { + return new OrderingSpecification(order, (Long)rhs.getValue() + 1, lhs.getWidthBits(), lhs.getDivisionBits()); + } + if (operator.equals(">=")) { + return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits()); + } + } else { + if (operator.equals("<")) { + return new OrderingSpecification(order, (Long)rhs.getValue() - 1, lhs.getWidthBits(), lhs.getDivisionBits()); + } + if (operator.equals("<=")) { + return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits()); + } + } + return null; + } + + public OrderingSpecification getOrdering(int order) { + if (lhs instanceof IdNode && rhs instanceof LiteralNode) { + return getOrdering((IdNode)lhs, (LiteralNode)rhs, operator, order); + } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) { + return getOrdering((IdNode)rhs, (LiteralNode)rhs, operator, order); + } + + return null; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + if (operator.equals("==") || operator.equals("=")) { + if (lhs instanceof IdNode && rhs instanceof LiteralNode) { + return compare(factory, (IdNode)lhs, (LiteralNode)rhs, operator); + } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) { + return compare(factory, (IdNode)rhs, (LiteralNode)lhs, operator); + } else if (lhs instanceof SearchColumnNode && rhs instanceof LiteralNode) { + return compare(factory, (SearchColumnNode)lhs, (LiteralNode)rhs); + } else if (rhs instanceof SearchColumnNode && lhs instanceof LiteralNode) { + return compare(factory, (SearchColumnNode)rhs, (LiteralNode)lhs); + } + } + return null; + } + + /** + * Compares a search column node with a literal node. + * + * @param factory The bucket id factory used. + * @param node The search column node. + * @param literal The literal node to compare to. + * @return The bucket set containing the buckets covered. + */ + private BucketSet compare(BucketIdFactory factory, SearchColumnNode node, LiteralNode literal) { + Object value = literal.getValue(); + int bucketCount = (int) Math.pow(2, 16); + if (value instanceof Long) { + BucketSet ret = new BucketSet(); + for (int i = 0; i < bucketCount; i++) { + BucketId id = new BucketId(16, i); + if ((Long)value == node.getDistribution().getColumn(id)) { + ret.add(new BucketId(16, i)); + } + } + return ret; + } + return null; + } + + private BucketSet compare(BucketIdFactory factory, IdNode id, LiteralNode literal, String operator) { + String field = id.getField(); + Object value = literal.getValue(); + if (field == null) { + if (value instanceof String) { + String name = (String)value; + if ((operator.equals("=") && name.contains("*")) || + (operator.equals("=~") && ((name.contains("*") || name.contains("?"))))) + { + return null; // no idea + } + return new BucketSet(factory.getBucketId(new DocumentId(name))); + } + } else if (field.equalsIgnoreCase("user")) { + if (value instanceof Long) { + return new BucketSet(new BucketId(factory.getLocationBitCount(), (Long)value)); + } + } else if (field.equalsIgnoreCase("group")) { + if (value instanceof String) { + String name = (String)value; + if ((operator.equals("=") && name.contains("*")) || + (operator.equals("=~") && ((name.contains("*") || name.contains("?"))))) + { + return null; // no idea + } + return new BucketSet(new BucketId(factory.getLocationBitCount(), new GroupDocIdString("", name, "").getLocation())); + } + } else if (field.equalsIgnoreCase("bucket")) { + if (value instanceof Long) { + return new BucketSet(new BucketId((Long)value)); + } + } + return null; + } + + // Inherit doc from Node. + public Object evaluate(Context context) { + Object oLeft = lhs.evaluate(context); + Object oRight = rhs.evaluate(context); + if (oLeft == null && oRight == null) { + return new ResultList(Result.TRUE); + } + if (oLeft == Result.INVALID || oRight == Result.INVALID) { + return new ResultList(Result.INVALID); + } + if (oLeft instanceof AttributeNode.VariableValueList && oRight instanceof AttributeNode.VariableValueList) { + if (operator.equals("==")) { + return evaluateListsTrue((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight); + } else if (operator.equals("!=")) { + return evaluateListsFalse((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight); + } else { + return new ResultList(Result.INVALID); + } + } else if (oLeft instanceof AttributeNode.VariableValueList) { + return evaluateListAndSingle((AttributeNode.VariableValueList)oLeft, oRight); + } else if (oRight instanceof AttributeNode.VariableValueList) { + return evaluateListAndSingle((AttributeNode.VariableValueList)oRight, oLeft); + } + return new ResultList(evaluateBool(oLeft, oRight)); + } + + public ResultList evaluateListsTrue(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) { + if (lhs.size() != rhs.size()) { + return new ResultList(Result.FALSE); + } + + for (int i = 0; i < lhs.size(); i++) { + if (!lhs.get(i).getVariables().equals(rhs.get(i).getVariables())) { + return new ResultList(Result.FALSE); + } + + if (evaluateEquals(lhs.get(i).getValue(), rhs.get(i).getValue()) == Result.FALSE) { + return new ResultList(Result.FALSE); + } + } + + return new ResultList(Result.TRUE); + } + + public ResultList evaluateListsFalse(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) { + ResultList lst = evaluateListsTrue(lhs, rhs); + if (lst.toResult() == Result.TRUE) { + return new ResultList(Result.FALSE); + } else if (lst.toResult() == Result.FALSE) { + return new ResultList(Result.TRUE); + } else { + return lst; + } + } + + public ResultList evaluateListAndSingle(AttributeNode.VariableValueList lhs, Object rhs) { + if (rhs == null && lhs == null) { + return new ResultList(Result.TRUE); + } + + if (rhs == null || lhs == null) { + return new ResultList(Result.FALSE); + } + + ResultList retVal = new ResultList(); + for (int i = 0; i < lhs.size(); i++) { + Result result = evaluateBool(lhs.get(i).getValue(), rhs); + retVal.add((FieldPathIteratorHandler.VariableMap)lhs.get(i).getVariables().clone(), result); + } + + return retVal; + } + + /** + * Evaluate this expression on two operands, given that they are not invalid. + * + * @param lhs Left hand side of operation. + * @param rhs Right hand side of operation. + * @return The evaluation result. + */ + private Result evaluateBool(Object lhs, Object rhs) { + if (operator.equals("==")) { + return evaluateEquals(lhs, rhs); + } else if (operator.equals("!=")) { + return Result.invert(evaluateEquals(lhs, rhs)); + } else if (operator.equals("<") || operator.equals("<=") || + operator.equals(">") || operator.equals(">=")) { + return evaluateNumber(lhs, rhs); + } else if (operator.equals("=~") || operator.equals("=")) { + return evaluateString(lhs, rhs); + } + throw new IllegalStateException("Comparison operator '" + operator + "' is not supported."); + } + + /** + * Compare two operands for equality. + * + * @param lhs Left hand side of operation. + * @param rhs Right hand side of operation. + * @return Wether or not the two operands are equal. + */ + private Result evaluateEquals(Object lhs, Object rhs) { + if (lhs == null || rhs == null) { + return Result.toResult(lhs == rhs); + } + + double a = getAsNumber(lhs); + double b = getAsNumber(rhs); + if (Double.isNaN(a) || Double.isNaN(b)) { + return Result.toResult(lhs.toString().equals(rhs.toString())); + } + return Result.toResult(a == b); // Ugh, comparing doubles? Should be converted to long value perhaps... + } + + private double getAsNumber(Object value) { + if (value instanceof Number) { + return ((Number)value).doubleValue(); + } else if (value instanceof NumericFieldValue) { + return getAsNumber(((NumericFieldValue)value).getNumber()); + } else { + return Double.NaN; //new IllegalStateException("Term '" + value + "' (" + value.getClass() + ") does not evaluate to a number."); + } + } + + /** + * Evalutes the value of this term over a document, given that both operands must be numbers. + * + * @param lhs Left hand side of operation. + * @param rhs Right hand side of operation. + * @return The evaluation result. + */ + private Result evaluateNumber(Object lhs, Object rhs) { + double a = getAsNumber(lhs); + double b = getAsNumber(rhs); + if (Double.isNaN(a) || Double.isNaN(b)) { + return Result.INVALID; + } + if (operator.equals("<")) { + return Result.toResult(a < b); + } else if (operator.equals("<=")) { + return Result.toResult(a <= b); + } else if (operator.equals(">")) { + return Result.toResult(a > b); + } else { + return Result.toResult(a >= b); + } + } + + /** + * Evalutes the value of this term over a document, given that both operands must be strings. + * + * @param lhs Left hand side of operation. + * @param rhs Right hand side of operation. + * @return The evaluation result. + */ + private Result evaluateString(Object lhs, Object rhs) { + String left = "" + lhs; // Allows null objects to evaluate to string. + String right = "" + rhs; + if (operator.equals("=~")) { + return Result.toResult(Pattern.compile(right).matcher(left).find()); + } else { + return Result.toResult(Pattern.compile(globToRegex(right)).matcher(left).find()); + } + } + + /** + * Converts a glob pattern to a corresponding regular expression string. + * + * @param glob The glob pattern. + * @return The regex string. + */ + private String globToRegex(String glob) { + StringBuilder ret = new StringBuilder(); + ret.append("^"); + for (int i = 0; i < glob.length(); i++) { + ret.append(globToRegex(glob.charAt(i))); + } + ret.append("$"); + + return ret.toString(); + } + + /** + * Converts a single character in a glob expression to the corresponding regular expression string. + * + * @param glob The glob character. + * @return The regex string. + */ + private String globToRegex(char glob) { + switch (glob) { + case'*': + return ".*"; + case'?': + return "."; + case'^': + case'$': + case'|': + case'{': + case'}': + case'(': + case')': + case'[': + case']': + case'\\': + case'+': + case'.': + return "\\" + glob; + default: + return "" + glob; + } + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + // Inherit doc from Object. + @Override + public String toString() { + return lhs + " " + operator + " " + rhs; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java b/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java index c071e6674aa..2b095db16c9 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java @@ -1,65 +1,65 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.*;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class DocumentNode implements ExpressionNode {
-
- private String type;
-
- public DocumentNode(String type) {
- this.type = type;
- }
-
- public String getType() {
- return type;
- }
-
- public DocumentNode setType(String type) {
- this.type = type;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- return evaluate(context.getDocumentOperation());
- }
-
- public Object evaluate(DocumentOperation op) {
- DocumentType doct;
- if (op instanceof DocumentPut) {
- doct = ((DocumentPut)op).getDocument().getDataType();
- } else if (op instanceof DocumentUpdate) {
- doct = ((DocumentUpdate)op).getDocumentType();
- } else {
- throw new IllegalStateException("Document class '" + op.getClass().getName() + "' is not supported.");
- }
- return doct.isA(this.type) ? op : Boolean.FALSE;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return type;
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.*; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Visitor; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class DocumentNode implements ExpressionNode { + + private String type; + + public DocumentNode(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public DocumentNode setType(String type) { + this.type = type; + return this; + } + + @Override + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + @Override + public Object evaluate(Context context) { + return evaluate(context.getDocumentOperation()); + } + + public Object evaluate(DocumentOperation op) { + DocumentType doct; + if (op instanceof DocumentPut) { + doct = ((DocumentPut)op).getDocument().getDataType(); + } else if (op instanceof DocumentUpdate) { + doct = ((DocumentUpdate)op).getDocumentType(); + } else { + throw new IllegalStateException("Document class '" + op.getClass().getName() + "' is not supported."); + } + return doct.isA(this.type) ? op : Boolean.FALSE; + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return type; + } + + @Override + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java b/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java index 13b20695cab..12192af7607 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java @@ -1,51 +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.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class EmbracedNode implements ExpressionNode {
-
- private ExpressionNode node;
-
- public EmbracedNode(ExpressionNode node) {
- this.node = node;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
-
- public EmbracedNode setNode(ExpressionNode node) {
- this.node = node;
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return node.getBucketSet(factory);
- }
-
- public Object evaluate(Context context) {
- return node.evaluate(context);
- }
-
- @Override
- public String toString() {
- return "(" + node + ")";
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Visitor; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class EmbracedNode implements ExpressionNode { + + private ExpressionNode node; + + public EmbracedNode(ExpressionNode node) { + this.node = node; + } + + public ExpressionNode getNode() { + return node; + } + + public EmbracedNode setNode(ExpressionNode node) { + this.node = node; + return this; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return node.getBucketSet(factory); + } + + public Object evaluate(Context context) { + return node.evaluate(context); + } + + @Override + public String toString() { + return "(" + node + ")"; + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java b/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java index ba51ec840d4..d84259f2643 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java @@ -1,48 +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.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * This is the interface of all expression nodes. It declares the methods requires by all expression nodes to maintain
- * a working document selector language.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public interface ExpressionNode {
-
- /**
- * Evaluate the content of this node based on document object, and return that value.
- *
- * @param doc The document to evaluate over.
- * @return The value of this.
- */
- public Object evaluate(Context doc);
-
- /**
- * Returns the set of bucket ids covered by this node.
- *
- * @param factory The factory used by the current application.
- */
- public BucketSet getBucketSet(BucketIdFactory factory);
-
- /**
- * If this document selection implies a specific ordering (using the orderdoc scheme),
- * return that specification.
- *
- * @param order The order in which we are looking to traverse the ordering (ASCENDING or DESCENDING)
- */
- public OrderingSpecification getOrdering(int order);
-
- /**
- * Perform visitation of this node.
- *
- * @param visitor The visitor that wishes to visit the node.
- */
- public void accept(Visitor visitor);
-
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Visitor; + +/** + * This is the interface of all expression nodes. It declares the methods requires by all expression nodes to maintain + * a working document selector language. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public interface ExpressionNode { + + /** + * Evaluate the content of this node based on document object, and return that value. + * + * @param doc The document to evaluate over. + * @return The value of this. + */ + public Object evaluate(Context doc); + + /** + * Returns the set of bucket ids covered by this node. + * + * @param factory The factory used by the current application. + */ + public BucketSet getBucketSet(BucketIdFactory factory); + + /** + * If this document selection implies a specific ordering (using the orderdoc scheme), + * return that specification. + * + * @param order The order in which we are looking to traverse the ordering (ASCENDING or DESCENDING) + */ + public OrderingSpecification getOrdering(int order); + + /** + * Perform visitation of this node. + * + * @param visitor The visitor that wishes to visit the node. + */ + public void accept(Visitor visitor); + +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/IdNode.java b/document/src/main/java/com/yahoo/document/select/rule/IdNode.java index f12ecbb752b..75b4890af80 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/IdNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/IdNode.java @@ -1,108 +1,108 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.DocumentId;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-import com.yahoo.document.idstring.*;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class IdNode implements ExpressionNode {
-
- private String field;
- private short widthBits = -1;
- private short divisionBits = -1;
-
- public IdNode() {
- // empty
- }
-
- public String getField() {
- return field;
- }
-
- public IdNode setField(String field) {
- this.field = field;
- return this;
- }
-
- public IdNode setWidthBits(short widthBits) {
- this.widthBits = widthBits;
- return this;
- }
-
- public IdNode setDivisionBits(short divisionBits) {
- this.divisionBits = divisionBits;
- return this;
- }
-
- public short getWidthBits() {
- return widthBits;
- }
-
- public short getDivisionBits() {
- return divisionBits;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- public OrderingSpecification getOrdering(int ordering) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- DocumentId id = context.getDocumentOperation().getId();
- if (id == null) {
- throw new IllegalStateException("Document has no identifier.");
- }
- if (field == null) {
- return id.toString();
- } else if (field.equalsIgnoreCase("scheme")) {
- return id.getScheme().getType().toString();
- } else if (field.equalsIgnoreCase("namespace")) {
- return id.getScheme().getNamespace();
- } else if (field.equalsIgnoreCase("specific")) {
- return id.getScheme().getNamespaceSpecific();
- } else if (field.equalsIgnoreCase("group")) {
- if (id.getScheme().hasGroup()) {
- return id.getScheme().getGroup();
- }
- throw new IllegalStateException("Group identifier is null.");
- } else if (field.equalsIgnoreCase("user")) {
- if (id.getScheme().hasNumber()) {
- return id.getScheme().getNumber();
- }
- throw new IllegalStateException("User identifier is null.");
- } else if (field.equalsIgnoreCase("type")) {
- if (id.getScheme().hasDocType()) {
- return id.getScheme().getDocType();
- }
- throw new IllegalStateException("Document id doesn't have doc type.");
- } else if (field.equalsIgnoreCase("order")) {
- if (id.getScheme() instanceof OrderDocIdString) {
- OrderDocIdString ods = (OrderDocIdString)id.getScheme();
- if (ods.getWidthBits() == widthBits && ods.getDivisionBits() == divisionBits) {
- return ods.getOrdering();
- }
- }
- } else{
- throw new IllegalStateException("Identifier field '" + field + "' is not supported.");
- }
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "id" + (field != null ? "." + field : "") + (widthBits != -1 ? "(" + widthBits + "," + divisionBits + ")" : "");
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.DocumentId; +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.*; +import com.yahoo.document.idstring.*; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class IdNode implements ExpressionNode { + + private String field; + private short widthBits = -1; + private short divisionBits = -1; + + public IdNode() { + // empty + } + + public String getField() { + return field; + } + + public IdNode setField(String field) { + this.field = field; + return this; + } + + public IdNode setWidthBits(short widthBits) { + this.widthBits = widthBits; + return this; + } + + public IdNode setDivisionBits(short divisionBits) { + this.divisionBits = divisionBits; + return this; + } + + public short getWidthBits() { + return widthBits; + } + + public short getDivisionBits() { + return divisionBits; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + public OrderingSpecification getOrdering(int ordering) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + DocumentId id = context.getDocumentOperation().getId(); + if (id == null) { + throw new IllegalStateException("Document has no identifier."); + } + if (field == null) { + return id.toString(); + } else if (field.equalsIgnoreCase("scheme")) { + return id.getScheme().getType().toString(); + } else if (field.equalsIgnoreCase("namespace")) { + return id.getScheme().getNamespace(); + } else if (field.equalsIgnoreCase("specific")) { + return id.getScheme().getNamespaceSpecific(); + } else if (field.equalsIgnoreCase("group")) { + if (id.getScheme().hasGroup()) { + return id.getScheme().getGroup(); + } + throw new IllegalStateException("Group identifier is null."); + } else if (field.equalsIgnoreCase("user")) { + if (id.getScheme().hasNumber()) { + return id.getScheme().getNumber(); + } + throw new IllegalStateException("User identifier is null."); + } else if (field.equalsIgnoreCase("type")) { + if (id.getScheme().hasDocType()) { + return id.getScheme().getDocType(); + } + throw new IllegalStateException("Document id doesn't have doc type."); + } else if (field.equalsIgnoreCase("order")) { + if (id.getScheme() instanceof OrderDocIdString) { + OrderDocIdString ods = (OrderDocIdString)id.getScheme(); + if (ods.getWidthBits() == widthBits && ods.getDivisionBits() == divisionBits) { + return ods.getOrdering(); + } + } + } else{ + throw new IllegalStateException("Identifier field '" + field + "' is not supported."); + } + return null; + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "id" + (field != null ? "." + field : "") + (widthBits != -1 ? "(" + widthBits + "," + divisionBits + ")" : ""); + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java b/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java index ae0d640d471..702026b59d3 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java @@ -1,61 +1,61 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-import com.yahoo.document.select.parser.SelectParserUtils;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class LiteralNode implements ExpressionNode {
-
- private Object value;
-
- public LiteralNode(Object value) {
- this.value = value;
- }
-
- public Object getValue() {
- return value;
- }
-
- public LiteralNode setValue(Object value) {
- this.value = value;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- return value;
- }
-
- @Override
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- if (value == null) {
- return "null";
- } else if (value instanceof String) {
- return SelectParserUtils.quote((String)value, '"');
- } else {
- return value.toString();
- }
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Visitor; +import com.yahoo.document.select.parser.SelectParserUtils; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class LiteralNode implements ExpressionNode { + + private Object value; + + public LiteralNode(Object value) { + this.value = value; + } + + public Object getValue() { + return value; + } + + public LiteralNode setValue(Object value) { + this.value = value; + return this; + } + + @Override + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + @Override + public Object evaluate(Context context) { + return value; + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + if (value == null) { + return "null"; + } else if (value instanceof String) { + return SelectParserUtils.quote((String)value, '"'); + } else { + return value.toString(); + } + } + + @Override + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java b/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java index 145c655fae2..edff3a0adaa 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java @@ -1,316 +1,316 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.ResultList;
-import com.yahoo.document.select.Visitor;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Stack;
-
-/**
- * This class defines a logical expression of nodes. This implementation uses a stack to evaluate its content as to
- * avoid deep recursions when building the parse tree.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class LogicNode implements ExpressionNode {
-
- // A no-op value is defined for completeness.
- public static final int NOP = 0;
-
- // The OR operator has lower precedence than AND.
- public static final int OR = 1;
-
- // The AND operator has the highest precedence.
- public static final int AND = 2;
-
- // The items contained in this.
- private final List<NodeItem> items = new ArrayList<NodeItem>();
-
- /**
- * Construct an empty logic expression.
- */
- public LogicNode() {
- // empty
- }
-
- public List<NodeItem> getItems() {
- return items;
- }
-
- /**
- * Adds an (operator, node) pair to this expression.
- *
- * @param operator The operator that combines the previous with the node given.
- * @param node The node to add to this.
- * @return This, to allow chaining.
- */
- public LogicNode add(String operator, ExpressionNode node) {
- items.add(new LogicNode.NodeItem(stringToOperator(operator), node));
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- Stack<BucketItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- combineBuckets(buf);
- }
- }
- buf.push(new BucketItem(item.operator, item.node.getBucketSet(factory)));
- }
- while (buf.size() > 1) {
- combineBuckets(buf);
- }
- return buf.pop().buckets;
- }
-
- public OrderingSpecification getOrdering(int order) {
- Stack<OrderingItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- pickOrdering(buf);
- }
- }
- buf.push(new OrderingItem(item.operator, item.node.getOrdering(order)));
- }
- while (buf.size() > 1) {
- pickOrdering(buf);
- }
- return buf.pop().ordering;
- }
-
- private OrderingSpecification pickOrdering(OrderingSpecification a, OrderingSpecification b, boolean isAnd) {
- if (a.getWidthBits() == b.getWidthBits() && a.getDivisionBits() == b.getDivisionBits() && a.getOrder() == b.getOrder()) {
- if ((a.getOrder() == OrderingSpecification.ASCENDING && isAnd) ||
- (a.getOrder() == OrderingSpecification.DESCENDING && !isAnd)) {
- return new OrderingSpecification(a.getOrder(), Math.max(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
- } else {
- return new OrderingSpecification(a.getOrder(), Math.min(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
- }
- }
- return null;
- }
-
- private void pickOrdering(Stack<OrderingItem> buf) {
- OrderingItem rhs = buf.pop();
- OrderingItem lhs = buf.pop();
- switch (rhs.operator) {
- case AND:
- if (lhs.ordering == null) {
- lhs.ordering = rhs.ordering;
- } else if (rhs.ordering == null) {
- // empty
- } else {
- lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, true);
- }
- break;
- case OR:
- if (lhs.ordering != null && rhs.ordering != null) {
- lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, false);
- } else {
- lhs.ordering = null;
- }
- break;
- default:
- lhs.ordering = null;
- }
- buf.push(lhs);
- }
-
- /**
- * Combines the top two items of the given stack using the operator of the second.
- *
- * @param buf The stack of bucket items.
- */
- private void combineBuckets(Stack<BucketItem> buf) {
- BucketItem rhs = buf.pop();
- BucketItem lhs = buf.pop();
- switch (rhs.operator) {
- case AND:
- if (lhs.buckets == null) {
- lhs.buckets = rhs.buckets;
- } else if (rhs.buckets == null) {
- // empty
- } else {
- lhs.buckets = lhs.buckets.intersection(rhs.buckets);
- }
- break;
- case OR:
- if (lhs.buckets == null) {
- // empty
- } else if (rhs.buckets == null) {
- lhs.buckets = null;
- } else {
- lhs.buckets = lhs.buckets.union(rhs.buckets);
- }
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- buf.push(lhs);
- }
-
- // Inherit doc from ExpressionNode.
- @Override
- public Object evaluate(Context context) {
- Stack<ValueItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if ( ! buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- combineValues(buf);
- }
- }
-
- buf.push(new ValueItem(item.operator, ResultList.toResultList(item.node.evaluate(context))));
- }
- while (buf.size() > 1) {
- combineValues(buf);
- }
- return buf.pop().value;
- }
-
- /**
- * Combines the top two items of the given stack using the operator of the second.
- *
- * @param buf The stack of values.
- */
- private void combineValues(Stack<ValueItem> buf) {
- ValueItem rhs = buf.pop();
- ValueItem lhs = buf.pop();
-
- switch (rhs.operator) {
- case AND:
- buf.push(new ValueItem(lhs.operator, lhs.value.combineAND(rhs.value)));
- break;
- case OR:
- buf.push(new ValueItem(lhs.operator, lhs.value.combineOR(rhs.value)));
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- // Inherit doc from Object.
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- for (LogicNode.NodeItem item : items) {
- if (item.operator != NOP) {
- ret.append(" ").append(operatorToString(item.operator)).append(" ");
- }
- ret.append(item.node);
- }
- return ret.toString();
- }
-
- /**
- * Converts the given operator index to a string representation.
- *
- * @param operator The operator index to convert.
- * @return The string representation.
- */
- public String operatorToString(int operator) {
- switch (operator) {
- case NOP:
- return null;
- case OR:
- return "or";
- case AND:
- return "and";
- default:
- throw new IllegalStateException("Logical operator " + operator + " not supported.");
- }
- }
-
- /**
- * Converts the given operator string to a corresponding operator index. This is necessary to perform a stack
- * traversal of logic expression.
- *
- * @param operator The operator to convert.
- * @return The corresponding index.
- */
- private int stringToOperator(String operator) {
- if (operator == null) {
- return NOP;
- } else if (operator.equalsIgnoreCase("or")) {
- return OR;
- } else if (operator.equalsIgnoreCase("and")) {
- return AND;
- } else {
- throw new IllegalStateException("Logical operator '" + operator + "' not supported.");
- }
- }
-
- /**
- * Private class to store results in a stack.
- */
- private final class ValueItem {
- private int operator;
- private ResultList value;
-
- public ValueItem(int operator, ResultList value) {
- this.operator = operator;
- this.value = value;
- }
- }
-
- /**
- * Private class to store bucket sets in a stack.
- */
- private final class BucketItem {
- private int operator;
- private BucketSet buckets;
-
- public BucketItem(int operator, BucketSet buckets) {
- this.operator = operator;
- this.buckets = buckets;
- }
- }
-
- /**
- * Private class to store ordering expressions in a stack.
- */
- private final class OrderingItem {
- private int operator;
- private OrderingSpecification ordering;
-
- public OrderingItem(int operator, OrderingSpecification orderSpec) {
- this.operator = operator;
- this.ordering = orderSpec;
- }
- }
-
- /**
- * Private class to store expression nodes in a stack.
- */
- public final class NodeItem {
- private int operator;
- private ExpressionNode node;
-
- public NodeItem(int operator, ExpressionNode node) {
- this.operator = operator;
- this.node = node;
- }
-
- public int getOperator() {
- return operator;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.ResultList; +import com.yahoo.document.select.Visitor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * This class defines a logical expression of nodes. This implementation uses a stack to evaluate its content as to + * avoid deep recursions when building the parse tree. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class LogicNode implements ExpressionNode { + + // A no-op value is defined for completeness. + public static final int NOP = 0; + + // The OR operator has lower precedence than AND. + public static final int OR = 1; + + // The AND operator has the highest precedence. + public static final int AND = 2; + + // The items contained in this. + private final List<NodeItem> items = new ArrayList<NodeItem>(); + + /** + * Construct an empty logic expression. + */ + public LogicNode() { + // empty + } + + public List<NodeItem> getItems() { + return items; + } + + /** + * Adds an (operator, node) pair to this expression. + * + * @param operator The operator that combines the previous with the node given. + * @param node The node to add to this. + * @return This, to allow chaining. + */ + public LogicNode add(String operator, ExpressionNode node) { + items.add(new LogicNode.NodeItem(stringToOperator(operator), node)); + return this; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + Stack<BucketItem> buf = new Stack<>(); + for (NodeItem item : items) { + if (!buf.isEmpty()) { + while (buf.peek().operator > item.operator) { + combineBuckets(buf); + } + } + buf.push(new BucketItem(item.operator, item.node.getBucketSet(factory))); + } + while (buf.size() > 1) { + combineBuckets(buf); + } + return buf.pop().buckets; + } + + public OrderingSpecification getOrdering(int order) { + Stack<OrderingItem> buf = new Stack<>(); + for (NodeItem item : items) { + if (!buf.isEmpty()) { + while (buf.peek().operator > item.operator) { + pickOrdering(buf); + } + } + buf.push(new OrderingItem(item.operator, item.node.getOrdering(order))); + } + while (buf.size() > 1) { + pickOrdering(buf); + } + return buf.pop().ordering; + } + + private OrderingSpecification pickOrdering(OrderingSpecification a, OrderingSpecification b, boolean isAnd) { + if (a.getWidthBits() == b.getWidthBits() && a.getDivisionBits() == b.getDivisionBits() && a.getOrder() == b.getOrder()) { + if ((a.getOrder() == OrderingSpecification.ASCENDING && isAnd) || + (a.getOrder() == OrderingSpecification.DESCENDING && !isAnd)) { + return new OrderingSpecification(a.getOrder(), Math.max(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits()); + } else { + return new OrderingSpecification(a.getOrder(), Math.min(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits()); + } + } + return null; + } + + private void pickOrdering(Stack<OrderingItem> buf) { + OrderingItem rhs = buf.pop(); + OrderingItem lhs = buf.pop(); + switch (rhs.operator) { + case AND: + if (lhs.ordering == null) { + lhs.ordering = rhs.ordering; + } else if (rhs.ordering == null) { + // empty + } else { + lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, true); + } + break; + case OR: + if (lhs.ordering != null && rhs.ordering != null) { + lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, false); + } else { + lhs.ordering = null; + } + break; + default: + lhs.ordering = null; + } + buf.push(lhs); + } + + /** + * Combines the top two items of the given stack using the operator of the second. + * + * @param buf The stack of bucket items. + */ + private void combineBuckets(Stack<BucketItem> buf) { + BucketItem rhs = buf.pop(); + BucketItem lhs = buf.pop(); + switch (rhs.operator) { + case AND: + if (lhs.buckets == null) { + lhs.buckets = rhs.buckets; + } else if (rhs.buckets == null) { + // empty + } else { + lhs.buckets = lhs.buckets.intersection(rhs.buckets); + } + break; + case OR: + if (lhs.buckets == null) { + // empty + } else if (rhs.buckets == null) { + lhs.buckets = null; + } else { + lhs.buckets = lhs.buckets.union(rhs.buckets); + } + break; + default: + throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported."); + } + buf.push(lhs); + } + + // Inherit doc from ExpressionNode. + @Override + public Object evaluate(Context context) { + Stack<ValueItem> buf = new Stack<>(); + for (NodeItem item : items) { + if ( ! buf.isEmpty()) { + while (buf.peek().operator > item.operator) { + combineValues(buf); + } + } + + buf.push(new ValueItem(item.operator, ResultList.toResultList(item.node.evaluate(context)))); + } + while (buf.size() > 1) { + combineValues(buf); + } + return buf.pop().value; + } + + /** + * Combines the top two items of the given stack using the operator of the second. + * + * @param buf The stack of values. + */ + private void combineValues(Stack<ValueItem> buf) { + ValueItem rhs = buf.pop(); + ValueItem lhs = buf.pop(); + + switch (rhs.operator) { + case AND: + buf.push(new ValueItem(lhs.operator, lhs.value.combineAND(rhs.value))); + break; + case OR: + buf.push(new ValueItem(lhs.operator, lhs.value.combineOR(rhs.value))); + break; + default: + throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported."); + } + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + // Inherit doc from Object. + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + for (LogicNode.NodeItem item : items) { + if (item.operator != NOP) { + ret.append(" ").append(operatorToString(item.operator)).append(" "); + } + ret.append(item.node); + } + return ret.toString(); + } + + /** + * Converts the given operator index to a string representation. + * + * @param operator The operator index to convert. + * @return The string representation. + */ + public String operatorToString(int operator) { + switch (operator) { + case NOP: + return null; + case OR: + return "or"; + case AND: + return "and"; + default: + throw new IllegalStateException("Logical operator " + operator + " not supported."); + } + } + + /** + * Converts the given operator string to a corresponding operator index. This is necessary to perform a stack + * traversal of logic expression. + * + * @param operator The operator to convert. + * @return The corresponding index. + */ + private int stringToOperator(String operator) { + if (operator == null) { + return NOP; + } else if (operator.equalsIgnoreCase("or")) { + return OR; + } else if (operator.equalsIgnoreCase("and")) { + return AND; + } else { + throw new IllegalStateException("Logical operator '" + operator + "' not supported."); + } + } + + /** + * Private class to store results in a stack. + */ + private final class ValueItem { + private int operator; + private ResultList value; + + public ValueItem(int operator, ResultList value) { + this.operator = operator; + this.value = value; + } + } + + /** + * Private class to store bucket sets in a stack. + */ + private final class BucketItem { + private int operator; + private BucketSet buckets; + + public BucketItem(int operator, BucketSet buckets) { + this.operator = operator; + this.buckets = buckets; + } + } + + /** + * Private class to store ordering expressions in a stack. + */ + private final class OrderingItem { + private int operator; + private OrderingSpecification ordering; + + public OrderingItem(int operator, OrderingSpecification orderSpec) { + this.operator = operator; + this.ordering = orderSpec; + } + } + + /** + * Private class to store expression nodes in a stack. + */ + public final class NodeItem { + private int operator; + private ExpressionNode node; + + public NodeItem(int operator, ExpressionNode node) { + this.operator = operator; + this.node = node; + } + + public int getOperator() { + return operator; + } + + public ExpressionNode getNode() { + return node; + } + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java b/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java index 2b85bc3eee6..74e6f0286f8 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java @@ -1,53 +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.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Result;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class NegationNode implements ExpressionNode {
-
- private ExpressionNode node;
-
- public NegationNode(ExpressionNode node) {
- this.node = node;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
-
- public NegationNode setNode(ExpressionNode node) {
- this.node = node;
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- return Result.invert(Result.toResult(node.evaluate(context)));
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "not " + node;
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Result; +import com.yahoo.document.select.Visitor; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class NegationNode implements ExpressionNode { + + private ExpressionNode node; + + public NegationNode(ExpressionNode node) { + this.node = node; + } + + public ExpressionNode getNode() { + return node; + } + + public NegationNode setNode(ExpressionNode node) { + this.node = node; + return this; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + return Result.invert(Result.toResult(node.evaluate(context))); + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "not " + node; + } + + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/NowNode.java b/document/src/main/java/com/yahoo/document/select/rule/NowNode.java index 600dbe536e4..8941f6b2808 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/NowNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/NowNode.java @@ -1,34 +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.document.select.rule;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-
-/**
- * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a>
- */
-public class NowNode implements ExpressionNode {
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- Object ret = System.currentTimeMillis() / 1000;
- return ret;
- }
-
- @Override
- public String toString() {
- return "now()";
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-}
+package com.yahoo.document.select.rule; +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.*; + +/** + * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a> + */ +public class NowNode implements ExpressionNode { + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + Object ret = System.currentTimeMillis() / 1000; + return ret; + } + + @Override + public String toString() { + return "now()"; + } + + public OrderingSpecification getOrdering(int order) { + return null; + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java b/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java index c63197ae3a4..03c8b273a77 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java @@ -1,56 +1,56 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketDistribution;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class SearchColumnNode implements ExpressionNode {
-
- private int field;
- private BucketIdFactory factory = new BucketIdFactory(); // why is this not an abstract class?
- private BucketDistribution distribution;
-
- public SearchColumnNode() {
- setField(0);
- }
-
- public int getField() {
- return field;
- }
-
- public SearchColumnNode setField(int field) {
- distribution = new BucketDistribution(this.field = field, 16);
- return this;
- }
-
- public BucketDistribution getDistribution() {
- return distribution;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- return distribution.getColumn(factory.getBucketId(context.getDocumentOperation().getId()));
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "searchcolumn." + field;
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketDistribution; +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.*; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class SearchColumnNode implements ExpressionNode { + + private int field; + private BucketIdFactory factory = new BucketIdFactory(); // why is this not an abstract class? + private BucketDistribution distribution; + + public SearchColumnNode() { + setField(0); + } + + public int getField() { + return field; + } + + public SearchColumnNode setField(int field) { + distribution = new BucketDistribution(this.field = field, 16); + return this; + } + + public BucketDistribution getDistribution() { + return distribution; + } + + // Inherit doc from ExpressionNode. + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + // Inherit doc from ExpressionNode. + public Object evaluate(Context context) { + return distribution.getColumn(factory.getBucketId(context.getDocumentOperation().getId())); + } + + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "searchcolumn." + field; + } + + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java b/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java index 77c462674db..f988729ebb8 100644 --- a/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java +++ b/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java @@ -1,58 +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.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class VariableNode implements ExpressionNode {
-
- private String value;
-
- public VariableNode(String value) {
- this.value = value;
- }
-
- public Object getValue() {
- return value;
- }
-
- public VariableNode setValue(String value) {
- this.value = value;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- Object o = context.getVariables().get(value);
- if (o == null) {
- throw new IllegalArgumentException("Variable " + value + " was not set in the variable list");
- }
- return o;
- }
-
- @Override
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "$" + value;
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule; + +import com.yahoo.document.BucketIdFactory; +import com.yahoo.document.select.BucketSet; +import com.yahoo.document.select.Context; +import com.yahoo.document.select.OrderingSpecification; +import com.yahoo.document.select.Visitor; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public class VariableNode implements ExpressionNode { + + private String value; + + public VariableNode(String value) { + this.value = value; + } + + public Object getValue() { + return value; + } + + public VariableNode setValue(String value) { + this.value = value; + return this; + } + + @Override + public BucketSet getBucketSet(BucketIdFactory factory) { + return null; + } + + @Override + public Object evaluate(Context context) { + Object o = context.getVariables().get(value); + if (o == null) { + throw new IllegalArgumentException("Variable " + value + " was not set in the variable list"); + } + return o; + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "$" + value; + } + + @Override + public OrderingSpecification getOrdering(int order) { + return null; + } +} diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java index d6dd1ad35ac..e2c94c190ab 100644 --- a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java +++ b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java @@ -35,4 +35,4 @@ public class DocumentUpdateFlags { int mask = ~(~0 << 28); return combined & mask; } -}
\ No newline at end of file +} diff --git a/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java b/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java index e97bd43d9bf..e385d0ce731 100644 --- a/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java +++ b/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java @@ -18,4 +18,4 @@ public interface FeedReader { */ public abstract void read(Operation operation) throws Exception; -}
\ No newline at end of file +} diff --git a/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java b/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java index 9e0c4e353f2..8ba0bd815ea 100644 --- a/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java +++ b/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java @@ -1,44 +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.document;
-
-import com.yahoo.document.datatypes.*;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests for ticket 6394548
- */
-public class IncompatibleFieldTypesTest {
- private DataType arrayOfStrings;
- private StructDataType struct;
- private StructuredFieldValue root;
-
- @Before
- public void setUp() {
- arrayOfStrings = new ArrayDataType(DataType.STRING);
- struct = new StructDataType("fancypants");
- struct.addField(new Field("stringarray", arrayOfStrings, false));
- DataType weightedSetOfStrings = DataType.getWeightedSet(DataType.STRING, false, false);
- struct.addField(new Field("stringws", weightedSetOfStrings, false));
-
- root = struct.createFieldValue();
- root.setFieldValue("stringarray", arrayOfStrings.createFieldValue());
- root.setFieldValue("stringws", weightedSetOfStrings.createFieldValue());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testAddingIncompatibleFieldToArrayFails() {
- System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getClass().getName());
- System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getDataType().toString());
-
- ((Array)root.getFieldValue("stringarray")).add(new IntegerFieldValue(1234));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testAddingIncompatibleFieldToWeightedSetFails() {
- System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getClass().getName());
- System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getDataType().toString());
-
- ((WeightedSet<FieldValue>)root.getFieldValue("stringws")).put(new IntegerFieldValue(1234), 100);
- }
-}
+package com.yahoo.document; + +import com.yahoo.document.datatypes.*; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for ticket 6394548 + */ +public class IncompatibleFieldTypesTest { + private DataType arrayOfStrings; + private StructDataType struct; + private StructuredFieldValue root; + + @Before + public void setUp() { + arrayOfStrings = new ArrayDataType(DataType.STRING); + struct = new StructDataType("fancypants"); + struct.addField(new Field("stringarray", arrayOfStrings, false)); + DataType weightedSetOfStrings = DataType.getWeightedSet(DataType.STRING, false, false); + struct.addField(new Field("stringws", weightedSetOfStrings, false)); + + root = struct.createFieldValue(); + root.setFieldValue("stringarray", arrayOfStrings.createFieldValue()); + root.setFieldValue("stringws", weightedSetOfStrings.createFieldValue()); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddingIncompatibleFieldToArrayFails() { + System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getClass().getName()); + System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getDataType().toString()); + + ((Array)root.getFieldValue("stringarray")).add(new IntegerFieldValue(1234)); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddingIncompatibleFieldToWeightedSetFails() { + System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getClass().getName()); + System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getDataType().toString()); + + ((WeightedSet<FieldValue>)root.getFieldValue("stringws")).put(new IntegerFieldValue(1234), 100); + } +} diff --git a/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java b/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java index ee448bb79b0..6c007bad32a 100644 --- a/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java +++ b/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java @@ -1,123 +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.document.annotation;
-
-import com.yahoo.document.Document;
-import com.yahoo.document.DocumentTypeManager;
-import com.yahoo.document.DocumentTypeManagerConfigurer;
-import com.yahoo.document.StructDataType;
-import com.yahoo.document.datatypes.*;
-import com.yahoo.document.serialization.*;
-import com.yahoo.io.GrowableByteBuffer;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-import static org.junit.Assert.*;
-
-public class Bug6394548TestCase {
- @Test
- public void testSerializeAndDeserializeMultipleAdjacentStructAnnotations() {
- DocumentTypeManager manager = new DocumentTypeManager();
- DocumentTypeManagerConfigurer.configure(manager, "file:src/test/java/com/yahoo/document/annotation/documentmanager.6394548.cfg");
-
- AnnotationTypeRegistry registry = manager.getAnnotationTypeRegistry();
- AnnotationType featureSetType = registry.getType("morty.RICK_FEATURESET");
- assertNotNull(featureSetType);
-
- Document doc = new Document(manager.getDocumentType("article"), "doc:article:test");
- StringFieldValue sfv = new StringFieldValue("badger waltz");
-
- SpanList root = new SpanList();
- SpanNode node = new Span(0, sfv.getString().length());
- root.add(node);
-
- SpanTree tree = new SpanTree("rick_features", root);
- for (int i = 0; i < 2; ++i) {
- tree.annotate(createBigFeatureSetAnnotation(featureSetType));
- }
-
- sfv.setSpanTree(tree);
- doc.setFieldValue("title", sfv);
- System.out.println(doc.toXml());
- String annotationsBefore = dumpAllAnnotations(tree);
-
- GrowableByteBuffer buffer = new GrowableByteBuffer();
- DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
- serializer.write(doc);
-
- buffer.flip();
- DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(manager, buffer);
- Document doc2 = new Document(deserializer);
-
- System.out.println(doc2.toXml());
-
- StringFieldValue readString = (StringFieldValue)doc2.getFieldValue("title");
- SpanTree readTree = readString.getSpanTree("rick_features");
- assertNotNull(readTree);
- String annotationsAfter = dumpAllAnnotations(readTree);
-
- System.out.println("before:\n" + annotationsBefore);
- System.out.println("after:\n" + annotationsAfter);
-
- assertEquals(annotationsBefore, annotationsAfter);
- }
-
- private String dumpAllAnnotations(SpanTree tree) {
- ArrayList<String> tmp = new ArrayList<>();
- for (Annotation anno : tree) {
- Struct s = (Struct)anno.getFieldValue();
- tmp.add(s.toXml());
- }
- Collections.sort(tmp);
- StringBuilder annotations = new StringBuilder();
- for (String s : tmp) {
- annotations.append(s);
- }
- return annotations.toString();
- }
-
- private Annotation createBigFeatureSetAnnotation(AnnotationType featuresetAnno) {
- StructDataType featuresetType = (StructDataType)featuresetAnno.getDataType();
- Struct featureset = featuresetType.createFieldValue();
- System.out.println("featureset type: " + featureset.getDataType().toString());
-
- MapFieldValue<StringFieldValue, IntegerFieldValue> discreteValued
- = (MapFieldValue<StringFieldValue, IntegerFieldValue>)featuresetType.getField("discretevaluedfeatures").getDataType().createFieldValue();
- discreteValued.put(new StringFieldValue("foo"), new IntegerFieldValue(1234));
- discreteValued.put(new StringFieldValue("bar"), new IntegerFieldValue(567890123));
- featureset.setFieldValue("discretevaluedfeatures", discreteValued);
-
- MapFieldValue<StringFieldValue, DoubleFieldValue> realValued
- = (MapFieldValue<StringFieldValue, DoubleFieldValue>)featuresetType.getField("realvaluedfeatures").getDataType().createFieldValue();
- realValued.put(new StringFieldValue("foo"), new DoubleFieldValue(0.75));
- realValued.put(new StringFieldValue("bar"), new DoubleFieldValue(1.5));
- featureset.setFieldValue("realvaluedfeatures", realValued);
-
- Array<StringFieldValue> nested = (Array<StringFieldValue>)featureset.getField("foo10").getDataType().createFieldValue();
- nested.add(new StringFieldValue("baz"));
- nested.add(new StringFieldValue("blargh"));
- featureset.setFieldValue("foo10", nested);
-
- featureset.setFieldValue("foo1", new StringFieldValue("asdf"));
- featureset.setFieldValue("foo4", new StringFieldValue("qwerty"));
- featureset.setFieldValue("foo2", new IntegerFieldValue(555));
- featureset.setFieldValue("foo2", new IntegerFieldValue(8));
- featureset.setFieldValue("foo7", new IntegerFieldValue(1337));
- featureset.setFieldValue("foo8", new IntegerFieldValue(967867));
- featureset.setFieldValue("foo9", new DoubleFieldValue(123.45));
-
- Array<StringFieldValue> attributes = (Array<StringFieldValue>)featureset.getField("foo6").getDataType().createFieldValue();
- attributes.add(new StringFieldValue("adam"));
- attributes.add(new StringFieldValue("jamie"));
- attributes.add(new StringFieldValue("grant"));
- attributes.add(new StringFieldValue("tory"));
- attributes.add(new StringFieldValue("kari"));
- featureset.setFieldValue("variantattribute", attributes);
-
- Annotation anno = new Annotation(featuresetAnno);
- anno.setFieldValue(featureset);
-
- return anno;
- }
-}
+package com.yahoo.document.annotation; + +import com.yahoo.document.Document; +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.document.DocumentTypeManagerConfigurer; +import com.yahoo.document.StructDataType; +import com.yahoo.document.datatypes.*; +import com.yahoo.document.serialization.*; +import com.yahoo.io.GrowableByteBuffer; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; + +import static org.junit.Assert.*; + +public class Bug6394548TestCase { + @Test + public void testSerializeAndDeserializeMultipleAdjacentStructAnnotations() { + DocumentTypeManager manager = new DocumentTypeManager(); + DocumentTypeManagerConfigurer.configure(manager, "file:src/test/java/com/yahoo/document/annotation/documentmanager.6394548.cfg"); + + AnnotationTypeRegistry registry = manager.getAnnotationTypeRegistry(); + AnnotationType featureSetType = registry.getType("morty.RICK_FEATURESET"); + assertNotNull(featureSetType); + + Document doc = new Document(manager.getDocumentType("article"), "doc:article:test"); + StringFieldValue sfv = new StringFieldValue("badger waltz"); + + SpanList root = new SpanList(); + SpanNode node = new Span(0, sfv.getString().length()); + root.add(node); + + SpanTree tree = new SpanTree("rick_features", root); + for (int i = 0; i < 2; ++i) { + tree.annotate(createBigFeatureSetAnnotation(featureSetType)); + } + + sfv.setSpanTree(tree); + doc.setFieldValue("title", sfv); + System.out.println(doc.toXml()); + String annotationsBefore = dumpAllAnnotations(tree); + + GrowableByteBuffer buffer = new GrowableByteBuffer(); + DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer); + serializer.write(doc); + + buffer.flip(); + DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(manager, buffer); + Document doc2 = new Document(deserializer); + + System.out.println(doc2.toXml()); + + StringFieldValue readString = (StringFieldValue)doc2.getFieldValue("title"); + SpanTree readTree = readString.getSpanTree("rick_features"); + assertNotNull(readTree); + String annotationsAfter = dumpAllAnnotations(readTree); + + System.out.println("before:\n" + annotationsBefore); + System.out.println("after:\n" + annotationsAfter); + + assertEquals(annotationsBefore, annotationsAfter); + } + + private String dumpAllAnnotations(SpanTree tree) { + ArrayList<String> tmp = new ArrayList<>(); + for (Annotation anno : tree) { + Struct s = (Struct)anno.getFieldValue(); + tmp.add(s.toXml()); + } + Collections.sort(tmp); + StringBuilder annotations = new StringBuilder(); + for (String s : tmp) { + annotations.append(s); + } + return annotations.toString(); + } + + private Annotation createBigFeatureSetAnnotation(AnnotationType featuresetAnno) { + StructDataType featuresetType = (StructDataType)featuresetAnno.getDataType(); + Struct featureset = featuresetType.createFieldValue(); + System.out.println("featureset type: " + featureset.getDataType().toString()); + + MapFieldValue<StringFieldValue, IntegerFieldValue> discreteValued + = (MapFieldValue<StringFieldValue, IntegerFieldValue>)featuresetType.getField("discretevaluedfeatures").getDataType().createFieldValue(); + discreteValued.put(new StringFieldValue("foo"), new IntegerFieldValue(1234)); + discreteValued.put(new StringFieldValue("bar"), new IntegerFieldValue(567890123)); + featureset.setFieldValue("discretevaluedfeatures", discreteValued); + + MapFieldValue<StringFieldValue, DoubleFieldValue> realValued + = (MapFieldValue<StringFieldValue, DoubleFieldValue>)featuresetType.getField("realvaluedfeatures").getDataType().createFieldValue(); + realValued.put(new StringFieldValue("foo"), new DoubleFieldValue(0.75)); + realValued.put(new StringFieldValue("bar"), new DoubleFieldValue(1.5)); + featureset.setFieldValue("realvaluedfeatures", realValued); + + Array<StringFieldValue> nested = (Array<StringFieldValue>)featureset.getField("foo10").getDataType().createFieldValue(); + nested.add(new StringFieldValue("baz")); + nested.add(new StringFieldValue("blargh")); + featureset.setFieldValue("foo10", nested); + + featureset.setFieldValue("foo1", new StringFieldValue("asdf")); + featureset.setFieldValue("foo4", new StringFieldValue("qwerty")); + featureset.setFieldValue("foo2", new IntegerFieldValue(555)); + featureset.setFieldValue("foo2", new IntegerFieldValue(8)); + featureset.setFieldValue("foo7", new IntegerFieldValue(1337)); + featureset.setFieldValue("foo8", new IntegerFieldValue(967867)); + featureset.setFieldValue("foo9", new DoubleFieldValue(123.45)); + + Array<StringFieldValue> attributes = (Array<StringFieldValue>)featureset.getField("foo6").getDataType().createFieldValue(); + attributes.add(new StringFieldValue("adam")); + attributes.add(new StringFieldValue("jamie")); + attributes.add(new StringFieldValue("grant")); + attributes.add(new StringFieldValue("tory")); + attributes.add(new StringFieldValue("kari")); + featureset.setFieldValue("variantattribute", attributes); + + Annotation anno = new Annotation(featuresetAnno); + anno.setFieldValue(featureset); + + return anno; + } +} diff --git a/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java b/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java index d34d0da8e82..68a97bc557c 100644 --- a/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java +++ b/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java @@ -1,66 +1,66 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.annotation;
-
-import com.yahoo.document.DataType;
-import com.yahoo.document.DocumentTypeManager;
-import com.yahoo.document.Field;
-import com.yahoo.document.StructDataType;
-import com.yahoo.document.datatypes.StringFieldValue;
-import com.yahoo.document.datatypes.Struct;
-import com.yahoo.document.serialization.*;
-import com.yahoo.io.GrowableByteBuffer;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-public class Bug6425939TestCase {
- private DocumentTypeManager man;
- private StructDataType person;
- private AnnotationType personA;
-
- @Before
- public void setUp() {
- man = new DocumentTypeManager();
-
- person = new StructDataType("personStruct");
- person.addField(new Field("foo", DataType.STRING));
- person.addField(new Field("bar", DataType.INT));
- man.register(person);
-
- personA = new AnnotationType("person", person);
- man.getAnnotationTypeRegistry().register(personA);
- }
-
- @Test
- public void canDeserializeAnnotationsOnZeroLengthStrings() {
- StringFieldValue emptyString = new StringFieldValue("");
- emptyString.setSpanTree(createSpanTree());
-
- GrowableByteBuffer buffer = new GrowableByteBuffer(1024);
- DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
- Field strField = new Field("flarn", DataType.STRING);
- serializer.write(strField, emptyString);
- buffer.flip();
-
- // Should not throw exception if bug 6425939 is fixed:
- DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(man, buffer);
- StringFieldValue deserializedString = new StringFieldValue();
- deserializer.read(strField, deserializedString);
-
- assertEquals("", deserializedString.getString());
- SpanTree readTree = deserializedString.getSpanTree("SpanTree1");
- assertNotNull(readTree);
- }
-
- private SpanTree createSpanTree() {
- SpanList root = new SpanList();
- SpanTree tree = new SpanTree("SpanTree1", root);
- SpanNode node = new Span(0, 0);
- Struct ps = new Struct(person);
- ps.setFieldValue("foo", "epic badger");
- ps.setFieldValue("bar", 54321);
- tree.annotate(node, new Annotation(personA, ps));
- root.add(node);
- return tree;
- }
-}
+package com.yahoo.document.annotation; + +import com.yahoo.document.DataType; +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.document.Field; +import com.yahoo.document.StructDataType; +import com.yahoo.document.datatypes.StringFieldValue; +import com.yahoo.document.datatypes.Struct; +import com.yahoo.document.serialization.*; +import com.yahoo.io.GrowableByteBuffer; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Bug6425939TestCase { + private DocumentTypeManager man; + private StructDataType person; + private AnnotationType personA; + + @Before + public void setUp() { + man = new DocumentTypeManager(); + + person = new StructDataType("personStruct"); + person.addField(new Field("foo", DataType.STRING)); + person.addField(new Field("bar", DataType.INT)); + man.register(person); + + personA = new AnnotationType("person", person); + man.getAnnotationTypeRegistry().register(personA); + } + + @Test + public void canDeserializeAnnotationsOnZeroLengthStrings() { + StringFieldValue emptyString = new StringFieldValue(""); + emptyString.setSpanTree(createSpanTree()); + + GrowableByteBuffer buffer = new GrowableByteBuffer(1024); + DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer); + Field strField = new Field("flarn", DataType.STRING); + serializer.write(strField, emptyString); + buffer.flip(); + + // Should not throw exception if bug 6425939 is fixed: + DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(man, buffer); + StringFieldValue deserializedString = new StringFieldValue(); + deserializer.read(strField, deserializedString); + + assertEquals("", deserializedString.getString()); + SpanTree readTree = deserializedString.getSpanTree("SpanTree1"); + assertNotNull(readTree); + } + + private SpanTree createSpanTree() { + SpanList root = new SpanList(); + SpanTree tree = new SpanTree("SpanTree1", root); + SpanNode node = new Span(0, 0); + Struct ps = new Struct(person); + ps.setFieldValue("foo", "epic badger"); + ps.setFieldValue("bar", 54321); + tree.annotate(node, new Annotation(personA, ps)); + root.add(node); + return tree; + } +} diff --git a/document/src/vespa/document/fieldvalue/variablemap.h b/document/src/vespa/document/fieldvalue/variablemap.h index 06679682e0c..ccebd3cdb52 100644 --- a/document/src/vespa/document/fieldvalue/variablemap.h +++ b/document/src/vespa/document/fieldvalue/variablemap.h @@ -44,4 +44,4 @@ public: vespalib::string toString() const; }; -}
\ No newline at end of file +} |