LUCENE-7059: always visit 1D points in sorted order; fix tie-break but in BKDWriter; fix BKDWriter to pass on maxMBSortInHeap to the OfflineSorter too

This commit is contained in:
Mike McCandless 2016-03-02 11:25:27 -05:00
parent 9427b7402d
commit e3198cac54
20 changed files with 443 additions and 241 deletions

View File

@ -1706,8 +1706,12 @@ public final class CheckIndex implements Closeable {
lastMaxPacked.length = bytesPerDim; lastMaxPacked.length = bytesPerDim;
lastMinPacked.length = bytesPerDim; lastMinPacked.length = bytesPerDim;
scratch.length = bytesPerDim; scratch.length = bytesPerDim;
byte[] lastPackedValue = new byte[dimCount*bytesPerDim];
values.intersect(fieldInfo.name, values.intersect(fieldInfo.name,
new PointValues.IntersectVisitor() { new PointValues.IntersectVisitor() {
private int lastDocID = -1;
@Override @Override
public void visit(int docID) { public void visit(int docID) {
throw new RuntimeException("codec called IntersectVisitor.visit without a packed value for docID=" + docID); throw new RuntimeException("codec called IntersectVisitor.visit without a packed value for docID=" + docID);
@ -1725,14 +1729,29 @@ public final class CheckIndex implements Closeable {
if (scratch.compareTo(lastMinPacked) < 0) { if (scratch.compareTo(lastMinPacked) < 0) {
// This doc's point, in this dimension, is lower than the minimum value of the last cell checked: // This doc's point, in this dimension, is lower than the minimum value of the last cell checked:
throw new RuntimeException("packed value " + Arrays.toString(packedValue) + " for docID=" + docID + " is out-of-bounds of the last cell min=" + Arrays.toString(lastMinPackedValue) + " max=" + Arrays.toString(lastMaxPackedValue) + " dim=" + dim); throw new RuntimeException("packed points value " + Arrays.toString(packedValue) + " for docID=" + docID + " is out-of-bounds of the last cell min=" + Arrays.toString(lastMinPackedValue) + " max=" + Arrays.toString(lastMaxPackedValue) + " dim=" + dim);
} }
if (scratch.compareTo(lastMaxPacked) > 0) { if (scratch.compareTo(lastMaxPacked) > 0) {
// This doc's point, in this dimension, is greater than the maximum value of the last cell checked: // This doc's point, in this dimension, is greater than the maximum value of the last cell checked:
throw new RuntimeException("packed value " + Arrays.toString(packedValue) + " for docID=" + docID + " is out-of-bounds of the last cell min=" + Arrays.toString(lastMinPackedValue) + " max=" + Arrays.toString(lastMaxPackedValue) + " dim=" + dim); throw new RuntimeException("packed points value " + Arrays.toString(packedValue) + " for docID=" + docID + " is out-of-bounds of the last cell min=" + Arrays.toString(lastMinPackedValue) + " max=" + Arrays.toString(lastMaxPackedValue) + " dim=" + dim);
} }
} }
// In the 1D case, PointValues must make a single in-order sweep through all values, and tie-break by
// increasing docID:
if (dimCount == 1) {
int cmp = StringHelper.compare(bytesPerDim, lastPackedValue, 0, packedValue, 0);
if (cmp > 0) {
throw new RuntimeException("packed points value " + Arrays.toString(packedValue) + " for docID=" + docID + " is out-of-order vs the previous document's value " + Arrays.toString(lastPackedValue));
} else if (cmp == 0) {
if (docID < lastDocID) {
throw new RuntimeException("packed points value is the same, but docID=" + docID + " is out of order vs previous docID=" + lastDocID);
}
}
System.arraycopy(packedValue, 0, lastPackedValue, 0, bytesPerDim);
lastDocID = docID;
}
status.totalValuePoints++; status.totalValuePoints++;
} }

View File

@ -61,7 +61,9 @@ public abstract class PointValues {
void visit(int docID) throws IOException; void visit(int docID) throws IOException;
/** Called for all documents in a leaf cell that crosses the query. The consumer /** Called for all documents in a leaf cell that crosses the query. The consumer
* should scrutinize the packedValue to decide whether to accept it. */ * should scrutinize the packedValue to decide whether to accept it. In the 1D case,
* values are visited in increasing order, and in the case of ties, in increasing
* docID order. */
void visit(int docID, byte[] packedValue) throws IOException; void visit(int docID, byte[] packedValue) throws IOException;
/** Called for non-leaf cells to test how the cell relates to the query, to /** Called for non-leaf cells to test how the cell relates to the query, to

View File

@ -43,6 +43,7 @@ class PointValuesWriter {
packedValue = new byte[fieldInfo.getPointDimensionCount() * fieldInfo.getPointNumBytes()]; packedValue = new byte[fieldInfo.getPointDimensionCount() * fieldInfo.getPointNumBytes()];
} }
// TODO: if exactly the same value is added to exactly the same doc, should we dedup?
public void addPackedValue(int docID, BytesRef value) { public void addPackedValue(int docID, BytesRef value) {
if (value == null) { if (value == null) {
throw new IllegalArgumentException("field=" + fieldInfo.name + ": point value cannot be null"); throw new IllegalArgumentException("field=" + fieldInfo.name + ": point value cannot be null");

View File

@ -236,7 +236,7 @@ public final class SlowCompositeReaderWrapper extends LeafReader {
@Override @Override
public PointValues getPointValues() { public PointValues getPointValues() {
ensureOpen(); ensureOpen();
return MultiPointValues.get(in); return null;
} }
@Override @Override

View File

@ -172,10 +172,6 @@ public abstract class PointInSetQuery extends Query {
this.sortedPackedPoints = sortedPackedPoints; this.sortedPackedPoints = sortedPackedPoints;
lastMaxPackedValue = new byte[bytesPerDim]; lastMaxPackedValue = new byte[bytesPerDim];
scratch.length = bytesPerDim; scratch.length = bytesPerDim;
resetIterator();
}
private void resetIterator() {
this.iterator = sortedPackedPoints.iterator(); this.iterator = sortedPackedPoints.iterator();
nextQueryPoint = iterator.next(); nextQueryPoint = iterator.next();
} }
@ -211,15 +207,6 @@ public abstract class PointInSetQuery extends Query {
@Override @Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) { public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
// NOTE: this is messy ... we need it in cases where a single vistor (us) is shared across multiple leaf readers
// (e.g. SlowCompositeReaderWrapper), in which case we need to reset our iterator to re-start the merge sort. Maybe we should instead
// add an explicit .start() to IntersectVisitor, and clarify the semantics that in the 1D case all cells will be visited in order?
if (StringHelper.compare(bytesPerDim, lastMaxPackedValue, 0, minPackedValue, 0) > 0) {
resetIterator();
}
System.arraycopy(maxPackedValue, 0, lastMaxPackedValue, 0, bytesPerDim);
while (nextQueryPoint != null) { while (nextQueryPoint != null) {
scratch.bytes = minPackedValue; scratch.bytes = minPackedValue;
int cmpMin = nextQueryPoint.compareTo(scratch); int cmpMin = nextQueryPoint.compareTo(scratch);

View File

@ -120,7 +120,7 @@ public class OfflineSorter {
final long minBufferSizeBytes = MIN_BUFFER_SIZE_MB*MB; final long minBufferSizeBytes = MIN_BUFFER_SIZE_MB*MB;
if (sortBufferByteSize < minBufferSizeBytes if (sortBufferByteSize < minBufferSizeBytes
|| totalAvailableBytes > 10 * minBufferSizeBytes) { // lets see if we need/should to grow the heap || totalAvailableBytes > 10 * minBufferSizeBytes) { // lets see if we need/should to grow the heap
if (totalAvailableBytes/2 > minBufferSizeBytes){ // there is enough mem for a reasonable buffer if (totalAvailableBytes/2 > minBufferSizeBytes) { // there is enough mem for a reasonable buffer
sortBufferByteSize = totalAvailableBytes/2; // grow the heap sortBufferByteSize = totalAvailableBytes/2; // grow the heap
} else { } else {
//heap seems smallish lets be conservative fall back to the free/2 //heap seems smallish lets be conservative fall back to the free/2

View File

@ -102,6 +102,7 @@ public class BKDWriter implements Closeable {
final TrackingDirectoryWrapper tempDir; final TrackingDirectoryWrapper tempDir;
final String tempFileNamePrefix; final String tempFileNamePrefix;
final double maxMBSortInHeap;
final byte[] scratchDiff; final byte[] scratchDiff;
final byte[] scratchPackedValue; final byte[] scratchPackedValue;
@ -169,6 +170,8 @@ public class BKDWriter implements Closeable {
// We write first maxPointsSortInHeap in heap, then cutover to offline for additional points: // We write first maxPointsSortInHeap in heap, then cutover to offline for additional points:
heapPointWriter = new HeapPointWriter(16, maxPointsSortInHeap, packedBytesLength); heapPointWriter = new HeapPointWriter(16, maxPointsSortInHeap, packedBytesLength);
this.maxMBSortInHeap = maxMBSortInHeap;
} }
public static void verifyParams(int numDims, int maxPointsInLeafNode, double maxMBSortInHeap) { public static void verifyParams(int numDims, int maxPointsInLeafNode, double maxMBSortInHeap) {
@ -550,7 +553,7 @@ public class BKDWriter implements Closeable {
//int[] swapCount = new int[1]; //int[] swapCount = new int[1];
//int[] cmpCount = new int[1]; //int[] cmpCount = new int[1];
//System.out.println("SORT length=" + length); // System.out.println("SORT length=" + length);
// All buffered points are still in heap; just do in-place sort: // All buffered points are still in heap; just do in-place sort:
new IntroSorter() { new IntroSorter() {
@ -623,13 +626,11 @@ public class BKDWriter implements Closeable {
return cmp; return cmp;
} }
// Tie-break // Tie-break by docID:
cmp = Integer.compare(writer.docIDs[i], writer.docIDs[j]);
if (cmp != 0) {
return cmp;
}
return Long.compare(writer.ords[i], writer.ords[j]); // No need to tie break on ord, for the case where the same doc has the same value in a given dimension indexed more than once: it
// can't matter at search time since we don't write ords into the index:
return Integer.compare(writer.docIDs[i], writer.docIDs[j]);
} }
}.sort(start, start+length); }.sort(start, start+length);
//System.out.println("LEN=" + length + " SWAP=" + swapCount[0] + " CMP=" + cmpCount[0]); //System.out.println("LEN=" + length + " SWAP=" + swapCount[0] + " CMP=" + cmpCount[0]);
@ -679,29 +680,23 @@ public class BKDWriter implements Closeable {
return cmp; return cmp;
} }
// Tie-break by docID and then ord: // Tie-break by docID:
reader.reset(a.bytes, a.offset + packedBytesLength, a.length); reader.reset(a.bytes, a.offset + packedBytesLength + Long.BYTES, a.length);
final int docIDA = reader.readVInt(); final int docIDA = reader.readInt();
final long ordA = reader.readVLong();
reader.reset(b.bytes, b.offset + packedBytesLength, b.length); reader.reset(b.bytes, b.offset + packedBytesLength + Long.BYTES, b.length);
final int docIDB = reader.readVInt(); final int docIDB = reader.readInt();
final long ordB = reader.readVLong();
cmp = Integer.compare(docIDA, docIDB); // No need to tie break on ord, for the case where the same doc has the same value in a given dimension indexed more than once: it
if (cmp != 0) { // can't matter at search time since we don't write ords into the index:
return cmp; return Integer.compare(docIDA, docIDB);
}
// TODO: is this really necessary? If OfflineSorter is stable, we can safely return 0 here, and avoid writing ords?
return Long.compare(ordA, ordB);
} }
}; };
// TODO: this is sort of sneaky way to get the final OfflinePointWriter from OfflineSorter: // TODO: this is sort of sneaky way to get the final OfflinePointWriter from OfflineSorter:
IndexOutput[] lastWriter = new IndexOutput[1]; IndexOutput[] lastWriter = new IndexOutput[1];
OfflineSorter sorter = new OfflineSorter(tempDir, tempFileNamePrefix, cmp) { OfflineSorter sorter = new OfflineSorter(tempDir, tempFileNamePrefix, cmp, OfflineSorter.BufferSize.megabytes(Math.max(1, (long) maxMBSortInHeap)), OfflineSorter.MAX_TEMPFILES) {
/** We write/read fixed-byte-width file that {@link OfflinePointReader} can read. */ /** We write/read fixed-byte-width file that {@link OfflinePointReader} can read. */
@Override @Override
@ -753,7 +748,7 @@ public class BKDWriter implements Closeable {
/** Writes the BKD tree to the provided {@link IndexOutput} and returns the file offset where index was written. */ /** Writes the BKD tree to the provided {@link IndexOutput} and returns the file offset where index was written. */
public long finish(IndexOutput out) throws IOException { public long finish(IndexOutput out) throws IOException {
//System.out.println("\nBKDTreeWriter.finish pointCount=" + pointCount + " out=" + out + " heapWriter=" + heapWriter); // System.out.println("\nBKDTreeWriter.finish pointCount=" + pointCount + " out=" + out + " heapWriter=" + heapPointWriter);
// TODO: specialize the 1D case? it's much faster at indexing time (no partitioning on recruse...) // TODO: specialize the 1D case? it's much faster at indexing time (no partitioning on recruse...)

View File

@ -162,8 +162,8 @@ public class TestDuelingCodecs extends LuceneTestCase {
createRandomIndex(numdocs, leftWriter, seed); createRandomIndex(numdocs, leftWriter, seed);
createRandomIndex(numdocs, rightWriter, seed); createRandomIndex(numdocs, rightWriter, seed);
leftReader = wrapReader(leftWriter.getReader()); leftReader = wrapReader(leftWriter.getReader(), false);
rightReader = wrapReader(rightWriter.getReader()); rightReader = wrapReader(rightWriter.getReader(), false);
// check that our readers are valid // check that our readers are valid
TestUtil.checkReader(leftReader); TestUtil.checkReader(leftReader);

View File

@ -17,8 +17,16 @@
package org.apache.lucene.index; package org.apache.lucene.index;
import java.io.IOException;
import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.FilterCodec;
import org.apache.lucene.codecs.PointFormat;
import org.apache.lucene.codecs.PointReader;
import org.apache.lucene.codecs.PointWriter;
import org.apache.lucene.codecs.lucene60.Lucene60PointReader;
import org.apache.lucene.codecs.lucene60.Lucene60PointWriter;
import org.apache.lucene.document.BinaryPoint; import org.apache.lucene.document.BinaryPoint;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoublePoint; import org.apache.lucene.document.DoublePoint;
@ -26,6 +34,9 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.FloatPoint; import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.PointValues.IntersectVisitor;
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
@ -478,4 +489,55 @@ public class TestPointValues extends LuceneTestCase {
field.numericValue(); field.numericValue();
}); });
} }
public void testTieBreakByDocID() throws Exception {
Directory dir = newFSDirectory(createTempDir());
IndexWriterConfig iwc = newIndexWriterConfig();
IndexWriter w = new IndexWriter(dir, iwc);
Document doc = new Document();
doc.add(new IntPoint("int", 17));
for(int i=0;i<300000;i++) {
w.addDocument(doc);
if (false && random().nextInt(1000) == 17) {
w.commit();
}
}
IndexReader r = DirectoryReader.open(w);
for(LeafReaderContext ctx : r.leaves()) {
PointValues points = ctx.reader().getPointValues();
points.intersect("int",
new IntersectVisitor() {
int lastDocID = -1;
@Override
public void visit(int docID) {
if (docID < lastDocID) {
fail("docs out of order: docID=" + docID + " but lastDocID=" + lastDocID);
}
lastDocID = docID;
}
@Override
public void visit(int docID, byte[] packedValue) {
visit(docID);
}
@Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
if (random().nextBoolean()) {
return Relation.CELL_CROSSES_QUERY;
} else {
return Relation.CELL_INSIDE_QUERY;
}
}
});
}
r.close();
w.close();
dir.close();
}
} }

View File

@ -53,11 +53,13 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.MultiDocValues; import org.apache.lucene.index.MultiDocValues;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.PointValues; import org.apache.lucene.index.PointValues;
import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.SegmentReadState; import org.apache.lucene.index.SegmentReadState;
import org.apache.lucene.index.SegmentWriteState; import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.index.SlowCompositeReaderWrapper;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
@ -360,7 +362,7 @@ public class TestPointQueries extends LuceneTestCase {
final IndexReader r = w.getReader(); final IndexReader r = w.getReader();
w.close(); w.close();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
int numThreads = TestUtil.nextInt(random(), 2, 5); int numThreads = TestUtil.nextInt(random(), 2, 5);
@ -627,7 +629,7 @@ public class TestPointQueries extends LuceneTestCase {
final IndexReader r = w.getReader(); final IndexReader r = w.getReader();
w.close(); w.close();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
int numThreads = TestUtil.nextInt(random(), 2, 5); int numThreads = TestUtil.nextInt(random(), 2, 5);
@ -847,7 +849,7 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(1, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, 0L, true))); assertEquals(1, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, 0L, true)));
assertEquals(1, s.count(LongPoint.newRangeQuery("value", 0L, true, Long.MAX_VALUE, true))); assertEquals(1, s.count(LongPoint.newRangeQuery("value", 0L, true, Long.MAX_VALUE, true)));
@ -885,7 +887,7 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(1, s.count(BinaryPoint.newRangeQuery("value", assertEquals(1, s.count(BinaryPoint.newRangeQuery("value",
toUTF8("aaa"), toUTF8("aaa"),
@ -950,7 +952,7 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(2, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, true))); assertEquals(2, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, true)));
assertEquals(1, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, false))); assertEquals(1, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, false)));
@ -976,7 +978,6 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
// We can't wrap with "exotic" readers because the query must see the RangeTreeDVFormat:
IndexSearcher s = newSearcher(r, false); IndexSearcher s = newSearcher(r, false);
assertEquals(2, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, true))); assertEquals(2, s.count(LongPoint.newRangeQuery("value", Long.MIN_VALUE, true, Long.MAX_VALUE, true)));
@ -1003,7 +1004,7 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(BinaryPoint.newRangeQuery("value", toUTF8("m"), true, toUTF8("n"), false))); assertEquals(0, s.count(BinaryPoint.newRangeQuery("value", toUTF8("m"), true, toUTF8("n"), false)));
assertEquals(2, s.count(BinaryPoint.newRangeQuery("value", (byte[]) null, true, null, true))); assertEquals(2, s.count(BinaryPoint.newRangeQuery("value", (byte[]) null, true, null, true)));
@ -1040,7 +1041,7 @@ public class TestPointQueries extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(LongPoint.newRangeQuery("value", 17L, true, 13L, false))); assertEquals(0, s.count(LongPoint.newRangeQuery("value", 17L, true, 13L, false)));
IOUtils.close(r, w, dir); IOUtils.close(r, w, dir);
@ -1207,7 +1208,7 @@ public class TestPointQueries extends LuceneTestCase {
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(1, s.count(IntPoint.newExactQuery("int", 42))); assertEquals(1, s.count(IntPoint.newExactQuery("int", 42)));
assertEquals(0, s.count(IntPoint.newExactQuery("int", 41))); assertEquals(0, s.count(IntPoint.newExactQuery("int", 41)));
@ -1328,7 +1329,7 @@ public class TestPointQueries extends LuceneTestCase {
final IndexReader r = w.getReader(); final IndexReader r = w.getReader();
w.close(); w.close();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
int numThreads = TestUtil.nextInt(random(), 2, 5); int numThreads = TestUtil.nextInt(random(), 2, 5);
@ -1467,7 +1468,7 @@ public class TestPointQueries extends LuceneTestCase {
doc.add(new IntPoint("int", 17, 42)); doc.add(new IntPoint("int", 17, 42));
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(newMultiDimIntSetQuery("int", 2, 17, 41))); assertEquals(0, s.count(newMultiDimIntSetQuery("int", 2, 17, 41)));
assertEquals(1, s.count(newMultiDimIntSetQuery("int", 2, 17, 42))); assertEquals(1, s.count(newMultiDimIntSetQuery("int", 2, 17, 42)));
@ -1490,7 +1491,7 @@ public class TestPointQueries extends LuceneTestCase {
doc.add(new IntPoint("int", 34, 79)); doc.add(new IntPoint("int", 34, 79));
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(newMultiDimIntSetQuery("int", 2, 17, 41))); assertEquals(0, s.count(newMultiDimIntSetQuery("int", 2, 17, 41)));
assertEquals(1, s.count(newMultiDimIntSetQuery("int", 2, 17, 42))); assertEquals(1, s.count(newMultiDimIntSetQuery("int", 2, 17, 42)));
@ -1523,7 +1524,7 @@ public class TestPointQueries extends LuceneTestCase {
w.addDocument(doc); w.addDocument(doc);
} }
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(zeroCount, s.count(newMultiDimIntSetQuery("int", 2, 0, 0))); assertEquals(zeroCount, s.count(newMultiDimIntSetQuery("int", 2, 0, 0)));
assertEquals(10000-zeroCount, s.count(newMultiDimIntSetQuery("int", 2, 1, 1))); assertEquals(10000-zeroCount, s.count(newMultiDimIntSetQuery("int", 2, 1, 1)));
@ -1573,7 +1574,7 @@ public class TestPointQueries extends LuceneTestCase {
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(IntPoint.newSetQuery("int", 16))); assertEquals(0, s.count(IntPoint.newSetQuery("int", 16)));
assertEquals(1, s.count(IntPoint.newSetQuery("int", 17))); assertEquals(1, s.count(IntPoint.newSetQuery("int", 17)));
assertEquals(3, s.count(IntPoint.newSetQuery("int", 17, 97, 42))); assertEquals(3, s.count(IntPoint.newSetQuery("int", 17, 97, 42)));
@ -1634,7 +1635,7 @@ public class TestPointQueries extends LuceneTestCase {
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(IntPoint.newSetQuery("int", 16))); assertEquals(0, s.count(IntPoint.newSetQuery("int", 16)));
assertEquals(1, s.count(IntPoint.newSetQuery("int", 17))); assertEquals(1, s.count(IntPoint.newSetQuery("int", 17)));
assertEquals(1, s.count(IntPoint.newSetQuery("int", 17, 97, 42))); assertEquals(1, s.count(IntPoint.newSetQuery("int", 17, 97, 42)));
@ -1685,7 +1686,7 @@ public class TestPointQueries extends LuceneTestCase {
w.addDocument(doc); w.addDocument(doc);
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(0, s.count(IntPoint.newSetQuery("int"))); assertEquals(0, s.count(IntPoint.newSetQuery("int")));
assertEquals(0, s.count(LongPoint.newSetQuery("long"))); assertEquals(0, s.count(LongPoint.newSetQuery("long")));
assertEquals(0, s.count(FloatPoint.newSetQuery("float"))); assertEquals(0, s.count(FloatPoint.newSetQuery("float")));
@ -1719,7 +1720,7 @@ public class TestPointQueries extends LuceneTestCase {
} }
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0)));
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0, -7))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0, -7)));
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 7, 0))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 7, 0)));
@ -1777,7 +1778,7 @@ public class TestPointQueries extends LuceneTestCase {
} }
IndexReader r = DirectoryReader.open(w); IndexReader r = DirectoryReader.open(w);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0)));
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0, -7))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 0, -7)));
assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 7, 0))); assertEquals(zeroCount, s.count(IntPoint.newSetQuery("int", 7, 0)));

