Index: contrib/queries/src/java/org/apache/lucene/search/trie/AbstractTrieRangeFilter.java =================================================================== --- contrib/queries/src/java/org/apache/lucene/search/trie/AbstractTrieRangeFilter.java (revision 745678) +++ contrib/queries/src/java/org/apache/lucene/search/trie/AbstractTrieRangeFilter.java (working copy) @@ -33,11 +33,11 @@ abstract class AbstractTrieRangeFilter extends Filter { - AbstractTrieRangeFilter(final String[] fields, final int precisionStep, + AbstractTrieRangeFilter(final String[] fields, final int[] precisionSteps, Number min, Number max, final boolean minInclusive, final boolean maxInclusive ) { this.fields=(String[])fields.clone(); - this.precisionStep=precisionStep; + this.precisionSteps=precisionSteps; this.min=min; this.max=max; this.minInclusive=minInclusive; @@ -66,12 +66,12 @@ if (this.getClass().equals(o.getClass())) { AbstractTrieRangeFilter q=(AbstractTrieRangeFilter)o; return ( - Arrays.equals(fields,q.fields) && (q.min == null ? min == null : q.min.equals(min)) && (q.max == null ? max == null : q.max.equals(max)) && minInclusive==q.minInclusive && maxInclusive==q.maxInclusive && - precisionStep==q.precisionStep + Arrays.equals(fields,q.fields) && + Arrays.equals(precisionSteps,q.precisionSteps) ); } return false; @@ -79,7 +79,8 @@ //@Override public final int hashCode() { - int hash=Arrays.asList(fields).hashCode()+(precisionStep^0x64365465); + int hash = Arrays.asList(fields).hashCode(); + for (int i=0; iThis is the counterpart to {@link TrieUtils#addIndexedFields(Document,String[],String[])}. */ - public IntTrieRangeFilter(final String[] fields, final int precisionStep, + public IntTrieRangeFilter(final String[] fields, final int[] precisionSteps, Integer min, Integer max, final boolean minInclusive, final boolean maxInclusive ) { - super(fields, precisionStep, min, max, minInclusive, maxInclusive); + super(fields, precisionSteps, min, max, minInclusive, maxInclusive); } /** @@ -126,7 +126,7 @@ } } - }, precisionStep, minBound, maxBound); + }, precisionSteps, minBound, maxBound); } catch (RuntimeException e) { if (e.getCause() instanceof IOException) throw (IOException)e.getCause(); throw e; Index: contrib/queries/src/java/org/apache/lucene/search/trie/LongTrieRangeFilter.java =================================================================== --- contrib/queries/src/java/org/apache/lucene/search/trie/LongTrieRangeFilter.java (revision 745678) +++ contrib/queries/src/java/org/apache/lucene/search/trie/LongTrieRangeFilter.java (working copy) @@ -51,7 +51,7 @@ ) { this( new String[]{field, field+TrieUtils.LOWER_PRECISION_FIELD_NAME_SUFFIX}, - precisionStep,min,max,minInclusive,maxInclusive + new int[]{precisionStep},min,max,minInclusive,maxInclusive ); } @@ -68,7 +68,7 @@ public LongTrieRangeFilter(final String field, final String lowerPrecisionField, final int precisionStep, final Long min, final Long max, final boolean minInclusive, final boolean maxInclusive ) { - this(new String[]{field, lowerPrecisionField},precisionStep,min,max,minInclusive,maxInclusive); + this(new String[]{field, lowerPrecisionField},new int[]{precisionStep},min,max,minInclusive,maxInclusive); } /** @@ -82,10 +82,10 @@ * To query double values use the converter {@link TrieUtils#doubleToSortableLong}. *

This is the counterpart to {@link TrieUtils#addIndexedFields(Document,String[],String[])}. */ - public LongTrieRangeFilter(final String[] fields, final int precisionStep, + public LongTrieRangeFilter(final String[] fields, final int[] precisionSteps, Long min, Long max, final boolean minInclusive, final boolean maxInclusive ) { - super(fields, precisionStep, min, max, minInclusive, maxInclusive); + super(fields, precisionSteps, min, max, minInclusive, maxInclusive); } /** @@ -126,7 +126,7 @@ } } - }, precisionStep, minBound, maxBound); + }, precisionSteps, minBound, maxBound); } catch (RuntimeException e) { if (e.getCause() instanceof IOException) throw (IOException)e.getCause(); throw e; Index: contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java =================================================================== --- contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java (revision 745678) +++ contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java (working copy) @@ -296,11 +296,29 @@ public static String[] trieCodeLong(long val, int precisionStep) { if (precisionStep<1 || precisionStep>64) throw new IllegalArgumentException("precisionStep may only be 1..64"); - String[] arr = new String[63/precisionStep+1]; - int idx = 0; - for (int shift=0; shift<64; shift+=precisionStep) { - arr[idx++] = longToPrefixCoded(val, shift); + return trieCodeLong(val, new int[]{precisionStep}); + } + + /** + * **TODO** Expert: Returns a sequence of trie coded numbers suitable for {@link LongTrieRangeFilter}. + * Each successive string in the list has had it's precision reduced by precisionStep. + * For sorting, index the first full-precision value into a separate field and the + * remaining values into another field. + *

To achieve this, use {@link #addIndexedFields(Document,String,String[])}. + */ + public static String[] trieCodeLong(long val, int[] precisionSteps) { + // determine size of trie array + int size=0; + for (int shift=0; shift<64; ) { + shift += precisionSteps[Math.min(precisionSteps.length-1, size)]; + size++; } + // create trie entries + final String[] arr = new String[size]; + for (int idx=0,shift=0; idx32) throw new IllegalArgumentException("precisionStep may only be 1..32"); - String[] arr = new String[31/precisionStep+1]; - int idx = 0; - for (int shift=0; shift<32; shift+=precisionStep) { - arr[idx++] = intToPrefixCoded(val, shift); + return trieCodeInt(val, new int[]{precisionStep}); + } + + /** + * **TODO** Expert: Returns a sequence of trie coded numbers suitable for {@link IntTrieRangeFilter}. + * Each successive string in the list has had it's precision reduced by precisionStep. + * For sorting, index the first full-precision value into a separate field and the + * remaining values into another field. + *

To achieve this, use {@link #addIndexedFields(Document,String,String[])}. + */ + public static String[] trieCodeInt(int val, int[] precisionSteps) { + // determine size of trie array + int size=0; + for (int shift=0; shift<32; ) { + shift += precisionSteps[Math.min(precisionSteps.length-1, size)]; + size++; } + // create trie entries + final String[] arr = new String[size]; + for (int idx=0,shift=0; idxThis method is used by {@link LongTrieRangeFilter}. */ @@ -395,10 +431,24 @@ ) { if (precisionStep<1 || precisionStep>64) throw new IllegalArgumentException("precisionStep may only be 1..64"); - splitRange(builder, 64, precisionStep, minBound, maxBound); + splitRange(builder, 64, new int[]{precisionStep}, minBound, maxBound); } /** + * **TODO** Expert: Splits a long range recursively. + * You may implement a builder that adds clauses to a + * {@link org.apache.lucene.search.BooleanQuery} for each call to its + * {@link LongRangeBuilder#addRange(String,String,int)} + * method. + *

This method is used by {@link LongTrieRangeFilter}. + */ + public static void splitLongRange(final LongRangeBuilder builder, + final int[] precisionSteps, final long minBound, final long maxBound + ) { + splitRange(builder, 64, precisionSteps, minBound, maxBound); + } + + /** * Expert: Splits an int range recursively. * You may implement a builder that adds clauses to a * {@link org.apache.lucene.search.BooleanQuery} for each call to its @@ -411,15 +461,31 @@ ) { if (precisionStep<1 || precisionStep>32) throw new IllegalArgumentException("precisionStep may only be 1..32"); - splitRange(builder, 32, precisionStep, (long)minBound, (long)maxBound); + splitRange(builder, 32, new int[]{precisionStep}, (long)minBound, (long)maxBound); } + /** + * **TODO** Expert: Splits an int range recursively. + * You may implement a builder that adds clauses to a + * {@link org.apache.lucene.search.BooleanQuery} for each call to its + * {@link IntRangeBuilder#addRange(String,String,int)} + * method. + *

This method is used by {@link IntTrieRangeFilter}. + */ + public static void splitIntRange(final IntRangeBuilder builder, + final int[] precisionSteps, final int minBound, final int maxBound + ) { + splitRange(builder, 32, precisionSteps, (long)minBound, (long)maxBound); + } + /** This helper does the splitting for both 32 and 64 bit. */ private static void splitRange( final Object builder, final int valSize, - final int precisionStep, long minBound, long maxBound + final int[] precisionSteps, long minBound, long maxBound ) { - for (int shift=0;; shift+=precisionStep) { + for (int level=0,shift=0;; level++) { + final int precisionStep = precisionSteps[Math.min(precisionSteps.length-1, level)]; + // calculate new bounds for inner precision final long diff = 1L << (shift+precisionStep), mask = ((1L<=valSize || nextMinBound>nextMaxBound) { // We are in the lowest precision or the next precision is not available. - addRange(builder, valSize, precisionStep, minBound, maxBound, shift); + addRange(builder, valSize, minBound, maxBound, shift, level); // exit the split recursion loop break; } if (hasLower) - addRange(builder, valSize, precisionStep, minBound, minBound | mask, shift); + addRange(builder, valSize, minBound, minBound | mask, shift, level); if (hasUpper) - addRange(builder, valSize, precisionStep, maxBound & ~mask, maxBound, shift); + addRange(builder, valSize, maxBound & ~mask, maxBound, shift, level); // recurse to next precision minBound = nextMinBound; maxBound = nextMaxBound; + shift += precisionStep; } } /** Helper that delegates to correct range builder */ private static void addRange( final Object builder, final int valSize, - final int precisionStep, long minBound, long maxBound, - final int shift + long minBound, long maxBound, + final int shift, final int level ) { // for the max bound set all lower bits (that were shifted away): // this is important for testing or other usages of the splitted range @@ -462,10 +529,10 @@ // delegate to correct range builder switch(valSize) { case 64: - ((LongRangeBuilder)builder).addRange(precisionStep, minBound, maxBound, shift); + ((LongRangeBuilder)builder).addRange(minBound, maxBound, shift, level); break; case 32: - ((IntRangeBuilder)builder).addRange(precisionStep, (int)minBound, (int)maxBound, shift); + ((IntRangeBuilder)builder).addRange((int)minBound, (int)maxBound, shift, level); break; default: // Should not happen! @@ -498,10 +565,10 @@ * Overwrite this method, if you like to receive the raw long range bounds. * You can use this for e.g. debugging purposes (print out range bounds). */ - public void addRange(final int precisionStep, final long min, final long max, final int shift) { + public void addRange(final long min, final long max, final int shift, final int level) { /*System.out.println(Long.toHexString((min^0x8000000000000000L) >>> shift)+".."+ Long.toHexString((max^0x8000000000000000L) >>> shift));*/ - addRange(longToPrefixCoded(min, shift), longToPrefixCoded(max, shift), shift/precisionStep); + addRange(longToPrefixCoded(min, shift), longToPrefixCoded(max, shift), level); } } @@ -531,10 +598,10 @@ * Overwrite this method, if you like to receive the raw int range bounds. * You can use this for e.g. debugging purposes (print out range bounds). */ - public void addRange(final int precisionStep, final int min, final int max, final int shift) { + public void addRange(final int min, final int max, final int shift, final int level) { /*System.out.println(Integer.toHexString((min^0x80000000) >>> shift)+".."+ Integer.toHexString((max^0x80000000) >>> shift));*/ - addRange(intToPrefixCoded(min, shift), intToPrefixCoded(max, shift), shift/precisionStep); + addRange(intToPrefixCoded(min, shift), intToPrefixCoded(max, shift), level); } } Index: contrib/queries/src/test/org/apache/lucene/search/trie/TestTrieUtils.java =================================================================== --- contrib/queries/src/test/org/apache/lucene/search/trie/TestTrieUtils.java (revision 745678) +++ contrib/queries/src/test/org/apache/lucene/search/trie/TestTrieUtils.java (working copy) @@ -178,7 +178,8 @@ final OpenBitSet bits=useBitSet ? new OpenBitSet(upper-lower+1) : null; TrieUtils.splitLongRange(new TrieUtils.LongRangeBuilder() { - public void addRange(int precisionStep, long min, long max, int shift) { + //@Override + public void addRange(long min, long max, int shift, int level) { assertTrue("min, max should be inside bounds", min>=lower && min<=upper && max>=lower && max<=upper); if (useBitSet) for (long l=min; l<=max; l++) { assertFalse("ranges should not overlap", bits.getAndSet(l-lower) ); @@ -251,7 +252,8 @@ final OpenBitSet bits=useBitSet ? new OpenBitSet(upper-lower+1) : null; TrieUtils.splitIntRange(new TrieUtils.IntRangeBuilder() { - public void addRange(int precisionStep, int min, int max, int shift) { + //@Override + public void addRange(int min, int max, int shift, int level) { assertTrue("min, max should be inside bounds", min>=lower && min<=upper && max>=lower && max<=upper); if (useBitSet) for (int i=min; i<=max; i++) { assertFalse("ranges should not overlap", bits.getAndSet(i-lower) );