Index: src/java/org/apache/lucene/search/FieldCacheRangeFilter.java =================================================================== --- src/java/org/apache/lucene/search/FieldCacheRangeFilter.java (revision 788070) +++ src/java/org/apache/lucene/search/FieldCacheRangeFilter.java (working copy) @@ -37,37 +37,181 @@ * fields which contain zero or one terms for each document. Thus it works on dates, * prices and other single value fields but will not work on regular text fields. It is * preferable to use an UN_TOKENIZED field to ensure that there is only a single term. - * - * Also, collation is done at the time the FieldCache is built; to change - * collation you need to override the getFieldCache() method to change the underlying cache. */ -public class FieldCacheRangeFilter extends Filter { - private String field; - private String lowerVal; - private String upperVal; - private boolean includeLower; - private boolean includeUpper; +public abstract class FieldCacheRangeFilter extends Filter { + final String field; + final FieldCache.Parser parser; + final Object lowerVal; + final Object upperVal; + final boolean includeLower; + final boolean includeUpper; - public FieldCacheRangeFilter( - String field, - String lowerVal, - String upperVal, - boolean includeLower, - boolean includeUpper) { + private FieldCacheRangeFilter(String field, FieldCache.Parser parser, Object lowerVal, Object upperVal, boolean includeLower, boolean includeUpper) { this.field = field; + this.parser = parser; this.lowerVal = lowerVal; this.upperVal = upperVal; this.includeLower = includeLower; this.includeUpper = includeUpper; } + + /** This method is implemented for each data type */ + abstract DocIdSetIterator newDocIdSetIterator(IndexReader reader) throws IOException; - public FieldCache getFieldCache() { - return FieldCache.DEFAULT; + public static FieldCacheRangeFilter newStringRange(String field, String lowerVal, String upperVal, boolean includeLower, boolean includeUpper) { + return new FieldCacheRangeFilter(field, null, lowerVal, upperVal, includeLower, includeUpper) { + + DocIdSetIterator newDocIdSetIterator(IndexReader reader) throws IOException { + final FieldCache.StringIndex fcsi = FieldCache.DEFAULT.getStringIndex(reader, field); + final int inclusiveLowerPoint; + final int inclusiveUpperPoint; + int lowerPoint = fcsi.binarySearchLookup((String) lowerVal); + int upperPoint = fcsi.binarySearchLookup((String) upperVal); + + if (lowerPoint == 0 && upperPoint == 0) { + throw new IllegalArgumentException("At least one value must be non-null"); + } + + if (includeLower && lowerPoint == 0) { + throw new IllegalArgumentException("The lower bound must be non-null to be inclusive"); + } else if (includeLower && lowerPoint > 0) { + inclusiveLowerPoint = lowerPoint; + } else if (lowerPoint >= 0) { + inclusiveLowerPoint = lowerPoint+1; + } else { + inclusiveLowerPoint = -lowerPoint-1; + } + + if (includeUpper && upperPoint == 0) { + throw new IllegalArgumentException("The upper bound must be non-null to be inclusive"); + } else if (upperPoint == 0) { + inclusiveUpperPoint = Integer.MAX_VALUE; + } else if (includeUpper && upperPoint > 0) { + inclusiveUpperPoint = upperPoint; + } else if (upperPoint >= 0) { + inclusiveUpperPoint = upperPoint - 1; + } else { + inclusiveUpperPoint = -upperPoint - 2; + } + + return new DocIdSetIterator() { + private int doc = -1; + + public int docID() { + return doc; + } + + public int nextDoc() { + try { + do { + doc++; + } while (fcsi.order[doc] > inclusiveUpperPoint || fcsi.order[doc] < inclusiveLowerPoint); + return doc; + } catch (ArrayIndexOutOfBoundsException e) { + return NO_MORE_DOCS; + } + } + + public int advance(int target) { + try { + doc = target; + while (fcsi.order[doc] > inclusiveUpperPoint || fcsi.order[doc] < inclusiveLowerPoint) { + doc++; + } + return doc; + } catch (ArrayIndexOutOfBoundsException e) { + return NO_MORE_DOCS; + } + } + + }; + } + }; } + public static FieldCacheRangeFilter newByteRange(String field, Byte lowerVal, Byte upperVal, boolean includeLower, boolean includeUpper) { + return newByteRange(field, null, lowerVal, upperVal, includeLower, includeUpper); + } + + public static FieldCacheRangeFilter newByteRange(String field, FieldCache.ByteParser parser, Byte lowerVal, Byte upperVal, boolean includeLower, boolean includeUpper) { + return new FieldCacheRangeFilter(field, parser, lowerVal, upperVal, includeLower, includeUpper) { + + DocIdSetIterator newDocIdSetIterator(IndexReader reader) throws IOException { + final byte[] bytes = FieldCache.DEFAULT.getBytes(reader, field, (FieldCache.ByteParser) parser); + final byte inclusiveLowerPoint,inclusiveUpperPoint; + if (lowerVal != null) { + inclusiveLowerPoint = (byte) (includeUpper ? ((Byte) lowerVal).byteValue() : (((Byte) lowerVal).byteValue() + 1)); + } else { + inclusiveLowerPoint = Byte.MIN_VALUE; + } + if (upperVal != null) { + inclusiveUpperPoint = (byte) (includeUpper ? ((Byte) upperVal).byteValue() : (((Byte) upperVal).byteValue() - 1)); + } else { + inclusiveUpperPoint = Byte.MAX_VALUE; + } + + return new DocIdSetIterator() { + private int doc = -1; + + public int docID() { + return doc; + } + + public int nextDoc() { + try { + do { + doc++; + } while (bytes[doc] > inclusiveUpperPoint || bytes[doc] < inclusiveLowerPoint); + return doc; + } catch (ArrayIndexOutOfBoundsException e) { + return NO_MORE_DOCS; + } + } + + public int advance(int target) { + try { + doc = target; + while (bytes[doc] > inclusiveUpperPoint || bytes[doc] < inclusiveLowerPoint) { + doc++; + } + return doc; + } catch (ArrayIndexOutOfBoundsException e) { + return NO_MORE_DOCS; + } + } + + }; + } + }; + } + + /* + + public static FieldCacheRangeFilter newShortRange(String field, Short lowerVal, Short upperVal, boolean includeLower, boolean includeUpper) { + return newShortRange(field, null, lowerVal, upperVal, includeLower, includeUpper); + } + + public static FieldCacheRangeFilter newShortRange(String field, FieldCache.ShortParser parser, Short lowerVal, Short upperVal, boolean includeLower, boolean includeUpper) { + return new FieldCacheRangeFilter(field, parser, lowerVal, upperVal, includeLower, includeUpper) { + }; + } + + public static FieldCacheRangeFilter newIntRange(String field, Short lowerVal, Short upperVal, boolean includeLower, boolean includeUpper) { + return newIntRange(field, null, lowerVal, upperVal, includeLower, includeUpper); + } + + public static FieldCacheRangeFilter newIntRange(String field, FieldCache.IntParser parser, Short lowerVal, Short upperVal, boolean includeLower, boolean includeUpper) { + return new FieldCacheRangeFilter(field, parser, lowerVal, upperVal, includeLower, includeUpper) { + }; + } + + ... + + */ + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { - return new RangeMultiFilterDocIdSet(getFieldCache().getStringIndex(reader, field)); + return new RangeDocIdSet(reader); } public String toString() { @@ -111,98 +255,16 @@ return h; } - protected class RangeMultiFilterDocIdSet extends DocIdSet { - private int inclusiveLowerPoint; - private int inclusiveUpperPoint; - private FieldCache.StringIndex fcsi; + protected class RangeDocIdSet extends DocIdSet { + private final IndexReader reader; - public RangeMultiFilterDocIdSet(FieldCache.StringIndex fcsi) { - this.fcsi = fcsi; - initialize(); + public RangeDocIdSet(IndexReader reader) { + this.reader = reader; } - private void initialize() { - int lowerPoint = fcsi.binarySearchLookup(lowerVal); - int upperPoint = fcsi.binarySearchLookup(upperVal); - - if (lowerPoint == 0 && upperPoint == 0) { - throw new IllegalArgumentException("At least one value must be non-null"); - } - - if (includeLower && lowerPoint == 0) { - throw new IllegalArgumentException("The lower bound must be non-null to be inclusive"); - } else if (includeLower && lowerPoint > 0) { - inclusiveLowerPoint = lowerPoint; - } else if (lowerPoint >= 0) { - inclusiveLowerPoint = lowerPoint+1; - } else { - inclusiveLowerPoint = -lowerPoint-1; - } - - if (includeUpper && upperPoint == 0) { - throw new IllegalArgumentException("The upper bound must be non-null to be inclusive"); - } else if (upperPoint == 0) { - inclusiveUpperPoint = Integer.MAX_VALUE; - } else if (includeUpper && upperPoint > 0) { - inclusiveUpperPoint = upperPoint; - } else if (upperPoint >= 0) { - inclusiveUpperPoint = upperPoint - 1; - } else { - inclusiveUpperPoint = -upperPoint - 2; - } + public DocIdSetIterator iterator() throws IOException { + return newDocIdSetIterator(reader); } - public DocIdSetIterator iterator() { - return new RangeMultiFilterIterator(); - } - - protected class RangeMultiFilterIterator extends DocIdSetIterator { - private int doc = -1; - - /** @deprecated use {@link #docID()} instead. */ - public int doc() { - return doc; - } - - public int docID() { - return doc; - } - - /** @deprecated use {@link #nextDoc()} instead. */ - public boolean next() { - return nextDoc() != NO_MORE_DOCS; - } - - public int nextDoc() { - try { - do { - doc++; - } while (fcsi.order[doc] > inclusiveUpperPoint - || fcsi.order[doc] < inclusiveLowerPoint); - } catch (ArrayIndexOutOfBoundsException e) { - doc = NO_MORE_DOCS; - } - return doc; - } - - /** @deprecated use {@link #advance(int)} instead. */ - public boolean skipTo(int target) { - return advance(target) != NO_MORE_DOCS; - } - - public int advance(int target) { - try { - doc = target; - while (fcsi.order[doc] > inclusiveUpperPoint - || fcsi.order[doc] < inclusiveLowerPoint) { - doc++; - } - } catch (ArrayIndexOutOfBoundsException e) { - doc = NO_MORE_DOCS; - } - return doc; - } - - } } } Index: src/test/org/apache/lucene/search/TestFieldCacheRangeFilter.java =================================================================== --- src/test/org/apache/lucene/search/TestFieldCacheRangeFilter.java (revision 788070) +++ src/test/org/apache/lucene/search/TestFieldCacheRangeFilter.java (working copy) @@ -67,64 +67,64 @@ // test id, bounded on both ends - result = search.search(q,new FieldCacheRangeFilter("id",minIP,maxIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,maxIP,T,T), numDocs).scoreDocs; assertEquals("find all", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,maxIP,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,maxIP,T,F), numDocs).scoreDocs; assertEquals("all but last", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,maxIP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,maxIP,F,T), numDocs).scoreDocs; assertEquals("all but first", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,maxIP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,maxIP,F,F), numDocs).scoreDocs; assertEquals("all but ends", numDocs-2, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",medIP,maxIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",medIP,maxIP,T,T), numDocs).scoreDocs; assertEquals("med and up", 1+ maxId-medId, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,medIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,medIP,T,T), numDocs).scoreDocs; assertEquals("up to med", 1+ medId-minId, result.length); // unbounded id - result = search.search(q,new FieldCacheRangeFilter("id",minIP,null,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,null,T,F), numDocs).scoreDocs; assertEquals("min and up", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",null,maxIP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",null,maxIP,F,T), numDocs).scoreDocs; assertEquals("max and down", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,null,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,null,F,F), numDocs).scoreDocs; assertEquals("not min, but up", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",null,maxIP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",null,maxIP,F,F), numDocs).scoreDocs; assertEquals("not max, but down", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",medIP,maxIP,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",medIP,maxIP,T,F), numDocs).scoreDocs; assertEquals("med and up, not max", maxId-medId, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,medIP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,medIP,F,T), numDocs).scoreDocs; assertEquals("not min, up to med", medId-minId, result.length); // very small sets - result = search.search(q,new FieldCacheRangeFilter("id",minIP,minIP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,minIP,F,F), numDocs).scoreDocs; assertEquals("min,min,F,F", 0, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",medIP,medIP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",medIP,medIP,F,F), numDocs).scoreDocs; assertEquals("med,med,F,F", 0, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",maxIP,maxIP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",maxIP,maxIP,F,F), numDocs).scoreDocs; assertEquals("max,max,F,F", 0, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",minIP,minIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",minIP,minIP,T,T), numDocs).scoreDocs; assertEquals("min,min,T,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",null,minIP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",null,minIP,F,T), numDocs).scoreDocs; assertEquals("nul,min,F,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",maxIP,maxIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",maxIP,maxIP,T,T), numDocs).scoreDocs; assertEquals("max,max,T,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",maxIP,null,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",maxIP,null,T,F), numDocs).scoreDocs; assertEquals("max,nul,T,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("id",medIP,medIP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("id",medIP,medIP,T,T), numDocs).scoreDocs; assertEquals("med,med,T,T", 1, result.length); } @@ -146,47 +146,47 @@ // test extremes, bounded on both ends - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,maxRP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,maxRP,T,T), numDocs).scoreDocs; assertEquals("find all", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,maxRP,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,maxRP,T,F), numDocs).scoreDocs; assertEquals("all but biggest", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,maxRP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,maxRP,F,T), numDocs).scoreDocs; assertEquals("all but smallest", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,maxRP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,maxRP,F,F), numDocs).scoreDocs; assertEquals("all but extremes", numDocs-2, result.length); // unbounded - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,null,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,null,T,F), numDocs).scoreDocs; assertEquals("smallest and up", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",null,maxRP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",null,maxRP,F,T), numDocs).scoreDocs; assertEquals("biggest and down", numDocs, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,null,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,null,F,F), numDocs).scoreDocs; assertEquals("not smallest, but up", numDocs-1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",null,maxRP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",null,maxRP,F,F), numDocs).scoreDocs; assertEquals("not biggest, but down", numDocs-1, result.length); // very small sets - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,minRP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,minRP,F,F), numDocs).scoreDocs; assertEquals("min,min,F,F", 0, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",maxRP,maxRP,F,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",maxRP,maxRP,F,F), numDocs).scoreDocs; assertEquals("max,max,F,F", 0, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",minRP,minRP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",minRP,minRP,T,T), numDocs).scoreDocs; assertEquals("min,min,T,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",null,minRP,F,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",null,minRP,F,T), numDocs).scoreDocs; assertEquals("nul,min,F,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",maxRP,maxRP,T,T), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",maxRP,maxRP,T,T), numDocs).scoreDocs; assertEquals("max,max,T,T", 1, result.length); - result = search.search(q,new FieldCacheRangeFilter("rand",maxRP,null,T,F), numDocs).scoreDocs; + result = search.search(q,FieldCacheRangeFilter.newStringRange("rand",maxRP,null,T,F), numDocs).scoreDocs; assertEquals("max,nul,T,T", 1, result.length); } }