aboutsummaryrefslogtreecommitdiffstats
path: root/container-search
diff options
context:
space:
mode:
authorJon Marius Venstad <venstad@gmail.com>2022-03-23 15:33:04 +0100
committerjonmv <venstad@gmail.com>2022-10-26 12:07:17 +0200
commitd92c5a98abe7f05efed896a93d47695ea76215f3 (patch)
tree938ca88a4d559a8da5f9dee57b54dce3ef0bd2b5 /container-search
parent2e727510f09094faf433172f060b4f4d0f6a4cb2 (diff)
Add test that fails now
Diffstat (limited to 'container-search')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java25
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java256
2 files changed, 278 insertions, 3 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java b/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java
index fb77f010df2..24d4623b2b8 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java
@@ -46,6 +46,8 @@ import static java.util.Objects.requireNonNull;
* Adding ranges in ascending order is much faster than not; ascending order here has the rather lax
* requirement that each added interval is not completely before the current last interval.
*
+ * todo: cover all three cases of single index + ranges, dual index + ranges, dual index + points
+ *
* @author jonmv
*/
public class MultiRangeItem extends MultiTermItem {
@@ -80,9 +82,17 @@ public class MultiRangeItem extends MultiTermItem {
return Objects.hash(start, end);
}
+ @Override
+ public String toString() {
+ return "(" + start + ", " + end + ")";
+ }
+
}
- private static final Comparator<Number> comparator = comparingDouble(Number::doubleValue);
+ static final Comparator<Number> comparator = (a, b) -> {
+ double u = a.doubleValue(), v = b.doubleValue();
+ return u < v ? -1 : u > v ? 1 : 0;
+ };
private final String startIndex;
private final String endIndex;
@@ -113,8 +123,17 @@ public class MultiRangeItem extends MultiTermItem {
return overRanges(index, startInclusive, index, endInclusive);
}
+ /** Adds the given point to this item. More efficient when each added point is not completely before the current last one. */
+ public MultiRangeItem addPoint(Number point) {
+ return addRange(point, point);
+ }
+
/** Adds the given range to this item. More efficient when each added range is not completely before the current last one. */
- public MultiRangeItem add(Number start, Number end) {
+ public MultiRangeItem addRange(Number start, Number end) {
+ if (Double.isNaN(start.doubleValue()))
+ throw new IllegalArgumentException("range start cannot be NaN");
+ if (Double.isNaN(end.doubleValue()))
+ throw new IllegalArgumentException("range end cannot be NaN");
if (comparator.compare(start, end) > 0)
throw new IllegalArgumentException("ranges must satisfy start <= end, but got " + start + " > " + end);
@@ -154,7 +173,7 @@ public class MultiRangeItem extends MultiTermItem {
return comparator.compare(a, b) >= 0 ? a : b;
}
- private List<Range> sortedRanges() {
+ List<Range> sortedRanges() {
if (sorted)
return ranges;
diff --git a/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java b/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java
new file mode 100644
index 00000000000..b6227c9969d
--- /dev/null
+++ b/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java
@@ -0,0 +1,256 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.prelude.query;
+
+import com.yahoo.prelude.query.MultiRangeItem.Range;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import static com.yahoo.prelude.query.MultiRangeItem.Limit.EXCLUSIVE;
+import static com.yahoo.prelude.query.MultiRangeItem.Limit.INCLUSIVE;
+import static java.lang.Double.NEGATIVE_INFINITY;
+import static java.lang.Double.NaN;
+import static java.lang.Double.POSITIVE_INFINITY;
+import static java.util.Comparator.comparingDouble;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * @author jonmv
+ */
+public class MultiRangeItemTestCase {
+
+ // We'll add ranges (0, 0), (0, 2), (2, 2), (3, 4), (5, 8), (6, 6), (7, 9), (9, 9), (1, 8), in that order, and in "random" order.
+ final List<Range> ranges = List.of(new Range(1, 8), // Make it "unordered", so sorting is delayed.
+ new Range(0, 0),
+ new Range(0, 2),
+ new Range(2, 2),
+ new Range(3, 4),
+ new Range(5, 8),
+ new Range(6, 6),
+ new Range(9, 9),
+ new Range(7, 9));
+
+ @Test
+ public void testNanIsDisallowed() {
+ try {
+ MultiRangeItem.overPoints("i", INCLUSIVE, EXCLUSIVE).addPoint(NaN);
+ fail("NaN should be disallowed");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("range start cannot be NaN", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSpecialValuesWithClosedIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE);
+ item.addPoint(0.0);
+ item.addPoint(-0.0);
+ assertEquals(List.of(new Range(0.0, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(NEGATIVE_INFINITY, 0);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(0, POSITIVE_INFINITY);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)),
+ item.sortedRanges());
+
+ try {
+ item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+ fail("negative ranges should be disallowed");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSpecialValuesWithClosedOpenIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, EXCLUSIVE);
+ item.addPoint( 0.0);
+ item.addPoint(-0.0);
+ assertEquals(List.of(new Range(0.0, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(NEGATIVE_INFINITY, 0);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(0, POSITIVE_INFINITY);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)),
+ item.sortedRanges());
+
+ try {
+ item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+ fail("negative ranges should be disallowed");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSpecialValuesWithOpenClosedIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, INCLUSIVE);
+ item.addPoint( 0.0);
+ item.addPoint(-0.0);
+ assertEquals(List.of(new Range(0.0, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(NEGATIVE_INFINITY, 0);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(0, POSITIVE_INFINITY);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)),
+ item.sortedRanges());
+
+ try {
+ item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+ fail("negative ranges should be disallowed");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSpecialValuesWithOpenIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE);
+ item.addPoint( 0.0);
+ item.addPoint(-0.0);
+ assertEquals(List.of(new Range(0.0, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(NEGATIVE_INFINITY, 0);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)),
+ item.sortedRanges());
+
+ item.addRange(0, POSITIVE_INFINITY);
+ assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)),
+ item.sortedRanges());
+
+ try {
+ item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+ fail("negative ranges should be disallowed");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testAddingRangesOrderedByStartWithClosedIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE);
+ ranges.stream().sorted(comparingDouble(range -> range.start.doubleValue()))
+ .forEach(range -> item.addRange(range.start, range.end));
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testAddingRangesOrderedByStartWithOpenIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE);
+ ranges.stream().sorted(comparingDouble(range -> range.start.doubleValue()))
+ .forEach(range -> item.addRange(range.start, range.end));
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testAddingRangesOrderedByEndWithClosedIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE);
+ ranges.stream().sorted(comparingDouble(range -> range.end.doubleValue()))
+ .forEach(range -> item.addRange(range.start, range.end));
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testAddingRangesOrderedByEndWithOpenIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE);
+ ranges.stream().sorted(comparingDouble(range -> range.end.doubleValue()))
+ .forEach(range -> item.addRange(range.start, range.end));
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testAddingRangesUnorderedWithClosedIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE);
+ for (Range range : ranges)
+ item.addRange(range.start, range.end);
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testAddingRangesUnorderedWithOpenIntervals() {
+ MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE);
+ for (Range range : ranges)
+ item.addRange(range.start, range.end);
+
+ assertEquals(List.of(new Range(0, 9)),
+ item.sortedRanges());
+ }
+
+ @Test
+ public void testSerialization() {
+ ByteBuffer pointsBuffer = ByteBuffer.allocate(25);
+ MultiRangeItem pointsItem = MultiRangeItem.overPoints("i", EXCLUSIVE, INCLUSIVE)
+ .addRange(NEGATIVE_INFINITY, POSITIVE_INFINITY);
+ pointsItem.encode(pointsBuffer);
+
+ ByteBuffer expected = ByteBuffer.allocate(25);
+ expected.put((byte) 0b00000111); // ItemType.MULTI_TERM
+ expected.put((byte) 0b00100000); // OR << 5, RANGES
+ expected.putInt(1); // term count
+ expected.put((byte) 0b00000101); // end inclusive, same index
+ expected.put((byte) 1); // index name length
+ expected.put((byte) 'i'); // index name bytes
+ expected.putDouble(NEGATIVE_INFINITY);
+ expected.putDouble(POSITIVE_INFINITY);
+
+ pointsBuffer.flip();
+ expected.flip();
+ assertEquals(expected, pointsBuffer);
+
+ ByteBuffer rangesBuffer = ByteBuffer.allocate(59);
+ MultiRangeItem rangesItem = MultiRangeItem.overRanges("i", INCLUSIVE, "j", EXCLUSIVE)
+ .addPoint( -0.0)
+ .addRange( 1, 2.0)
+ .addRange(-1, -0.5);
+ rangesItem.encode(rangesBuffer);
+
+ expected = ByteBuffer.allocate(59);
+ expected.put((byte) 0b00000111); // ItemType.MULTI_TERM
+ expected.put((byte) 0b00100000); // OR << 5, RANGES
+ expected.putInt(3); // term count
+ expected.put((byte) 0b00000010); // end inclusive, same index
+ expected.put((byte) 1); // index name length
+ expected.put((byte) 'i'); // index name bytes
+ expected.put((byte) 1); // index name length
+ expected.put((byte) 'j'); // index name bytes
+ expected.putDouble(-1.0);
+ expected.putDouble(-0.5);
+ expected.putDouble(-0.0);
+ expected.putDouble(-0.0);
+ expected.putDouble( 1.0);
+ expected.putDouble( 2.0);
+
+ rangesBuffer.flip();
+ expected.flip();
+ assertEquals(expected, rangesBuffer);
+ }
+
+}