Index: lucene/CHANGES.txt =================================================================== --- lucene/CHANGES.txt (revision 1173704) +++ lucene/CHANGES.txt (working copy) @@ -12,7 +12,8 @@ be populated directly into the FieldCache arrays during sorting, leading to concurrency issues. To fix this behaviour, the method signatures had to be changed: - - FieldCache.getUnValuedDocs() returns the interface Bits instead DocIdSet + - FieldCache.getUnValuedDocs() was renamed to FieldCache.getDocsWithField() + returning a Bits interface (backported from Lucene 4.0). - FieldComparator.setMissingValue() was removed and added to constructor As this is expert API, most code will not be affected. Index: lucene/src/java/org/apache/lucene/search/FieldCache.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldCache.java (revision 1173704) +++ lucene/src/java/org/apache/lucene/search/FieldCache.java (working copy) @@ -314,9 +314,9 @@ /** Checks the internal cache for an appropriate entry, and if none is found, * reads the terms in field and returns a bit set at the size of * reader.maxDoc(), with turned on bits for each docid that - * does not have a value for this field. + * does have a value for this field. */ - public Bits getUnValuedDocs (IndexReader reader, String field) + public Bits getDocsWithField(IndexReader reader, String field) throws IOException; /** Checks the internal cache for an appropriate entry, and if none is Index: lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java (revision 1173704) +++ lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java (working copy) @@ -59,7 +59,7 @@ caches.put(Double.TYPE, new DoubleCache(this)); caches.put(String.class, new StringCache(this)); caches.put(StringIndex.class, new StringIndexCache(this)); - caches.put(UnValuedDocsCache.class, new UnValuedDocsCache(this)); + caches.put(DocsWithFieldCache.class, new DocsWithFieldCache(this)); } public synchronized void purgeAllCaches() { @@ -413,13 +413,13 @@ } } - public Bits getUnValuedDocs(IndexReader reader, String field) + public Bits getDocsWithField(IndexReader reader, String field) throws IOException { - return (Bits) caches.get(UnValuedDocsCache.class).get(reader, new Entry(field, null)); + return (Bits) caches.get(DocsWithFieldCache.class).get(reader, new Entry(field, null)); } - static final class UnValuedDocsCache extends Cache { - UnValuedDocsCache(FieldCache wrapper) { + static final class DocsWithFieldCache extends Cache { + DocsWithFieldCache(FieldCache wrapper) { super(wrapper); } @@ -428,13 +428,15 @@ throws IOException { final Entry entry = entryKey; final String field = entry.field; - final FixedBitSet res = new FixedBitSet(reader.maxDoc()); + FixedBitSet res = null; final TermDocs termDocs = reader.termDocs(); final TermEnum termEnum = reader.terms(new Term(field)); try { do { final Term term = termEnum.term(); if (term == null || term.field() != field) break; + if (res == null) // late init + res = new FixedBitSet(reader.maxDoc()); termDocs.seek(termEnum); while (termDocs.next()) { res.set(termDocs.doc()); @@ -444,14 +446,15 @@ termDocs.close(); termEnum.close(); } + if (res == null) + return new Bits.MatchNoBits(reader.maxDoc()); final int numSet = res.cardinality(); if (numSet >= reader.numDocs()) { // The cardinality of the BitSet is numDocs if all documents have a value. // As deleted docs are not in TermDocs, this is always true assert numSet == reader.numDocs(); - return new Bits.MatchNoBits(reader.maxDoc()); + return new Bits.MatchAllBits(reader.maxDoc()); } - res.flip(0, reader.maxDoc()); return res; } } Index: lucene/src/java/org/apache/lucene/search/FieldComparator.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldComparator.java (revision 1173704) +++ lucene/src/java/org/apache/lucene/search/FieldComparator.java (working copy) @@ -187,7 +187,7 @@ protected final T missingValue; protected final String field; - protected Bits unvaluedDocs = null; + protected Bits docsWithField = null; public NumericComparator(String field, T missingValue) { this.field = field; @@ -197,12 +197,12 @@ @Override public void setNextReader(IndexReader reader, int docBase) throws IOException { if (missingValue != null) { - unvaluedDocs = FieldCache.DEFAULT.getUnValuedDocs(reader, field); + docsWithField = FieldCache.DEFAULT.getDocsWithField(reader, field); // optimization to remove unneeded checks on the bit interface: - if (unvaluedDocs instanceof Bits.MatchNoBits) - unvaluedDocs = null; + if (docsWithField instanceof Bits.MatchAllBits) + docsWithField = null; } else { - unvaluedDocs = null; + docsWithField = null; } } @@ -234,7 +234,7 @@ @Override public int compareBottom(int doc) { byte v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; return bottom - v2; } @@ -242,7 +242,7 @@ @Override public void copy(int slot, int doc) { byte v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } @@ -344,7 +344,7 @@ @Override public int compareBottom(int doc) { double v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; if (bottom > v2) { return 1; @@ -358,7 +358,7 @@ @Override public void copy(int slot, int doc) { double v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } @@ -418,7 +418,7 @@ // TODO: are there sneaky non-branch ways to compute // sign of float? float v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; if (bottom > v2) { return 1; @@ -432,7 +432,7 @@ @Override public void copy(int slot, int doc) { float v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } @@ -496,7 +496,7 @@ // Cannot return bottom - values[slot2] because that // may overflow int v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; if (bottom > v2) { return 1; @@ -510,7 +510,7 @@ @Override public void copy(int slot, int doc) { int v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } @@ -570,7 +570,7 @@ // TODO: there are sneaky non-branch ways to compute // -1/+1/0 sign long v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; if (bottom > v2) { return 1; @@ -584,7 +584,7 @@ @Override public void copy(int slot, int doc) { long v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } @@ -700,7 +700,7 @@ @Override public int compareBottom(int doc) { short v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; return bottom - v2; } @@ -708,7 +708,7 @@ @Override public void copy(int slot, int doc) { short v2 = currentReaderValues[doc]; - if (unvaluedDocs != null && v2 == 0 && unvaluedDocs.get(doc)) + if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) v2 = missingValue; values[slot] = v2; } Index: lucene/src/test/org/apache/lucene/search/TestFieldCache.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestFieldCache.java (revision 1173704) +++ lucene/src/test/org/apache/lucene/search/TestFieldCache.java (working copy) @@ -138,20 +138,20 @@ } - Bits unvalued = cache.getUnValuedDocs(reader, "theLong"); - assertSame("Second request to cache return same array", unvalued, cache.getUnValuedDocs(reader, "theLong")); - assertTrue("unvalued(theLong) must be class Bits.MatchNoBits", unvalued instanceof Bits.MatchNoBits); - assertTrue("unvalued(theLong) Size: " + unvalued.length() + " is not: " + NUM_DOCS, unvalued.length() == NUM_DOCS); - for (int i = 0; i < unvalued.length(); i++) { - assertFalse(unvalued.get(i)); + Bits docsWithField = cache.getDocsWithField(reader, "theLong"); + assertSame("Second request to cache return same array", docsWithField, cache.getDocsWithField(reader, "theLong")); + assertTrue("docsWithField(theLong) must be class Bits.MatchAllBits", docsWithField instanceof Bits.MatchAllBits); + assertTrue("docsWithField(theLong) Size: " + docsWithField.length() + " is not: " + NUM_DOCS, docsWithField.length() == NUM_DOCS); + for (int i = 0; i < docsWithField.length(); i++) { + assertTrue(docsWithField.get(i)); } - unvalued = cache.getUnValuedDocs(reader, "sparse"); - assertSame("Second request to cache return same array", unvalued, cache.getUnValuedDocs(reader, "sparse")); - assertFalse("unvalued(sparse) must not be class Bits.MatchNoBits", unvalued instanceof Bits.MatchNoBits); - assertTrue("unvalued(sparse) Size: " + unvalued.length() + " is not: " + NUM_DOCS, unvalued.length() == NUM_DOCS); - for (int i = 0; i < unvalued.length(); i++) { - assertEquals(i%2 != 0, unvalued.get(i)); + docsWithField = cache.getDocsWithField(reader, "sparse"); + assertSame("Second request to cache return same array", docsWithField, cache.getDocsWithField(reader, "sparse")); + assertFalse("docsWithField(sparse) must not be class Bits.MatchAllBits", docsWithField instanceof Bits.MatchAllBits); + assertTrue("docsWithField(sparse) Size: " + docsWithField.length() + " is not: " + NUM_DOCS, docsWithField.length() == NUM_DOCS); + for (int i = 0; i < docsWithField.length(); i++) { + assertEquals(i%2 == 0, docsWithField.get(i)); } } }