diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/RangeAccumulator.java b/lucene/facet/src/java/org/apache/lucene/facet/range/RangeAccumulator.java index 0a07e92d1a7..6adacec3426 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/RangeAccumulator.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/RangeAccumulator.java @@ -30,6 +30,7 @@ import org.apache.lucene.facet.search.FacetsAccumulator; import org.apache.lucene.facet.search.FacetsCollector.MatchingDocs; import org.apache.lucene.facet.taxonomy.CategoryPath; import org.apache.lucene.index.NumericDocValues; +import org.apache.lucene.util.Bits; /** Uses a {@link NumericDocValues} and accumulates * counts for provided ranges. This is dynamic (does not @@ -86,10 +87,19 @@ public class RangeAccumulator extends FacetsAccumulator { if (ndv == null) { continue; // no numeric values for this field in this reader } + Bits docsWithField = hits.context.reader().getDocsWithField(ranges.field); + final int length = hits.bits.length(); int doc = 0; while (doc < length && (doc = hits.bits.nextSetBit(doc)) != -1) { long v = ndv.get(doc); + + // Skip missing docs: + if (v == 0 && docsWithField.get(doc) == false) { + doc++; + continue; + } + // TODO: if all ranges are non-overlapping, we // should instead do a bin-search up front // (really, a specialized case of the interval diff --git a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeAccumulator.java b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeAccumulator.java index 92ecb17bcb4..7b0f4a423ec 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeAccumulator.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeAccumulator.java @@ -632,5 +632,43 @@ public class TestRangeAccumulator extends FacetTestCase { r.close(); dir.close(); } -} + // LUCENE-5178 + public void testMissingValues() throws Exception { + Directory d = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), d); + Document doc = new Document(); + NumericDocValuesField field = new NumericDocValuesField("field", 0L); + doc.add(field); + for(long l=0;l<100;l++) { + if (l % 5 == 0) { + // Every 5th doc is missing the value: + w.addDocument(new Document()); + continue; + } + field.setLongValue(l); + w.addDocument(doc); + } + + IndexReader r = w.getReader(); + w.close(); + + RangeAccumulator a = new RangeAccumulator(new RangeFacetRequest("field", + new LongRange("less than 10", 0L, true, 10L, false), + new LongRange("less than or equal to 10", 0L, true, 10L, true), + new LongRange("over 90", 90L, false, 100L, false), + new LongRange("90 or above", 90L, true, 100L, false), + new LongRange("over 1000", 1000L, false, Long.MAX_VALUE, false))); + + FacetsCollector fc = FacetsCollector.create(a); + + IndexSearcher s = newSearcher(r); + s.search(new MatchAllDocsQuery(), fc); + List result = fc.getFacetResults(); + assertEquals(1, result.size()); + assertEquals("field (0)\n less than 10 (8)\n less than or equal to 10 (8)\n over 90 (8)\n 90 or above (8)\n over 1000 (0)\n", FacetTestUtils.toSimpleString(result.get(0))); + + r.close(); + d.close(); + } +}