View File

@ -218,7 +218,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
final TaxonomyReader tr = new DirectoryTaxonomyReader(tw); final TaxonomyReader tr = new DirectoryTaxonomyReader(tw);
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
if (VERBOSE) { if (VERBOSE) {
System.out.println("TEST: searcher=" + s); System.out.println("TEST: searcher=" + s);
@ -375,7 +375,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
} }
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
FacetsConfig config = new FacetsConfig(); FacetsConfig config = new FacetsConfig();
int numIters = atLeast(10); int numIters = atLeast(10);
@ -516,7 +516,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
} }
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
FacetsConfig config = new FacetsConfig(); FacetsConfig config = new FacetsConfig();
int numIters = atLeast(10); int numIters = atLeast(10);
@ -671,7 +671,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
} }
IndexReader r = w.getReader(); IndexReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
FacetsConfig config = new FacetsConfig(); FacetsConfig config = new FacetsConfig();
int numIters = atLeast(10); int numIters = atLeast(10);

View File

@ -174,7 +174,8 @@ public abstract class SorterTestBase extends LuceneTestCase {
doc.add(new Field(TERM_VECTORS_FIELD, Integer.toString(id), TERM_VECTORS_TYPE)); doc.add(new Field(TERM_VECTORS_FIELD, Integer.toString(id), TERM_VECTORS_TYPE));
byte[] bytes = new byte[4]; byte[] bytes = new byte[4];
NumericUtils.intToBytes(id, bytes, 0); NumericUtils.intToBytes(id, bytes, 0);
doc.add(new BinaryPoint(DIMENSIONAL_FIELD, bytes)); // TODO: index time sorting doesn't yet support points
//doc.add(new BinaryPoint(DIMENSIONAL_FIELD, bytes));
return doc; return doc;
} }
@ -378,6 +379,8 @@ public abstract class SorterTestBase extends LuceneTestCase {
} }
} }
// TODO: index sorting doesn't yet support points
/*
public void testPoints() throws Exception { public void testPoints() throws Exception {
PointValues values = sortedReader.getPointValues(); PointValues values = sortedReader.getPointValues();
values.intersect(DIMENSIONAL_FIELD, values.intersect(DIMENSIONAL_FIELD,
@ -398,4 +401,5 @@ public abstract class SorterTestBase extends LuceneTestCase {
} }
}); });
} }
*/
} }

