diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 42a6e8073576..9fd4552ec4ab 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -295,7 +295,10 @@ Optimizations Bug Fixes --------------------- -(No changes) + +* GITHUB#16295: SingletonSortedNumericDocValues now delegates rangeIntoBitSet + to the wrapped NumericDocValues, enabling optimized range evaluation for + single-valued sorted numeric fields. (Costin Leau) Other --------------------- diff --git a/lucene/core/src/java/org/apache/lucene/index/SingletonSortedNumericDocValues.java b/lucene/core/src/java/org/apache/lucene/index/SingletonSortedNumericDocValues.java index 10783561819d..f2d3062ec5d0 100644 --- a/lucene/core/src/java/org/apache/lucene/index/SingletonSortedNumericDocValues.java +++ b/lucene/core/src/java/org/apache/lucene/index/SingletonSortedNumericDocValues.java @@ -73,6 +73,13 @@ public int docIDRunEnd() throws IOException { return in.docIDRunEnd(); } + @Override + public void rangeIntoBitSet( + int fromDoc, int toDoc, long minValue, long maxValue, FixedBitSet bitSet, int offset) + throws IOException { + in.rangeIntoBitSet(fromDoc, toDoc, minValue, maxValue, bitSet, offset); + } + @Override public long cost() { return in.cost(); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSkipBlockRangeIteratorIntoBitSet.java b/lucene/core/src/test/org/apache/lucene/search/TestSkipBlockRangeIteratorIntoBitSet.java index 76e01cae13c3..365757a65462 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSkipBlockRangeIteratorIntoBitSet.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSkipBlockRangeIteratorIntoBitSet.java @@ -694,4 +694,43 @@ private void doTestSortedNumericRangeIntoBitSet(boolean dense, boolean fixedCard } } } + + public void testSingletonDelegatesRangeIntoBitSet() throws Exception { + int numDocs = 4096 * 4; + try (Directory dir = newDirectory()) { + IndexWriterConfig conf = new IndexWriterConfig(); + conf.setCodec(new Lucene104Codec()); + try (IndexWriter writer = new IndexWriter(dir, conf)) { + for (int i = 0; i < numDocs; i++) { + Document doc = new Document(); + long value = i % 100; + doc.add(NumericDocValuesField.indexedField("numeric", value)); + doc.add(SortedNumericDocValuesField.indexedField("sorted_numeric", value)); + writer.addDocument(doc); + } + writer.forceMerge(1); + } + try (DirectoryReader reader = DirectoryReader.open(dir)) { + for (LeafReaderContext ctx : reader.leaves()) { + int maxDoc = ctx.reader().maxDoc(); + + FixedBitSet fromNumeric = new FixedBitSet(maxDoc); + ctx.reader() + .getNumericDocValues("numeric") + .rangeIntoBitSet(0, maxDoc, 20, 40, fromNumeric, 0); + + FixedBitSet fromSingleton = new FixedBitSet(maxDoc); + ctx.reader() + .getSortedNumericDocValues("sorted_numeric") + .rangeIntoBitSet(0, maxDoc, 20, 40, fromSingleton, 0); + + assertEquals( + "Singleton sorted numeric should produce identical results to underlying numeric", + fromNumeric, + fromSingleton); + assertTrue("Expected some bits set", fromNumeric.cardinality() > 0); + } + } + } + } }