diff --git a/core/src/main/java/org/elasticsearch/search/MultiValueMode.java b/core/src/main/java/org/elasticsearch/search/MultiValueMode.java index 2d85c379f54..b2ee4b8ffbd 100644 --- a/core/src/main/java/org/elasticsearch/search/MultiValueMode.java +++ b/core/src/main/java/org/elasticsearch/search/MultiValueMode.java @@ -416,11 +416,11 @@ public enum MultiValueMode implements Writeable { if (singleton != null) { return new AbstractNumericDocValues() { - private boolean hasValue; + private long value; @Override public boolean advanceExact(int target) throws IOException { - hasValue = singleton.advanceExact(target); + this.value = singleton.advanceExact(target) ? singleton.longValue() : missingValue; return true; } @@ -431,17 +431,17 @@ public enum MultiValueMode implements Writeable { @Override public long longValue() throws IOException { - return hasValue ? singleton.longValue() : missingValue; + return this.value; } }; } else { return new AbstractNumericDocValues() { - private boolean hasValue; + private long value; @Override public boolean advanceExact(int target) throws IOException { - hasValue = values.advanceExact(target); + this.value = values.advanceExact(target) ? pick(values) : missingValue; return true; } @@ -452,7 +452,7 @@ public enum MultiValueMode implements Writeable { @Override public long longValue() throws IOException { - return hasValue ? pick(values) : missingValue; + return value; } }; } @@ -533,35 +533,33 @@ public enum MultiValueMode implements Writeable { final NumericDoubleValues singleton = FieldData.unwrapSingleton(values); if (singleton != null) { return new NumericDoubleValues() { - - private boolean hasValue; + private double value; @Override public boolean advanceExact(int doc) throws IOException { - hasValue = singleton.advanceExact(doc); + this.value = singleton.advanceExact(doc) ? singleton.doubleValue() : missingValue; return true; } @Override public double doubleValue() throws IOException { - return hasValue ? singleton.doubleValue() : missingValue; + return this.value; } - }; } else { return new NumericDoubleValues() { - private boolean hasValue; + private double value; @Override public boolean advanceExact(int target) throws IOException { - hasValue = values.advanceExact(target); + value = values.advanceExact(target) ? pick(values) : missingValue; return true; } @Override public double doubleValue() throws IOException { - return hasValue ? pick(values) : missingValue; + return this.value; } }; } @@ -638,17 +636,17 @@ public enum MultiValueMode implements Writeable { } return new AbstractBinaryDocValues() { - private boolean hasValue; + private BytesRef value; @Override public boolean advanceExact(int target) throws IOException { - hasValue = singleton.advanceExact(target); + this.value = singleton.advanceExact(target) ? singleton.binaryValue() : missingValue; return true; } @Override public BytesRef binaryValue() throws IOException { - return hasValue ? singleton.binaryValue() : missingValue; + return this.value; } }; } else { diff --git a/core/src/test/java/org/elasticsearch/search/MultiValueModeTests.java b/core/src/test/java/org/elasticsearch/search/MultiValueModeTests.java index df18b00528c..d9eb4501326 100644 --- a/core/src/test/java/org/elasticsearch/search/MultiValueModeTests.java +++ b/core/src/test/java/org/elasticsearch/search/MultiValueModeTests.java @@ -19,8 +19,6 @@ package org.elasticsearch.search; -import com.carrotsearch.randomizedtesting.generators.RandomStrings; - import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.NumericDocValues; @@ -160,6 +158,8 @@ public class MultiValueModeTests extends ESTestCase { for (int i = 0; i < maxDoc; ++i) { assertTrue(selected.advanceExact(i)); final long actual = selected.longValue(); + verifyLongValueCanCalledMoreThanOnce(selected, actual); + long expected = 0; if (values.advanceExact(i) == false) { expected = missingValue; @@ -203,6 +203,12 @@ public class MultiValueModeTests extends ESTestCase { } } + private void verifyLongValueCanCalledMoreThanOnce(NumericDocValues values, long expected) throws IOException { + for (int j = 0, numCall = randomIntBetween(1, 10); j < numCall; j++) { + assertEquals(expected, values.longValue()); + } + } + private void verifySortedNumeric(Supplier supplier, int maxDoc, FixedBitSet rootDocs, FixedBitSet innerDocs) throws IOException { for (long missingValue : new long[] { 0, randomLong() }) { for (MultiValueMode mode : new MultiValueMode[] {MultiValueMode.MIN, MultiValueMode.MAX, MultiValueMode.SUM, MultiValueMode.AVG}) { @@ -212,6 +218,8 @@ public class MultiValueModeTests extends ESTestCase { for (int root = rootDocs.nextSetBit(0); root != -1; root = root + 1 < maxDoc ? rootDocs.nextSetBit(root + 1) : -1) { assertTrue(selected.advanceExact(root)); final long actual = selected.longValue(); + verifyLongValueCanCalledMoreThanOnce(selected, actual); + long expected = 0; if (mode == MultiValueMode.MAX) { expected = Long.MIN_VALUE; @@ -320,14 +328,13 @@ public class MultiValueModeTests extends ESTestCase { private void verifySortedNumericDouble(Supplier supplier, int maxDoc) throws IOException { for (long missingValue : new long[] { 0, randomLong() }) { for (MultiValueMode mode : MultiValueMode.values()) { - if (MultiValueMode.MEDIAN.equals(mode)) { - continue; - } SortedNumericDoubleValues values = supplier.get(); final NumericDoubleValues selected = mode.select(values, missingValue); for (int i = 0; i < maxDoc; ++i) { assertTrue(selected.advanceExact(i)); final double actual = selected.doubleValue(); + verifyDoubleValueCanCalledMoreThanOnce(selected, actual); + double expected = 0.0; if (values.advanceExact(i) == false) { expected = missingValue; @@ -371,6 +378,12 @@ public class MultiValueModeTests extends ESTestCase { } } + private void verifyDoubleValueCanCalledMoreThanOnce(NumericDoubleValues values, double expected) throws IOException { + for (int j = 0, numCall = randomIntBetween(1, 10); j < numCall; j++) { + assertTrue(Double.compare(values.doubleValue(), expected) == 0); + } + } + private void verifySortedNumericDouble(Supplier supplier, int maxDoc, FixedBitSet rootDocs, FixedBitSet innerDocs) throws IOException { for (long missingValue : new long[] { 0, randomLong() }) { for (MultiValueMode mode : new MultiValueMode[] {MultiValueMode.MIN, MultiValueMode.MAX, MultiValueMode.SUM, MultiValueMode.AVG}) { @@ -379,7 +392,9 @@ public class MultiValueModeTests extends ESTestCase { int prevRoot = -1; for (int root = rootDocs.nextSetBit(0); root != -1; root = root + 1 < maxDoc ? rootDocs.nextSetBit(root + 1) : -1) { assertTrue(selected.advanceExact(root)); - final double actual = selected.doubleValue();; + final double actual = selected.doubleValue(); + verifyDoubleValueCanCalledMoreThanOnce(selected, actual); + double expected = 0.0; if (mode == MultiValueMode.MAX) { expected = Long.MIN_VALUE; @@ -421,7 +436,7 @@ public class MultiValueModeTests extends ESTestCase { final FixedBitSet docsWithValue = randomBoolean() ? null : new FixedBitSet(numDocs); for (int i = 0; i < array.length; ++i) { if (randomBoolean()) { - array[i] = new BytesRef(RandomStrings.randomAsciiOfLength(random(), 8)); + array[i] = new BytesRef(randomAlphaOfLengthBetween(8, 8)); if (docsWithValue != null) { docsWithValue.set(i); } @@ -456,7 +471,7 @@ public class MultiValueModeTests extends ESTestCase { for (int i = 0; i < numDocs; ++i) { final BytesRef[] values = new BytesRef[randomInt(4)]; for (int j = 0; j < values.length; ++j) { - values[j] = new BytesRef(RandomStrings.randomAsciiOfLength(random(), 8)); + values[j] = new BytesRef(randomAlphaOfLengthBetween(8, 8)); } Arrays.sort(values); array[i] = values; @@ -489,13 +504,15 @@ public class MultiValueModeTests extends ESTestCase { } private void verifySortedBinary(Supplier supplier, int maxDoc) throws IOException { - for (BytesRef missingValue : new BytesRef[] { new BytesRef(), new BytesRef(RandomStrings.randomAsciiOfLength(random(), 8)) }) { + for (BytesRef missingValue : new BytesRef[] { new BytesRef(), new BytesRef(randomAlphaOfLengthBetween(8, 8)) }) { for (MultiValueMode mode : new MultiValueMode[] {MultiValueMode.MIN, MultiValueMode.MAX}) { SortedBinaryDocValues values = supplier.get(); final BinaryDocValues selected = mode.select(values, missingValue); for (int i = 0; i < maxDoc; ++i) { assertTrue(selected.advanceExact(i)); final BytesRef actual = selected.binaryValue(); + verifyBinaryValueCanCalledMoreThanOnce(selected, actual); + BytesRef expected = null; if (values.advanceExact(i) == false) { expected = missingValue; @@ -524,8 +541,14 @@ public class MultiValueModeTests extends ESTestCase { } } + private void verifyBinaryValueCanCalledMoreThanOnce(BinaryDocValues values, BytesRef expected) throws IOException { + for (int j = 0, numCall = randomIntBetween(1, 10); j < numCall; j++) { + assertEquals(values.binaryValue(), expected); + } + } + private void verifySortedBinary(Supplier supplier, int maxDoc, FixedBitSet rootDocs, FixedBitSet innerDocs) throws IOException { - for (BytesRef missingValue : new BytesRef[] { new BytesRef(), new BytesRef(RandomStrings.randomAsciiOfLength(random(), 8)) }) { + for (BytesRef missingValue : new BytesRef[] { new BytesRef(), new BytesRef(randomAlphaOfLengthBetween(8, 8)) }) { for (MultiValueMode mode : new MultiValueMode[] {MultiValueMode.MIN, MultiValueMode.MAX}) { SortedBinaryDocValues values = supplier.get(); final BinaryDocValues selected = mode.select(values, missingValue, rootDocs, new BitSetIterator(innerDocs, 0L), maxDoc); @@ -533,6 +556,8 @@ public class MultiValueModeTests extends ESTestCase { for (int root = rootDocs.nextSetBit(0); root != -1; root = root + 1 < maxDoc ? rootDocs.nextSetBit(root + 1) : -1) { assertTrue(selected.advanceExact(root)); final BytesRef actual = selected.binaryValue(); + verifyBinaryValueCanCalledMoreThanOnce(selected, actual); + BytesRef expected = null; for (int child = innerDocs.nextSetBit(prevRoot + 1); child != -1 && child < root; child = innerDocs.nextSetBit(child + 1)) { if (values.advanceExact(child)) { @@ -658,7 +683,11 @@ public class MultiValueModeTests extends ESTestCase { SortedSetDocValues values = supplier.get(); final SortedDocValues selected = mode.select(values); for (int i = 0; i < maxDoc; ++i) { - final long actual = selected.advanceExact(i) ? selected.ordValue() : -1; + long actual = -1; + if (selected.advanceExact(i)) { + actual = selected.ordValue(); + verifyOrdValueCanCalledMoreThanOnce(selected, selected.ordValue()); + } int expected = -1; if (values.advanceExact(i)) { for (long ord = values.nextOrd(); ord != SortedSetDocValues.NO_MORE_ORDS; ord = values.nextOrd()) { @@ -679,13 +708,23 @@ public class MultiValueModeTests extends ESTestCase { } } + private void verifyOrdValueCanCalledMoreThanOnce(SortedDocValues values, long expected) throws IOException { + for (int j = 0, numCall = randomIntBetween(1, 10); j < numCall; j++) { + assertEquals(values.ordValue(), expected); + } + } + private void verifySortedSet(Supplier supplier, int maxDoc, FixedBitSet rootDocs, FixedBitSet innerDocs) throws IOException { for (MultiValueMode mode : new MultiValueMode[] {MultiValueMode.MIN, MultiValueMode.MAX}) { SortedSetDocValues values = supplier.get(); final SortedDocValues selected = mode.select(values, rootDocs, new BitSetIterator(innerDocs, 0L)); int prevRoot = -1; for (int root = rootDocs.nextSetBit(0); root != -1; root = root + 1 < maxDoc ? rootDocs.nextSetBit(root + 1) : -1) { - final int actual = selected.advanceExact(root) ? selected.ordValue() : -1; + int actual = -1; + if (selected.advanceExact(root)) { + actual = selected.ordValue(); + verifyOrdValueCanCalledMoreThanOnce(selected, actual); + } int expected = -1; for (int child = innerDocs.nextSetBit(prevRoot + 1); child != -1 && child < root; child = innerDocs.nextSetBit(child + 1)) { if (values.advanceExact(child)) {