View File

@ -40,7 +40,7 @@ public class TestBigIntegerPoint extends LuceneTestCase {
// search and verify we found our doc // search and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(BigIntegerPoint.newExactQuery("field", large))); assertEquals(1, searcher.count(BigIntegerPoint.newExactQuery("field", large)));
assertEquals(1, searcher.count(BigIntegerPoint.newRangeQuery("field", large.subtract(BigInteger.ONE), false, large.add(BigInteger.ONE), false))); assertEquals(1, searcher.count(BigIntegerPoint.newRangeQuery("field", large.subtract(BigInteger.ONE), false, large.add(BigInteger.ONE), false)));
assertEquals(1, searcher.count(BigIntegerPoint.newSetQuery("field", large))); assertEquals(1, searcher.count(BigIntegerPoint.newSetQuery("field", large)));
@ -65,7 +65,7 @@ public class TestBigIntegerPoint extends LuceneTestCase {
// search and verify we found our doc // search and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(BigIntegerPoint.newExactQuery("field", negative))); assertEquals(1, searcher.count(BigIntegerPoint.newExactQuery("field", negative)));
assertEquals(1, searcher.count(BigIntegerPoint.newRangeQuery("field", negative.subtract(BigInteger.ONE), false, negative.add(BigInteger.ONE), false))); assertEquals(1, searcher.count(BigIntegerPoint.newRangeQuery("field", negative.subtract(BigInteger.ONE), false, negative.add(BigInteger.ONE), false)));

View File

@ -40,7 +40,7 @@ public class TestInetAddressPoint extends LuceneTestCase {
// search and verify we found our doc // search and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(InetAddressPoint.newExactQuery("field", address))); assertEquals(1, searcher.count(InetAddressPoint.newExactQuery("field", address)));
assertEquals(1, searcher.count(InetAddressPoint.newPrefixQuery("field", address, 24))); assertEquals(1, searcher.count(InetAddressPoint.newPrefixQuery("field", address, 24)));
assertEquals(1, searcher.count(InetAddressPoint.newRangeQuery("field", InetAddress.getByName("1.2.3.3"), false, InetAddress.getByName("1.2.3.5"), false))); assertEquals(1, searcher.count(InetAddressPoint.newRangeQuery("field", InetAddress.getByName("1.2.3.3"), false, InetAddress.getByName("1.2.3.5"), false)));
@ -66,7 +66,7 @@ public class TestInetAddressPoint extends LuceneTestCase {
// search and verify we found our doc // search and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(InetAddressPoint.newExactQuery("field", address))); assertEquals(1, searcher.count(InetAddressPoint.newExactQuery("field", address)));
assertEquals(1, searcher.count(InetAddressPoint.newPrefixQuery("field", address, 64))); assertEquals(1, searcher.count(InetAddressPoint.newPrefixQuery("field", address, 64)));
assertEquals(1, searcher.count(InetAddressPoint.newRangeQuery("field", InetAddress.getByName("fec0::f66c"), false, InetAddress.getByName("fec0::f66e"), false))); assertEquals(1, searcher.count(InetAddressPoint.newRangeQuery("field", InetAddress.getByName("fec0::f66c"), false, InetAddress.getByName("fec0::f66e"), false)));

View File

@ -38,7 +38,7 @@ public class TestLatLonPoint extends LuceneTestCase {
// search and verify we found our doc // search and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(LatLonPoint.newBoxQuery("field", 18, 19, -66, -65))); assertEquals(1, searcher.count(LatLonPoint.newBoxQuery("field", 18, 19, -66, -65)));
reader.close(); reader.close();

View File

@ -55,7 +55,7 @@ public class TestLatLonPointDistanceQuery extends LuceneTestCase {
// search within 50km and verify we found our doc // search within 50km and verify we found our doc
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader, false);
assertEquals(1, searcher.count(LatLonPoint.newDistanceQuery("field", 18, -65, 50_000))); assertEquals(1, searcher.count(LatLonPoint.newDistanceQuery("field", 18, -65, 50_000)));
reader.close(); reader.close();

View File

@ -60,7 +60,7 @@ public class TestDocValuesRangeQuery extends LuceneTestCase {
} }
iw.commit(); iw.commit();
final IndexReader reader = iw.getReader(); final IndexReader reader = iw.getReader();
final IndexSearcher searcher = newSearcher(reader); final IndexSearcher searcher = newSearcher(reader, false);
iw.close(); iw.close();
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
@ -188,7 +188,7 @@ public class TestDocValuesRangeQuery extends LuceneTestCase {
} }
iw.commit(); iw.commit();
final IndexReader reader = iw.getReader(); final IndexReader reader = iw.getReader();
final IndexSearcher searcher = newSearcher(reader); final IndexSearcher searcher = newSearcher(reader, false);
iw.close(); iw.close();
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {

View File

@ -17,6 +17,7 @@
package org.apache.lucene.codecs.asserting; package org.apache.lucene.codecs.asserting;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import org.apache.lucene.codecs.PointFormat; import org.apache.lucene.codecs.PointFormat;
@ -24,9 +25,13 @@ import org.apache.lucene.codecs.PointReader;
import org.apache.lucene.codecs.PointWriter; import org.apache.lucene.codecs.PointWriter;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.MergeState; import org.apache.lucene.index.MergeState;
import org.apache.lucene.index.PointValues.IntersectVisitor;
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.index.SegmentReadState; import org.apache.lucene.index.SegmentReadState;
import org.apache.lucene.index.SegmentWriteState; import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.util.Accountable; import org.apache.lucene.util.Accountable;
import org.apache.lucene.util.StringHelper;
import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.TestUtil;
/** /**
@ -61,6 +66,83 @@ public final class AssertingPointFormat extends PointFormat {
return new AssertingPointReader(in.fieldsReader(state)); return new AssertingPointReader(in.fieldsReader(state));
} }
/** Validates in the 1D case that all points are visited in order, and point values are in bounds of the last cell checked */
static class AssertingIntersectVisitor implements IntersectVisitor {
final IntersectVisitor in;
final int numDims;
final int bytesPerDim;
final byte[] lastDocValue;
final byte[] lastMinPackedValue;
final byte[] lastMaxPackedValue;
private Relation lastCompareResult;
private int lastDocID = -1;
public AssertingIntersectVisitor(int numDims, int bytesPerDim, IntersectVisitor in) {
this.in = in;
this.numDims = numDims;
this.bytesPerDim = bytesPerDim;
lastMaxPackedValue = new byte[numDims*bytesPerDim];
lastMinPackedValue = new byte[numDims*bytesPerDim];
if (numDims == 1) {
lastDocValue = new byte[bytesPerDim];
} else {
lastDocValue = null;
}
}
@Override
public void visit(int docID) throws IOException {
// This method, not filtering each hit, should only be invoked when the cell is inside the query shape:
assert lastCompareResult == Relation.CELL_INSIDE_QUERY;
in.visit(docID);
}
@Override
public void visit(int docID, byte[] packedValue) throws IOException {
// This method, to filter each doc's value, should only be invoked when the cell crosses the query shape:
assert lastCompareResult == PointValues.Relation.CELL_CROSSES_QUERY;
// This doc's packed value should be contained in the last cell passed to compare:
for(int dim=0;dim<numDims;dim++) {
assert StringHelper.compare(bytesPerDim, lastMinPackedValue, dim*bytesPerDim, packedValue, dim*bytesPerDim) <= 0: "dim=" + dim + " of " + numDims;
assert StringHelper.compare(bytesPerDim, lastMaxPackedValue, dim*bytesPerDim, packedValue, dim*bytesPerDim) >= 0: "dim=" + dim + " of " + numDims;
}
// TODO: we should assert that this "matches" whatever relation the last call to compare had returned
assert packedValue.length == numDims * bytesPerDim;
if (numDims == 1) {
int cmp = StringHelper.compare(bytesPerDim, lastDocValue, 0, packedValue, 0);
if (cmp < 0) {
// ok
} else if (cmp == 0) {
assert lastDocID <= docID: "doc ids are out of order when point values are the same!";
} else {
// out of order!
assert false: "point values are out of order";
}
System.arraycopy(packedValue, 0, lastDocValue, 0, bytesPerDim);
}
in.visit(docID, packedValue);
}
@Override
public void grow(int count) {
in.grow(count);
}
@Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
for(int dim=0;dim<numDims;dim++) {
assert StringHelper.compare(bytesPerDim, minPackedValue, dim*bytesPerDim, maxPackedValue, dim*bytesPerDim) <= 0;
}
System.arraycopy(maxPackedValue, 0, lastMaxPackedValue, 0, numDims*bytesPerDim);
System.arraycopy(minPackedValue, 0, lastMinPackedValue, 0, numDims*bytesPerDim);
lastCompareResult = in.compare(minPackedValue, maxPackedValue);
return lastCompareResult;
}
}
static class AssertingPointReader extends PointReader { static class AssertingPointReader extends PointReader {
private final PointReader in; private final PointReader in;
@ -80,8 +162,8 @@ public final class AssertingPointFormat extends PointFormat {
@Override @Override
public void intersect(String fieldName, IntersectVisitor visitor) throws IOException { public void intersect(String fieldName, IntersectVisitor visitor) throws IOException {
// TODO: wrap the visitor and make sure things are being reasonable in.intersect(fieldName,
in.intersect(fieldName, visitor); new AssertingIntersectVisitor(in.getNumDimensions(fieldName), in.getBytesPerDimension(fieldName), visitor));
} }
@Override @Override

View File

@ -163,29 +163,31 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
w.close(); w.close();
DirectoryReader r = DirectoryReader.open(dir); DirectoryReader r = DirectoryReader.open(dir);
assertEquals(1, r.numDocs()); assertEquals(1, r.numDocs());
PointValues values = MultiPointValues.get(r);
Bits liveDocs = MultiFields.getLiveDocs(r); Bits liveDocs = MultiFields.getLiveDocs(r);
NumericDocValues idValues = MultiDocValues.getNumericValues(r, "id");
if (values != null) { for(LeafReaderContext ctx : r.leaves()) {
BitSet seen = new BitSet(); PointValues values = ctx.reader().getPointValues();
values.intersect("dim", NumericDocValues idValues = ctx.reader().getNumericDocValues("id");
new IntersectVisitor() { if (values != null) {
@Override BitSet seen = new BitSet();
public Relation compare(byte[] minPacked, byte[] maxPacked) { values.intersect("dim",
return Relation.CELL_CROSSES_QUERY; new IntersectVisitor() {
} @Override
public void visit(int docID) { public Relation compare(byte[] minPacked, byte[] maxPacked) {
throw new IllegalStateException(); return Relation.CELL_CROSSES_QUERY;
}
public void visit(int docID, byte[] packedValue) {
if (liveDocs.get(docID)) {
seen.set(docID);
} }
assertEquals(idValues.get(docID), NumericUtils.bytesToInt(packedValue, 0)); public void visit(int docID) {
} throw new IllegalStateException();
}); }
assertEquals(0, seen.cardinality()); public void visit(int docID, byte[] packedValue) {
if (liveDocs.get(docID)) {
seen.set(docID);
}
assertEquals(idValues.get(docID), NumericUtils.bytesToInt(packedValue, 0));
}
});
assertEquals(0, seen.cardinality());
}
} }
IOUtils.close(r, dir); IOUtils.close(r, dir);
} }
@ -361,8 +363,6 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
DirectoryReader r = w.getReader(); DirectoryReader r = w.getReader();
w.close(); w.close();
PointValues dimValues = MultiPointValues.get(r);
int iters = atLeast(100); int iters = atLeast(100);
for(int iter=0;iter<iters;iter++) { for(int iter=0;iter<iters;iter++) {
if (VERBOSE) { if (VERBOSE) {
@ -386,50 +386,59 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
} }
final BitSet hits = new BitSet(); final BitSet hits = new BitSet();
dimValues.intersect("field", new IntersectVisitor() { for(LeafReaderContext ctx : r.leaves()) {
@Override PointValues dimValues = ctx.reader().getPointValues();
public void visit(int docID) { if (dimValues == null) {
hits.set(docID); continue;
//System.out.println("visit docID=" + docID); }
}
@Override final int docBase = ctx.docBase;
public void visit(int docID, byte[] packedValue) {
//System.out.println("visit check docID=" + docID); dimValues.intersect("field", new IntersectVisitor() {
for(int dim=0;dim<numDims;dim++) { @Override
BigInteger x = NumericUtils.bytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim); public void visit(int docID) {
if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) { hits.set(docBase+docID);
//System.out.println(" no"); //System.out.println("visit docID=" + docID);
return; }
@Override
public void visit(int docID, byte[] packedValue) {
//System.out.println("visit check docID=" + docID);
for(int dim=0;dim<numDims;dim++) {
BigInteger x = NumericUtils.bytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim);
if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) {
//System.out.println(" no");
return;
}
}
//System.out.println(" yes");
hits.set(docBase+docID);
}
@Override
public Relation compare(byte[] minPacked, byte[] maxPacked) {
boolean crosses = false;
for(int dim=0;dim<numDims;dim++) {
BigInteger min = NumericUtils.bytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim);
BigInteger max = NumericUtils.bytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim);
assert max.compareTo(min) >= 0;
if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) {
return Relation.CELL_OUTSIDE_QUERY;
} else if (min.compareTo(queryMin[dim]) < 0 || max.compareTo(queryMax[dim]) > 0) {
crosses = true;
}
}
if (crosses) {
return Relation.CELL_CROSSES_QUERY;
} else {
return Relation.CELL_INSIDE_QUERY;
} }
} }
});
//System.out.println(" yes"); }
hits.set(docID);
}
@Override
public Relation compare(byte[] minPacked, byte[] maxPacked) {
boolean crosses = false;
for(int dim=0;dim<numDims;dim++) {
BigInteger min = NumericUtils.bytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim);
BigInteger max = NumericUtils.bytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim);
assert max.compareTo(min) >= 0;
if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) {
return Relation.CELL_OUTSIDE_QUERY;
} else if (min.compareTo(queryMin[dim]) < 0 || max.compareTo(queryMax[dim]) > 0) {
crosses = true;
}
}
if (crosses) {
return Relation.CELL_CROSSES_QUERY;
} else {
return Relation.CELL_INSIDE_QUERY;
}
}
});
for(int docID=0;docID<numDocs;docID++) { for(int docID=0;docID<numDocs;docID++) {
BigInteger[] docValues = docs[docID]; BigInteger[] docValues = docs[docID];
@ -665,24 +674,39 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
System.out.println("TEST: reader=" + r); System.out.println("TEST: reader=" + r);
} }
PointValues dimValues = MultiPointValues.get(r);
if (VERBOSE) {
System.out.println(" dimValues=" + dimValues);
}
assertNotNull(dimValues);
NumericDocValues idValues = MultiDocValues.getNumericValues(r, "id"); NumericDocValues idValues = MultiDocValues.getNumericValues(r, "id");
Bits liveDocs = MultiFields.getLiveDocs(r); Bits liveDocs = MultiFields.getLiveDocs(r);
// Verify min/max values are correct: // Verify min/max values are correct:
byte[] minValues = dimValues.getMinPackedValue("field"); byte[] minValues = new byte[numDims*numBytesPerDim];
byte[] maxValues = dimValues.getMaxPackedValue("field"); Arrays.fill(minValues, (byte) 0xff);
byte[] maxValues = new byte[numDims*numBytesPerDim];
for(LeafReaderContext ctx : r.leaves()) {
PointValues dimValues = ctx.reader().getPointValues();
if (dimValues == null) {
continue;
}
byte[] leafMinValues = dimValues.getMinPackedValue("field");
byte[] leafMaxValues = dimValues.getMaxPackedValue("field");
for(int dim=0;dim<numDims;dim++) {
if (StringHelper.compare(numBytesPerDim, leafMinValues, dim*numBytesPerDim, minValues, dim*numBytesPerDim) < 0) {
System.arraycopy(leafMinValues, dim*numBytesPerDim, minValues, dim*numBytesPerDim, numBytesPerDim);
}
if (StringHelper.compare(numBytesPerDim, leafMaxValues, dim*numBytesPerDim, maxValues, dim*numBytesPerDim) > 0) {
System.arraycopy(leafMaxValues, dim*numBytesPerDim, maxValues, dim*numBytesPerDim, numBytesPerDim);
}
}
}
byte[] scratch = new byte[numBytesPerDim]; byte[] scratch = new byte[numBytesPerDim];
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
System.arraycopy(minValues, dim*numBytesPerDim, scratch, 0, scratch.length); System.arraycopy(minValues, dim*numBytesPerDim, scratch, 0, numBytesPerDim);
//System.out.println("dim=" + dim + " expectedMin=" + new BytesRef(expectedMinValues[dim]) + " min=" + new BytesRef(scratch)); //System.out.println("dim=" + dim + " expectedMin=" + new BytesRef(expectedMinValues[dim]) + " min=" + new BytesRef(scratch));
assertTrue(Arrays.equals(expectedMinValues[dim], scratch)); assertTrue(Arrays.equals(expectedMinValues[dim], scratch));
System.arraycopy(maxValues, dim*numBytesPerDim, scratch, 0, scratch.length); System.arraycopy(maxValues, dim*numBytesPerDim, scratch, 0, numBytesPerDim);
//System.out.println("dim=" + dim + " expectedMax=" + new BytesRef(expectedMaxValues[dim]) + " max=" + new BytesRef(scratch)); //System.out.println("dim=" + dim + " expectedMax=" + new BytesRef(expectedMaxValues[dim]) + " max=" + new BytesRef(scratch));
assertTrue(Arrays.equals(expectedMaxValues[dim], scratch)); assertTrue(Arrays.equals(expectedMaxValues[dim], scratch));
} }
@ -716,58 +740,68 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
final BitSet hits = new BitSet(); final BitSet hits = new BitSet();
dimValues.intersect("field", new PointValues.IntersectVisitor() { for(LeafReaderContext ctx : r.leaves()) {
@Override PointValues dimValues = ctx.reader().getPointValues();
public void visit(int docID) { if (dimValues == null) {
if (liveDocs == null || liveDocs.get(docID)) { continue;
hits.set((int) idValues.get(docID)); }
}
//System.out.println("visit docID=" + docID);
}
@Override final int docBase = ctx.docBase;
public void visit(int docID, byte[] packedValue) {
if (liveDocs != null && liveDocs.get(docID) == false) { dimValues.intersect("field", new PointValues.IntersectVisitor() {
return; @Override
public void visit(int docID) {
if (liveDocs == null || liveDocs.get(docBase+docID)) {
hits.set((int) idValues.get(docBase+docID));
}
//System.out.println("visit docID=" + docID);
} }
//System.out.println("visit check docID=" + docID + " id=" + idValues.get(docID));
for(int dim=0;dim<numDims;dim++) { @Override
//System.out.println(" dim=" + dim + " value=" + new BytesRef(packedValue, dim*numBytesPerDim, numBytesPerDim)); public void visit(int docID, byte[] packedValue) {
if (StringHelper.compare(numBytesPerDim, packedValue, dim*numBytesPerDim, queryMin[dim], 0) < 0 || if (liveDocs != null && liveDocs.get(docBase+docID) == false) {
StringHelper.compare(numBytesPerDim, packedValue, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
//System.out.println(" no");
return; return;
} }
//System.out.println("visit check docID=" + docID + " id=" + idValues.get(docID));
for(int dim=0;dim<numDims;dim++) {
//System.out.println(" dim=" + dim + " value=" + new BytesRef(packedValue, dim*numBytesPerDim, numBytesPerDim));
if (StringHelper.compare(numBytesPerDim, packedValue, dim*numBytesPerDim, queryMin[dim], 0) < 0 ||
StringHelper.compare(numBytesPerDim, packedValue, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
//System.out.println(" no");
return;
}
}
//System.out.println(" yes");
hits.set((int) idValues.get(docBase+docID));
} }
//System.out.println(" yes"); @Override
hits.set((int) idValues.get(docID)); public Relation compare(byte[] minPacked, byte[] maxPacked) {
} boolean crosses = false;
//System.out.println("compare");
for(int dim=0;dim<numDims;dim++) {
if (StringHelper.compare(numBytesPerDim, maxPacked, dim*numBytesPerDim, queryMin[dim], 0) < 0 ||
StringHelper.compare(numBytesPerDim, minPacked, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
//System.out.println(" query_outside_cell");
return Relation.CELL_OUTSIDE_QUERY;
} else if (StringHelper.compare(numBytesPerDim, minPacked, dim*numBytesPerDim, queryMin[dim], 0) < 0 ||
StringHelper.compare(numBytesPerDim, maxPacked, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
crosses = true;
}
}
@Override if (crosses) {
public Relation compare(byte[] minPacked, byte[] maxPacked) { //System.out.println(" query_crosses_cell");
boolean crosses = false; return Relation.CELL_CROSSES_QUERY;
//System.out.println("compare"); } else {
for(int dim=0;dim<numDims;dim++) { //System.out.println(" cell_inside_query");
if (StringHelper.compare(numBytesPerDim, maxPacked, dim*numBytesPerDim, queryMin[dim], 0) < 0 || return Relation.CELL_INSIDE_QUERY;
StringHelper.compare(numBytesPerDim, minPacked, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
//System.out.println(" query_outside_cell");
return Relation.CELL_OUTSIDE_QUERY;
} else if (StringHelper.compare(numBytesPerDim, minPacked, dim*numBytesPerDim, queryMin[dim], 0) < 0 ||
StringHelper.compare(numBytesPerDim, maxPacked, dim*numBytesPerDim, queryMax[dim], 0) > 0) {
crosses = true;
} }
} }
});
if (crosses) { }
//System.out.println(" query_crosses_cell");
return Relation.CELL_CROSSES_QUERY;
} else {
//System.out.println(" cell_inside_query");
return Relation.CELL_INSIDE_QUERY;
}
}
});
BitSet expected = new BitSet(); BitSet expected = new BitSet();
for(int ord=0;ord<numValues;ord++) { for(int ord=0;ord<numValues;ord++) {
@ -845,7 +879,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
w.forceMerge(1); w.forceMerge(1);
DirectoryReader r = w.getReader(); DirectoryReader r = w.getReader();
IndexSearcher s = newSearcher(r); IndexSearcher s = newSearcher(r, false);
assertEquals(2, s.count(IntPoint.newExactQuery("int1", 17))); assertEquals(2, s.count(IntPoint.newExactQuery("int1", 17)));
assertEquals(2, s.count(IntPoint.newExactQuery("int2", 42))); assertEquals(2, s.count(IntPoint.newExactQuery("int2", 42)));
r.close(); r.close();

View File

@ -1625,6 +1625,10 @@ public abstract class LuceneTestCase extends Assert {
} }
public static IndexReader wrapReader(IndexReader r) throws IOException { public static IndexReader wrapReader(IndexReader r) throws IOException {
return wrapReader(r, true);
}
public static IndexReader wrapReader(IndexReader r, boolean allowSlowCompositeReader) throws IOException {
Random random = random(); Random random = random();
// TODO: remove this, and fix those tests to wrap before putting slow around: // TODO: remove this, and fix those tests to wrap before putting slow around:
@ -1632,10 +1636,12 @@ public abstract class LuceneTestCase extends Assert {
for (int i = 0, c = random.nextInt(6)+1; i < c; i++) { for (int i = 0, c = random.nextInt(6)+1; i < c; i++) {
switch(random.nextInt(6)) { switch(random.nextInt(6)) {
case 0: case 0:
if (VERBOSE) { if (allowSlowCompositeReader) {
System.out.println("NOTE: LuceneTestCase.wrapReader: wrapping previous reader=" + r + " with SlowCompositeReaderWrapper.wrap"); if (VERBOSE) {
System.out.println("NOTE: LuceneTestCase.wrapReader: wrapping previous reader=" + r + " with SlowCompositeReaderWrapper.wrap");
}
r = SlowCompositeReaderWrapper.wrap(r);
} }
r = SlowCompositeReaderWrapper.wrap(r);
break; break;
case 1: case 1:
// will create no FC insanity in atomic case, as ParallelLeafReader has own cache key: // will create no FC insanity in atomic case, as ParallelLeafReader has own cache key:
@ -1656,22 +1662,24 @@ public abstract class LuceneTestCase extends Assert {
r = new FCInvisibleMultiReader(r); r = new FCInvisibleMultiReader(r);
break; break;
case 3: case 3:
final LeafReader ar = SlowCompositeReaderWrapper.wrap(r); if (allowSlowCompositeReader) {
final List<String> allFields = new ArrayList<>(); final LeafReader ar = SlowCompositeReaderWrapper.wrap(r);
for (FieldInfo fi : ar.getFieldInfos()) { final List<String> allFields = new ArrayList<>();
allFields.add(fi.name); for (FieldInfo fi : ar.getFieldInfos()) {
allFields.add(fi.name);
}
Collections.shuffle(allFields, random);
final int end = allFields.isEmpty() ? 0 : random.nextInt(allFields.size());
final Set<String> fields = new HashSet<>(allFields.subList(0, end));
// will create no FC insanity as ParallelLeafReader has own cache key:
if (VERBOSE) {
System.out.println("NOTE: LuceneTestCase.wrapReader: wrapping previous reader=" + r + " with ParallelLeafReader(SlowCompositeReaderWapper)");
}
r = new ParallelLeafReader(
new FieldFilterLeafReader(ar, fields, false),
new FieldFilterLeafReader(ar, fields, true)
);
} }
Collections.shuffle(allFields, random);
final int end = allFields.isEmpty() ? 0 : random.nextInt(allFields.size());
final Set<String> fields = new HashSet<>(allFields.subList(0, end));
// will create no FC insanity as ParallelLeafReader has own cache key:
if (VERBOSE) {
System.out.println("NOTE: LuceneTestCase.wrapReader: wrapping previous reader=" + r + " with ParallelLeafReader(SlowCompositeReaderWapper)");
}
r = new ParallelLeafReader(
new FieldFilterLeafReader(ar, fields, false),
new FieldFilterLeafReader(ar, fields, true)
);
break; break;
case 4: case 4:
// Häckidy-Hick-Hack: a standard Reader will cause FC insanity, so we use // Häckidy-Hick-Hack: a standard Reader will cause FC insanity, so we use
@ -1701,7 +1709,9 @@ public abstract class LuceneTestCase extends Assert {
} }
} }
if (wasOriginallyAtomic) { if (wasOriginallyAtomic) {
r = SlowCompositeReaderWrapper.wrap(r); if (allowSlowCompositeReader) {
r = SlowCompositeReaderWrapper.wrap(r);
}
} else if ((r instanceof CompositeReader) && !(r instanceof FCInvisibleMultiReader)) { } else if ((r instanceof CompositeReader) && !(r instanceof FCInvisibleMultiReader)) {
// prevent cache insanity caused by e.g. ParallelCompositeReader, to fix we wrap one more time: // prevent cache insanity caused by e.g. ParallelCompositeReader, to fix we wrap one more time:
r = new FCInvisibleMultiReader(r); r = new FCInvisibleMultiReader(r);
@ -2588,40 +2598,45 @@ public abstract class LuceneTestCase extends Assert {
} }
// naive silly memory heavy uninversion!! maps docID -> packed values (a Set because a given doc can be multi-valued) // naive silly memory heavy uninversion!! maps docID -> packed values (a Set because a given doc can be multi-valued)
private Map<Integer,Set<BytesRef>> uninvert(String fieldName, PointValues points) throws IOException { private Map<Integer,Set<BytesRef>> uninvert(String fieldName, IndexReader reader) throws IOException {
final Map<Integer,Set<BytesRef>> docValues = new HashMap<>(); final Map<Integer,Set<BytesRef>> docValues = new HashMap<>();
points.intersect(fieldName, new PointValues.IntersectVisitor() { for(LeafReaderContext ctx : reader.leaves()) {
@Override
public void visit(int docID) {
throw new UnsupportedOperationException();
}
@Override PointValues points = ctx.reader().getPointValues();
public void visit(int docID, byte[] packedValue) throws IOException { if (points == null) {
if (docValues.containsKey(docID) == false) { continue;
docValues.put(docID, new HashSet<BytesRef>()); }
}
docValues.get(docID).add(new BytesRef(packedValue.clone())); points.intersect(fieldName,
} new PointValues.IntersectVisitor() {
@Override
public void visit(int docID) {
throw new UnsupportedOperationException();
}
@Override
public void visit(int docID, byte[] packedValue) throws IOException {
int topDocID = ctx.docBase + docID;
if (docValues.containsKey(topDocID) == false) {
docValues.put(topDocID, new HashSet<BytesRef>());
}
docValues.get(topDocID).add(new BytesRef(packedValue.clone()));
}
@Override
public PointValues.Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
// We pretend our query shape is so hairy that it crosses every single cell:
return PointValues.Relation.CELL_CROSSES_QUERY;
}
});
}
@Override
public PointValues.Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
// We pretend our query shape is so hairy that it crosses every single cell:
return PointValues.Relation.CELL_CROSSES_QUERY;
}
});
return docValues; return docValues;
} }
public void assertPointsEquals(String info, IndexReader leftReader, IndexReader rightReader) throws IOException { public void assertPointsEquals(String info, IndexReader leftReader, IndexReader rightReader) throws IOException {
assertPointsEquals(info, FieldInfos fieldInfos1 = MultiFields.getMergedFieldInfos(leftReader);
MultiFields.getMergedFieldInfos(leftReader), FieldInfos fieldInfos2 = MultiFields.getMergedFieldInfos(rightReader);
MultiPointValues.get(leftReader),
MultiFields.getMergedFieldInfos(rightReader),
MultiPointValues.get(rightReader));
}
public void assertPointsEquals(String info, FieldInfos fieldInfos1, PointValues points1, FieldInfos fieldInfos2, PointValues points2) throws IOException {
for(FieldInfo fieldInfo1 : fieldInfos1) { for(FieldInfo fieldInfo1 : fieldInfos1) {
if (fieldInfo1.getPointDimensionCount() != 0) { if (fieldInfo1.getPointDimensionCount() != 0) {
FieldInfo fieldInfo2 = fieldInfos2.fieldInfo(fieldInfo1.name); FieldInfo fieldInfo2 = fieldInfos2.fieldInfo(fieldInfo1.name);
@ -2631,8 +2646,8 @@ public abstract class LuceneTestCase extends Assert {
assertEquals(info, fieldInfo2.getPointNumBytes(), fieldInfo2.getPointNumBytes()); assertEquals(info, fieldInfo2.getPointNumBytes(), fieldInfo2.getPointNumBytes());
assertEquals(info + " field=" + fieldInfo1.name, assertEquals(info + " field=" + fieldInfo1.name,
uninvert(fieldInfo1.name, points1), uninvert(fieldInfo1.name, leftReader),
uninvert(fieldInfo1.name, points2)); uninvert(fieldInfo1.name, rightReader));
} }
} }