LUCENE-7063: add tests/docs for numericutils, rename confusing methods, remove overlap with LegacyNumericUtils

This commit is contained in:
Robert Muir 2016-03-03 21:51:14 -05:00
parent 44d8ee9115
commit 3ffeccab7e
36 changed files with 778 additions and 348 deletions

View File

@ -30,6 +30,7 @@ import org.apache.lucene.util.AttributeReflector;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
/** /**
* <b>Expert:</b> This class provides a {@link TokenStream} * <b>Expert:</b> This class provides a {@link TokenStream}
@ -299,7 +300,7 @@ public final class LegacyNumericTokenStream extends TokenStream {
* <code>new Field(name, new LegacyNumericTokenStream(precisionStep).setDoubleValue(value))</code> * <code>new Field(name, new LegacyNumericTokenStream(precisionStep).setDoubleValue(value))</code>
*/ */
public LegacyNumericTokenStream setDoubleValue(final double value) { public LegacyNumericTokenStream setDoubleValue(final double value) {
numericAtt.init(LegacyNumericUtils.doubleToSortableLong(value), valSize = 64, precisionStep, -precisionStep); numericAtt.init(NumericUtils.doubleToSortableLong(value), valSize = 64, precisionStep, -precisionStep);
return this; return this;
} }
@ -310,7 +311,7 @@ public final class LegacyNumericTokenStream extends TokenStream {
* <code>new Field(name, new LegacyNumericTokenStream(precisionStep).setFloatValue(value))</code> * <code>new Field(name, new LegacyNumericTokenStream(precisionStep).setFloatValue(value))</code>
*/ */
public LegacyNumericTokenStream setFloatValue(final float value) { public LegacyNumericTokenStream setFloatValue(final float value) {
numericAtt.init(LegacyNumericUtils.floatToSortableInt(value), valSize = 32, precisionStep, -precisionStep); numericAtt.init(NumericUtils.floatToSortableInt(value), valSize = 32, precisionStep, -precisionStep);
return this; return this;
} }

View File

@ -137,12 +137,12 @@ public final class DoublePoint extends Field {
/** Encode single double dimension */ /** Encode single double dimension */
public static void encodeDimension(double value, byte dest[], int offset) { public static void encodeDimension(double value, byte dest[], int offset) {
NumericUtils.longToBytes(NumericUtils.doubleToSortableLong(value), dest, offset); NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(value), dest, offset);
} }
/** Decode single double dimension */ /** Decode single double dimension */
public static double decodeDimension(byte value[], int offset) { public static double decodeDimension(byte value[], int offset) {
return NumericUtils.sortableLongToDouble(NumericUtils.bytesToLong(value, offset)); return NumericUtils.sortableLongToDouble(NumericUtils.sortableBytesToLong(value, offset));
} }
// static methods for generating queries // static methods for generating queries

View File

@ -137,12 +137,12 @@ public final class FloatPoint extends Field {
/** Encode single float dimension */ /** Encode single float dimension */
public static void encodeDimension(float value, byte dest[], int offset) { public static void encodeDimension(float value, byte dest[], int offset) {
NumericUtils.intToBytes(NumericUtils.floatToSortableInt(value), dest, offset); NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(value), dest, offset);
} }
/** Decode single float dimension */ /** Decode single float dimension */
public static float decodeDimension(byte value[], int offset) { public static float decodeDimension(byte value[], int offset) {
return NumericUtils.sortableIntToFloat(NumericUtils.bytesToInt(value, offset)); return NumericUtils.sortableIntToFloat(NumericUtils.sortableBytesToInt(value, offset));
} }
// static methods for generating queries // static methods for generating queries

View File

@ -137,12 +137,12 @@ public final class IntPoint extends Field {
/** Encode single integer dimension */ /** Encode single integer dimension */
public static void encodeDimension(int value, byte dest[], int offset) { public static void encodeDimension(int value, byte dest[], int offset) {
NumericUtils.intToBytes(value, dest, offset); NumericUtils.intToSortableBytes(value, dest, offset);
} }
/** Decode single integer dimension */ /** Decode single integer dimension */
public static int decodeDimension(byte value[], int offset) { public static int decodeDimension(byte value[], int offset) {
return NumericUtils.bytesToInt(value, offset); return NumericUtils.sortableBytesToInt(value, offset);
} }
// static methods for generating queries // static methods for generating queries

View File

@ -137,12 +137,12 @@ public final class LongPoint extends Field {
/** Encode single long dimension */ /** Encode single long dimension */
public static void encodeDimension(long value, byte dest[], int offset) { public static void encodeDimension(long value, byte dest[], int offset) {
NumericUtils.longToBytes(value, dest, offset); NumericUtils.longToSortableBytes(value, dest, offset);
} }
/** Decode single long dimension */ /** Decode single long dimension */
public static long decodeDimension(byte value[], int offset) { public static long decodeDimension(byte value[], int offset) {
return NumericUtils.bytesToLong(value, offset); return NumericUtils.sortableBytesToLong(value, offset);
} }
// static methods for generating queries // static methods for generating queries

View File

@ -29,6 +29,7 @@ import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.index.Term; // for javadocs import org.apache.lucene.index.Term; // for javadocs
/** /**
@ -364,13 +365,13 @@ public final class LegacyNumericRangeQuery<T extends Number> extends MultiTermQu
// used to handle float/double infinity correcty // used to handle float/double infinity correcty
static final long LONG_NEGATIVE_INFINITY = static final long LONG_NEGATIVE_INFINITY =
LegacyNumericUtils.doubleToSortableLong(Double.NEGATIVE_INFINITY); NumericUtils.doubleToSortableLong(Double.NEGATIVE_INFINITY);
static final long LONG_POSITIVE_INFINITY = static final long LONG_POSITIVE_INFINITY =
LegacyNumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY); NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY);
static final int INT_NEGATIVE_INFINITY = static final int INT_NEGATIVE_INFINITY =
LegacyNumericUtils.floatToSortableInt(Float.NEGATIVE_INFINITY); NumericUtils.floatToSortableInt(Float.NEGATIVE_INFINITY);
static final int INT_POSITIVE_INFINITY = static final int INT_POSITIVE_INFINITY =
LegacyNumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY); NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY);
/** /**
* Subclass of FilteredTermsEnum for enumerating all terms that match the * Subclass of FilteredTermsEnum for enumerating all terms that match the
@ -400,7 +401,7 @@ public final class LegacyNumericRangeQuery<T extends Number> extends MultiTermQu
} else { } else {
assert dataType == FieldType.LegacyNumericType.DOUBLE; assert dataType == FieldType.LegacyNumericType.DOUBLE;
minBound = (min == null) ? LONG_NEGATIVE_INFINITY minBound = (min == null) ? LONG_NEGATIVE_INFINITY
: LegacyNumericUtils.doubleToSortableLong(min.doubleValue()); : NumericUtils.doubleToSortableLong(min.doubleValue());
} }
if (!minInclusive && min != null) { if (!minInclusive && min != null) {
if (minBound == Long.MAX_VALUE) break; if (minBound == Long.MAX_VALUE) break;
@ -414,7 +415,7 @@ public final class LegacyNumericRangeQuery<T extends Number> extends MultiTermQu
} else { } else {
assert dataType == FieldType.LegacyNumericType.DOUBLE; assert dataType == FieldType.LegacyNumericType.DOUBLE;
maxBound = (max == null) ? LONG_POSITIVE_INFINITY maxBound = (max == null) ? LONG_POSITIVE_INFINITY
: LegacyNumericUtils.doubleToSortableLong(max.doubleValue()); : NumericUtils.doubleToSortableLong(max.doubleValue());
} }
if (!maxInclusive && max != null) { if (!maxInclusive && max != null) {
if (maxBound == Long.MIN_VALUE) break; if (maxBound == Long.MIN_VALUE) break;
@ -440,7 +441,7 @@ public final class LegacyNumericRangeQuery<T extends Number> extends MultiTermQu
} else { } else {
assert dataType == FieldType.LegacyNumericType.FLOAT; assert dataType == FieldType.LegacyNumericType.FLOAT;
minBound = (min == null) ? INT_NEGATIVE_INFINITY minBound = (min == null) ? INT_NEGATIVE_INFINITY
: LegacyNumericUtils.floatToSortableInt(min.floatValue()); : NumericUtils.floatToSortableInt(min.floatValue());
} }
if (!minInclusive && min != null) { if (!minInclusive && min != null) {
if (minBound == Integer.MAX_VALUE) break; if (minBound == Integer.MAX_VALUE) break;
@ -454,7 +455,7 @@ public final class LegacyNumericRangeQuery<T extends Number> extends MultiTermQu
} else { } else {
assert dataType == FieldType.LegacyNumericType.FLOAT; assert dataType == FieldType.LegacyNumericType.FLOAT;
maxBound = (max == null) ? INT_POSITIVE_INFINITY maxBound = (max == null) ? INT_POSITIVE_INFINITY
: LegacyNumericUtils.floatToSortableInt(max.floatValue()); : NumericUtils.floatToSortableInt(max.floatValue());
} }
if (!maxInclusive && max != null) { if (!maxInclusive && max != null) {
if (maxBound == Integer.MIN_VALUE) break; if (maxBound == Integer.MIN_VALUE) break;

View File

@ -20,7 +20,7 @@ package org.apache.lucene.search;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.NumericUtils;
/** /**
* Selects a value from the document's list to use as the representative value * Selects a value from the document's list to use as the representative value
@ -81,14 +81,14 @@ public class SortedNumericSelector {
return new NumericDocValues() { return new NumericDocValues() {
@Override @Override
public long get(int docID) { public long get(int docID) {
return LegacyNumericUtils.sortableFloatBits((int) view.get(docID)); return NumericUtils.sortableFloatBits((int) view.get(docID));
} }
}; };
case DOUBLE: case DOUBLE:
return new NumericDocValues() { return new NumericDocValues() {
@Override @Override
public long get(int docID) { public long get(int docID) {
return LegacyNumericUtils.sortableDoubleBits(view.get(docID)); return NumericUtils.sortableDoubleBits(view.get(docID));
} }
}; };
default: default:

View File

@ -40,13 +40,6 @@ import org.apache.lucene.index.TermsEnum;
* prefixed (in the first char) by the <code>shift</code> value (number of bits removed) used * prefixed (in the first char) by the <code>shift</code> value (number of bits removed) used
* during encoding. * during encoding.
* *
* <p>To also index floating point numbers, this class supplies two methods to convert them
* to integer values by changing their bit layout: {@link #doubleToSortableLong},
* {@link #floatToSortableInt}. You will have no precision loss by
* converting floating point numbers to integers and back (only that the integer form
* is not usable). Other data types like dates can easily converted to longs or ints (e.g.
* date to long: {@link java.util.Date#getTime}).
*
* <p>For easy usage, the trie algorithm is implemented for indexing inside * <p>For easy usage, the trie algorithm is implemented for indexing inside
* {@link org.apache.lucene.analysis.LegacyNumericTokenStream} that can index <code>int</code>, <code>long</code>, * {@link org.apache.lucene.analysis.LegacyNumericTokenStream} that can index <code>int</code>, <code>long</code>,
* <code>float</code>, and <code>double</code>. For querying, * <code>float</code>, and <code>double</code>. For querying,
@ -231,58 +224,6 @@ public final class LegacyNumericUtils {
return (sortableBits << getPrefixCodedIntShift(val)) ^ 0x80000000; return (sortableBits << getPrefixCodedIntShift(val)) ^ 0x80000000;
} }
/**
* Converts a <code>double</code> value to a sortable signed <code>long</code>.
* The value is converted by getting their IEEE 754 floating-point &quot;double format&quot;
* bit layout and then some bits are swapped, to be able to compare the result as long.
* By this the precision is not reduced, but the value can easily used as a long.
* The sort order (including {@link Double#NaN}) is defined by
* {@link Double#compareTo}; {@code NaN} is greater than positive infinity.
* @see #sortableLongToDouble
*/
public static long doubleToSortableLong(double val) {
return sortableDoubleBits(Double.doubleToLongBits(val));
}
/**
* Converts a sortable <code>long</code> back to a <code>double</code>.
* @see #doubleToSortableLong
*/
public static double sortableLongToDouble(long val) {
return Double.longBitsToDouble(sortableDoubleBits(val));
}
/**
* Converts a <code>float</code> value to a sortable signed <code>int</code>.
* The value is converted by getting their IEEE 754 floating-point &quot;float format&quot;
* bit layout and then some bits are swapped, to be able to compare the result as int.
* By this the precision is not reduced, but the value can easily used as an int.
* The sort order (including {@link Float#NaN}) is defined by
* {@link Float#compareTo}; {@code NaN} is greater than positive infinity.
* @see #sortableIntToFloat
*/
public static int floatToSortableInt(float val) {
return sortableFloatBits(Float.floatToIntBits(val));
}
/**
* Converts a sortable <code>int</code> back to a <code>float</code>.
* @see #floatToSortableInt
*/
public static float sortableIntToFloat(int val) {
return Float.intBitsToFloat(sortableFloatBits(val));
}
/** Converts IEEE 754 representation of a double to sortable order (or back to the original) */
public static long sortableDoubleBits(long bits) {
return bits ^ (bits >> 63) & 0x7fffffffffffffffL;
}
/** Converts IEEE 754 representation of a float to sortable order (or back to the original) */
public static int sortableFloatBits(int bits) {
return bits ^ (bits >> 31) & 0x7fffffff;
}
/** /**
* Splits a long range recursively. * Splits a long range recursively.
* You may implement a builder that adds clauses to a * You may implement a builder that adds clauses to a

View File

@ -22,6 +22,14 @@ import java.util.Arrays;
/** /**
* Helper APIs to encode numeric values as sortable bytes and vice-versa. * Helper APIs to encode numeric values as sortable bytes and vice-versa.
*
* <p>
* To also index floating point numbers, this class supplies two methods to convert them
* to integer values by changing their bit layout: {@link #doubleToSortableLong},
* {@link #floatToSortableInt}. You will have no precision loss by
* converting floating point numbers to integers and back (only that the integer form
* is not usable). Other data types like dates can easily converted to longs or ints (e.g.
* date to long: {@link java.util.Date#getTime}).
* *
* @lucene.internal * @lucene.internal
*/ */
@ -38,16 +46,16 @@ public final class NumericUtils {
* {@link Double#compareTo}; {@code NaN} is greater than positive infinity. * {@link Double#compareTo}; {@code NaN} is greater than positive infinity.
* @see #sortableLongToDouble * @see #sortableLongToDouble
*/ */
public static long doubleToSortableLong(double val) { public static long doubleToSortableLong(double value) {
return sortableDoubleBits(Double.doubleToLongBits(val)); return sortableDoubleBits(Double.doubleToLongBits(value));
} }
/** /**
* Converts a sortable <code>long</code> back to a <code>double</code>. * Converts a sortable <code>long</code> back to a <code>double</code>.
* @see #doubleToSortableLong * @see #doubleToSortableLong
*/ */
public static double sortableLongToDouble(long val) { public static double sortableLongToDouble(long encoded) {
return Double.longBitsToDouble(sortableDoubleBits(val)); return Double.longBitsToDouble(sortableDoubleBits(encoded));
} }
/** /**
@ -59,16 +67,16 @@ public final class NumericUtils {
* {@link Float#compareTo}; {@code NaN} is greater than positive infinity. * {@link Float#compareTo}; {@code NaN} is greater than positive infinity.
* @see #sortableIntToFloat * @see #sortableIntToFloat
*/ */
public static int floatToSortableInt(float val) { public static int floatToSortableInt(float value) {
return sortableFloatBits(Float.floatToIntBits(val)); return sortableFloatBits(Float.floatToIntBits(value));
} }
/** /**
* Converts a sortable <code>int</code> back to a <code>float</code>. * Converts a sortable <code>int</code> back to a <code>float</code>.
* @see #floatToSortableInt * @see #floatToSortableInt
*/ */
public static float sortableIntToFloat(int val) { public static float sortableIntToFloat(int encoded) {
return Float.intBitsToFloat(sortableFloatBits(val)); return Float.intBitsToFloat(sortableFloatBits(encoded));
} }
/** Converts IEEE 754 representation of a double to sortable order (or back to the original) */ /** Converts IEEE 754 representation of a double to sortable order (or back to the original) */
@ -122,83 +130,76 @@ public final class NumericUtils {
} }
} }
/** Returns true if N-dim rect A contains N-dim rect B */ /**
public static boolean contains(int bytesPerDim, * Encodes an integer {@code value} such that unsigned byte order comparison
byte[] minPackedA, byte[] maxPackedA, * is consistent with {@link Integer#compare(int, int)}
byte[] minPackedB, byte[] maxPackedB) { * @see #sortableBytesToInt(byte[], int)
int dims = minPackedA.length / bytesPerDim; */
for(int dim=0;dim<dims;dim++) { public static void intToSortableBytes(int value, byte[] result, int offset) {
int offset = dim * bytesPerDim;
if (StringHelper.compare(bytesPerDim, minPackedA, offset, minPackedB, offset) > 0) {
return false;
}
if (StringHelper.compare(bytesPerDim, maxPackedA, offset, maxPackedB, offset) < 0) {
return false;
}
}
return true;
}
public static void intToBytes(int x, byte[] dest, int offset) {
// Flip the sign bit, so negative ints sort before positive ints correctly: // Flip the sign bit, so negative ints sort before positive ints correctly:
x ^= 0x80000000; value ^= 0x80000000;
for (int i = 0; i < 4; i++) { result[offset] = (byte) (value >> 24);
dest[offset+i] = (byte) (x >> 24-i*8); result[offset+1] = (byte) (value >> 16);
} result[offset+2] = (byte) (value >> 8);
result[offset+3] = (byte) value;
} }
public static int bytesToInt(byte[] src, int offset) { /**
int x = 0; * Decodes an integer value previously written with {@link #intToSortableBytes}
for (int i = 0; i < 4; i++) { * @see #intToSortableBytes(int, byte[], int)
x |= (src[offset+i] & 0xff) << (24-i*8); */
} public static int sortableBytesToInt(byte[] encoded, int offset) {
int x = ((encoded[offset] & 0xFF) << 24) |
((encoded[offset+1] & 0xFF) << 16) |
((encoded[offset+2] & 0xFF) << 8) |
(encoded[offset+3] & 0xFF);
// Re-flip the sign bit to restore the original value: // Re-flip the sign bit to restore the original value:
return x ^ 0x80000000; return x ^ 0x80000000;
} }
public static void longToBytes(long v, byte[] bytes, int offset) { /**
* Encodes an long {@code value} such that unsigned byte order comparison
* is consistent with {@link Long#compare(long, long)}
* @see #sortableBytesToLong(byte[], int)
*/
public static void longToSortableBytes(long value, byte[] result, int offset) {
// Flip the sign bit so negative longs sort before positive longs: // Flip the sign bit so negative longs sort before positive longs:
v ^= 0x8000000000000000L; value ^= 0x8000000000000000L;
longToBytesDirect(v, bytes, offset); result[offset] = (byte) (value >> 56);
result[offset+1] = (byte) (value >> 48);
result[offset+2] = (byte) (value >> 40);
result[offset+3] = (byte) (value >> 32);
result[offset+4] = (byte) (value >> 24);
result[offset+5] = (byte) (value >> 16);
result[offset+6] = (byte) (value >> 8);
result[offset+7] = (byte) value;
} }
public static void longToBytesDirect(long v, byte[] bytes, int offset) { /**
bytes[offset] = (byte) (v >> 56); * Decodes a long value previously written with {@link #longToSortableBytes}
bytes[offset+1] = (byte) (v >> 48); * @see #longToSortableBytes(long, byte[], int)
bytes[offset+2] = (byte) (v >> 40); */
bytes[offset+3] = (byte) (v >> 32); public static long sortableBytesToLong(byte[] encoded, int offset) {
bytes[offset+4] = (byte) (v >> 24); long v = ((encoded[offset] & 0xFFL) << 56) |
bytes[offset+5] = (byte) (v >> 16); ((encoded[offset+1] & 0xFFL) << 48) |
bytes[offset+6] = (byte) (v >> 8); ((encoded[offset+2] & 0xFFL) << 40) |
bytes[offset+7] = (byte) v; ((encoded[offset+3] & 0xFFL) << 32) |
} ((encoded[offset+4] & 0xFFL) << 24) |
((encoded[offset+5] & 0xFFL) << 16) |
public static long bytesToLong(byte[] bytes, int offset) { ((encoded[offset+6] & 0xFFL) << 8) |
long v = bytesToLongDirect(bytes, offset); (encoded[offset+7] & 0xFFL);
// Flip the sign bit back // Flip the sign bit back
v ^= 0x8000000000000000L; v ^= 0x8000000000000000L;
return v; return v;
} }
public static long bytesToLongDirect(byte[] bytes, int offset) { /**
long v = ((bytes[offset] & 0xffL) << 56) | * Encodes a BigInteger {@code value} such that unsigned byte order comparison
((bytes[offset+1] & 0xffL) << 48) | * is consistent with {@link BigInteger#compareTo(BigInteger)}. This also sign-extends
((bytes[offset+2] & 0xffL) << 40) | * the value to {@code bigIntSize} bytes if necessary: useful to create a fixed-width size.
((bytes[offset+3] & 0xffL) << 32) | * @see #sortableBytesToBigInt(byte[], int, int)
((bytes[offset+4] & 0xffL) << 24) | */
((bytes[offset+5] & 0xffL) << 16) | public static void bigIntToSortableBytes(BigInteger bigInt, int bigIntSize, byte[] result, int offset) {
((bytes[offset+6] & 0xffL) << 8) |
(bytes[offset+7] & 0xffL);
return v;
}
public static void sortableBigIntBytes(byte[] bytes) {
// Flip the sign bit so negative bigints sort before positive bigints:
bytes[0] ^= 0x80;
}
public static void bigIntToBytes(BigInteger bigInt, int bigIntSize, byte[] result, int offset) {
byte[] bigIntBytes = bigInt.toByteArray(); byte[] bigIntBytes = bigInt.toByteArray();
byte[] fullBigIntBytes; byte[] fullBigIntBytes;
@ -214,17 +215,23 @@ public final class NumericUtils {
} else { } else {
throw new IllegalArgumentException("BigInteger: " + bigInt + " requires more than " + bigIntSize + " bytes storage"); throw new IllegalArgumentException("BigInteger: " + bigInt + " requires more than " + bigIntSize + " bytes storage");
} }
sortableBigIntBytes(fullBigIntBytes); // Flip the sign bit so negative bigints sort before positive bigints:
fullBigIntBytes[0] ^= 0x80;
System.arraycopy(fullBigIntBytes, 0, result, offset, bigIntSize); System.arraycopy(fullBigIntBytes, 0, result, offset, bigIntSize);
assert bytesToBigInt(result, offset, bigIntSize).equals(bigInt): "bigInt=" + bigInt + " converted=" + bytesToBigInt(result, offset, bigIntSize); assert sortableBytesToBigInt(result, offset, bigIntSize).equals(bigInt): "bigInt=" + bigInt + " converted=" + sortableBytesToBigInt(result, offset, bigIntSize);
} }
public static BigInteger bytesToBigInt(byte[] bytes, int offset, int length) { /**
* Decodes a BigInteger value previously written with {@link #bigIntToSortableBytes}
* @see #bigIntToSortableBytes(BigInteger, int, byte[], int)
*/
public static BigInteger sortableBytesToBigInt(byte[] encoded, int offset, int length) {
byte[] bigIntBytes = new byte[length]; byte[] bigIntBytes = new byte[length];
System.arraycopy(bytes, offset, bigIntBytes, 0, length); System.arraycopy(encoded, offset, bigIntBytes, 0, length);
sortableBigIntBytes(bigIntBytes); // Flip the sign bit back to the original
bigIntBytes[0] ^= 0x80;
return new BigInteger(bigIntBytes); return new BigInteger(bigIntBytes);
} }
} }

View File

@ -55,6 +55,55 @@ public final class RamUsageEstimator {
/** No instantiation. */ /** No instantiation. */
private RamUsageEstimator() {} private RamUsageEstimator() {}
/**
* Number of bytes used to represent a {@code boolean} in binary form
* @deprecated use {@code 1} instead.
*/
@Deprecated
public final static int NUM_BYTES_BOOLEAN = 1;
/**
* Number of bytes used to represent a {@code byte} in binary form
* @deprecated use {@code 1} instead.
*/
@Deprecated
public final static int NUM_BYTES_BYTE = 1;
/**
* Number of bytes used to represent a {@code char} in binary form
* @deprecated use {@link Character#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_CHAR = Character.BYTES;
/**
* Number of bytes used to represent a {@code short} in binary form
* @deprecated use {@link Short#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_SHORT = Short.BYTES;
/**
* Number of bytes used to represent an {@code int} in binary form
* @deprecated use {@link Integer#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_INT = Integer.BYTES;
/**
* Number of bytes used to represent a {@code float} in binary form
* @deprecated use {@link Float#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_FLOAT = Float.BYTES;
/**
* Number of bytes used to represent a {@code long} in binary form
* @deprecated use {@link Long#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_LONG = Long.BYTES;
/**
* Number of bytes used to represent a {@code double} in binary form
* @deprecated use {@link Double#BYTES} instead.
*/
@Deprecated
public final static int NUM_BYTES_DOUBLE = Double.BYTES;
/** /**
* True, iff compressed references (oops) are enabled by this JVM * True, iff compressed references (oops) are enabled by this JVM
*/ */

View File

@ -16,7 +16,6 @@
*/ */
package org.apache.lucene.index; package org.apache.lucene.index;
import org.apache.lucene.analysis.CannedBinaryTokenStream; import org.apache.lucene.analysis.CannedBinaryTokenStream;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.LegacyDoubleField; import org.apache.lucene.document.LegacyDoubleField;
@ -29,6 +28,7 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.TestUtil;
public class TestTerms extends LuceneTestCase { public class TestTerms extends LuceneTestCase {
@ -167,8 +167,8 @@ public class TestTerms extends LuceneTestCase {
IndexReader r = w.getReader(); IndexReader r = w.getReader();
Terms terms = MultiFields.getTerms(r, "field"); Terms terms = MultiFields.getTerms(r, "field");
assertEquals(minValue, LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.getMinInt(terms)), 0.0f); assertEquals(minValue, NumericUtils.sortableIntToFloat(LegacyNumericUtils.getMinInt(terms)), 0.0f);
assertEquals(maxValue, LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.getMaxInt(terms)), 0.0f); assertEquals(maxValue, NumericUtils.sortableIntToFloat(LegacyNumericUtils.getMaxInt(terms)), 0.0f);
r.close(); r.close();
w.close(); w.close();
@ -194,8 +194,8 @@ public class TestTerms extends LuceneTestCase {
Terms terms = MultiFields.getTerms(r, "field"); Terms terms = MultiFields.getTerms(r, "field");
assertEquals(minValue, LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.getMinLong(terms)), 0.0); assertEquals(minValue, NumericUtils.sortableLongToDouble(LegacyNumericUtils.getMinLong(terms)), 0.0);
assertEquals(maxValue, LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.getMaxLong(terms)), 0.0); assertEquals(maxValue, NumericUtils.sortableLongToDouble(LegacyNumericUtils.getMaxLong(terms)), 0.0);
r.close(); r.close();
w.close(); w.close();

View File

@ -34,6 +34,7 @@ import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.TestLegacyNumericUtils; // NaN arrays import org.apache.lucene.util.TestLegacyNumericUtils; // NaN arrays
import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.TestUtil;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -525,7 +526,7 @@ public class TestNumericRangeQuery32 extends LuceneTestCase {
final int lower=-1000, upper=+2000; final int lower=-1000, upper=+2000;
Query tq= LegacyNumericRangeQuery.newFloatRange(field, precisionStep, Query tq= LegacyNumericRangeQuery.newFloatRange(field, precisionStep,
LegacyNumericUtils.sortableIntToFloat(lower), LegacyNumericUtils.sortableIntToFloat(upper), true, true); NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
TopDocs tTopDocs = searcher.search(tq, 1); TopDocs tTopDocs = searcher.search(tq, 1);
assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits ); assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
} }

View File

@ -34,6 +34,7 @@ import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.TestLegacyNumericUtils; import org.apache.lucene.util.TestLegacyNumericUtils;
import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.TestUtil;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -559,7 +560,7 @@ public class TestNumericRangeQuery64 extends LuceneTestCase {
final long lower=-1000L, upper=+2000L; final long lower=-1000L, upper=+2000L;
Query tq= LegacyNumericRangeQuery.newDoubleRange(field, precisionStep, Query tq= LegacyNumericRangeQuery.newDoubleRange(field, precisionStep,
LegacyNumericUtils.sortableLongToDouble(lower), LegacyNumericUtils.sortableLongToDouble(upper), true, true); NumericUtils.sortableLongToDouble(lower), NumericUtils.sortableLongToDouble(upper), true, true);
TopDocs tTopDocs = searcher.search(tq, 1); TopDocs tTopDocs = searcher.search(tq, 1);
assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits ); assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
} }

View File

@ -393,8 +393,8 @@ public class TestPointQueries extends LuceneTestCase {
for(int i=0;i<10000;i++) { for(int i=0;i<10000;i++) {
long v = random().nextLong(); long v = random().nextLong();
byte[] tmp = new byte[8]; byte[] tmp = new byte[8];
NumericUtils.longToBytes(v, tmp, 0); NumericUtils.longToSortableBytes(v, tmp, 0);
long v2 = NumericUtils.bytesToLong(tmp, 0); long v2 = NumericUtils.sortableBytesToLong(tmp, 0);
assertEquals("got bytes=" + Arrays.toString(tmp), v, v2); assertEquals("got bytes=" + Arrays.toString(tmp), v, v2);
} }
} }
@ -467,7 +467,7 @@ public class TestPointQueries extends LuceneTestCase {
if (missing.get(id) == false) { if (missing.get(id) == false) {
doc.add(new LongPoint("sn_value", values[id])); doc.add(new LongPoint("sn_value", values[id]));
byte[] bytes = new byte[8]; byte[] bytes = new byte[8];
NumericUtils.longToBytes(values[id], bytes, 0); NumericUtils.longToSortableBytes(values[id], bytes, 0);
doc.add(new BinaryPoint("ss_value", bytes)); doc.add(new BinaryPoint("ss_value", bytes));
} }
} }
@ -529,11 +529,11 @@ public class TestPointQueries extends LuceneTestCase {
System.out.println("\n" + Thread.currentThread().getName() + ": TEST: iter=" + iter + " value=" + lower + " TO " + upper); System.out.println("\n" + Thread.currentThread().getName() + ": TEST: iter=" + iter + " value=" + lower + " TO " + upper);
byte[] tmp = new byte[8]; byte[] tmp = new byte[8];
if (lower != null) { if (lower != null) {
NumericUtils.longToBytes(lower, tmp, 0); NumericUtils.longToSortableBytes(lower, tmp, 0);
System.out.println(" lower bytes=" + Arrays.toString(tmp)); System.out.println(" lower bytes=" + Arrays.toString(tmp));
} }
if (upper != null) { if (upper != null) {
NumericUtils.longToBytes(upper, tmp, 0); NumericUtils.longToSortableBytes(upper, tmp, 0);
System.out.println(" upper bytes=" + Arrays.toString(tmp)); System.out.println(" upper bytes=" + Arrays.toString(tmp));
} }
} }
@ -542,9 +542,9 @@ public class TestPointQueries extends LuceneTestCase {
query = LongPoint.newRangeQuery("sn_value", lower, upper); query = LongPoint.newRangeQuery("sn_value", lower, upper);
} else { } else {
byte[] lowerBytes = new byte[8]; byte[] lowerBytes = new byte[8];
NumericUtils.longToBytes(lower, lowerBytes, 0); NumericUtils.longToSortableBytes(lower, lowerBytes, 0);
byte[] upperBytes = new byte[8]; byte[] upperBytes = new byte[8];
NumericUtils.longToBytes(upper, upperBytes, 0); NumericUtils.longToSortableBytes(upper, upperBytes, 0);
query = BinaryPoint.newRangeQuery("ss_value", lowerBytes, upperBytes); query = BinaryPoint.newRangeQuery("ss_value", lowerBytes, upperBytes);
} }

View File

@ -16,7 +16,6 @@
*/ */
package org.apache.lucene.search; package org.apache.lucene.search;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.document.SortedNumericDocValuesField;
@ -25,8 +24,8 @@ import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.NumericUtils;
/** Simple tests for SortedNumericSortField */ /** Simple tests for SortedNumericSortField */
public class TestSortedNumericSortField extends LuceneTestCase { public class TestSortedNumericSortField extends LuceneTestCase {
@ -223,12 +222,12 @@ public class TestSortedNumericSortField extends LuceneTestCase {
Directory dir = newDirectory(); Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir); RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document doc = new Document(); Document doc = new Document();
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.floatToSortableInt(-3f))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.floatToSortableInt(-3f)));
doc.add(newStringField("id", "2", Field.Store.YES)); doc.add(newStringField("id", "2", Field.Store.YES));
writer.addDocument(doc); writer.addDocument(doc);
doc = new Document(); doc = new Document();
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.floatToSortableInt(-5f))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.floatToSortableInt(-5f)));
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.floatToSortableInt(7f))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.floatToSortableInt(7f)));
doc.add(newStringField("id", "1", Field.Store.YES)); doc.add(newStringField("id", "1", Field.Store.YES));
writer.addDocument(doc); writer.addDocument(doc);
IndexReader ir = writer.getReader(); IndexReader ir = writer.getReader();
@ -251,12 +250,12 @@ public class TestSortedNumericSortField extends LuceneTestCase {
Directory dir = newDirectory(); Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir); RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document doc = new Document(); Document doc = new Document();
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.doubleToSortableLong(-3d))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.doubleToSortableLong(-3d)));
doc.add(newStringField("id", "2", Field.Store.YES)); doc.add(newStringField("id", "2", Field.Store.YES));
writer.addDocument(doc); writer.addDocument(doc);
doc = new Document(); doc = new Document();
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.doubleToSortableLong(-5d))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.doubleToSortableLong(-5d)));
doc.add(new SortedNumericDocValuesField("value", LegacyNumericUtils.doubleToSortableLong(7d))); doc.add(new SortedNumericDocValuesField("value", NumericUtils.doubleToSortableLong(7d)));
doc.add(newStringField("id", "1", Field.Store.YES)); doc.add(newStringField("id", "1", Field.Store.YES));
writer.addDocument(doc); writer.addDocument(doc);
IndexReader ir = writer.getReader(); IndexReader ir = writer.getReader();

View File

@ -145,8 +145,8 @@ public class TestLegacyNumericUtils extends LuceneTestCase {
// check forward and back conversion // check forward and back conversion
for (int i=0; i<vals.length; i++) { for (int i=0; i<vals.length; i++) {
longVals[i]= LegacyNumericUtils.doubleToSortableLong(vals[i]); longVals[i]= NumericUtils.doubleToSortableLong(vals[i]);
assertTrue( "forward and back conversion should generate same double", Double.compare(vals[i], LegacyNumericUtils.sortableLongToDouble(longVals[i]))==0 ); assertTrue( "forward and back conversion should generate same double", Double.compare(vals[i], NumericUtils.sortableLongToDouble(longVals[i]))==0 );
} }
// check sort order (prefixVals should be ascending) // check sort order (prefixVals should be ascending)
@ -164,10 +164,10 @@ public class TestLegacyNumericUtils extends LuceneTestCase {
}; };
public void testSortableDoubleNaN() { public void testSortableDoubleNaN() {
final long plusInf = LegacyNumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY); final long plusInf = NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY);
for (double nan : DOUBLE_NANs) { for (double nan : DOUBLE_NANs) {
assertTrue(Double.isNaN(nan)); assertTrue(Double.isNaN(nan));
final long sortable = LegacyNumericUtils.doubleToSortableLong(nan); final long sortable = NumericUtils.doubleToSortableLong(nan);
assertTrue("Double not sorted correctly: " + nan + ", long repr: " assertTrue("Double not sorted correctly: " + nan + ", long repr: "
+ sortable + ", positive inf.: " + plusInf, sortable > plusInf); + sortable + ", positive inf.: " + plusInf, sortable > plusInf);
} }
@ -182,8 +182,8 @@ public class TestLegacyNumericUtils extends LuceneTestCase {
// check forward and back conversion // check forward and back conversion
for (int i=0; i<vals.length; i++) { for (int i=0; i<vals.length; i++) {
intVals[i]= LegacyNumericUtils.floatToSortableInt(vals[i]); intVals[i]= NumericUtils.floatToSortableInt(vals[i]);
assertTrue( "forward and back conversion should generate same double", Float.compare(vals[i], LegacyNumericUtils.sortableIntToFloat(intVals[i]))==0 ); assertTrue( "forward and back conversion should generate same double", Float.compare(vals[i], NumericUtils.sortableIntToFloat(intVals[i]))==0 );
} }
// check sort order (prefixVals should be ascending) // check sort order (prefixVals should be ascending)
@ -201,10 +201,10 @@ public class TestLegacyNumericUtils extends LuceneTestCase {
}; };
public void testSortableFloatNaN() { public void testSortableFloatNaN() {
final int plusInf = LegacyNumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY); final int plusInf = NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY);
for (float nan : FLOAT_NANs) { for (float nan : FLOAT_NANs) {
assertTrue(Float.isNaN(nan)); assertTrue(Float.isNaN(nan));
final int sortable = LegacyNumericUtils.floatToSortableInt(nan); final int sortable = NumericUtils.floatToSortableInt(nan);
assertTrue("Float not sorted correctly: " + nan + ", int repr: " assertTrue("Float not sorted correctly: " + nan + ", int repr: "
+ sortable + ", positive inf.: " + plusInf, sortable > plusInf); + sortable + ", positive inf.: " + plusInf, sortable > plusInf);
} }

View File

@ -0,0 +1,491 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.util;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Tests for NumericUtils static methods.
*/
public class TestNumericUtils extends LuceneTestCase {
/**
* generate a series of encoded longs, each numerical one bigger than the one before.
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testLongConversionAndOrdering() throws Exception {
BytesRef previous = null;
BytesRef current = new BytesRef(new byte[Long.BYTES]);
for (long value = -100000L; value < 100000L; value++) {
NumericUtils.longToSortableBytes(value, current.bytes, current.offset);
if (previous == null) {
previous = new BytesRef(new byte[Long.BYTES]);
} else {
// test if smaller
assertTrue("current bigger than previous: ", previous.compareTo(current) < 0);
}
// test is back and forward conversion works
assertEquals("forward and back conversion should generate same long", value, NumericUtils.sortableBytesToLong(current.bytes, current.offset));
// next step
System.arraycopy(current.bytes, current.offset, previous.bytes, previous.offset, current.length);
}
}
/**
* generate a series of encoded ints, each numerical one bigger than the one before.
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testIntConversionAndOrdering() throws Exception {
BytesRef previous = null;
BytesRef current = new BytesRef(new byte[Integer.BYTES]);
for (int value = -100000; value < 100000; value++) {
NumericUtils.intToSortableBytes(value, current.bytes, current.offset);
if (previous == null) {
previous = new BytesRef(new byte[Integer.BYTES]);
} else {
// test if smaller
assertTrue("current bigger than previous: ", previous.compareTo(current) < 0);
}
// test is back and forward conversion works
assertEquals("forward and back conversion should generate same int", value, NumericUtils.sortableBytesToInt(current.bytes, current.offset));
// next step
System.arraycopy(current.bytes, current.offset, previous.bytes, previous.offset, current.length);
}
}
/**
* generate a series of encoded BigIntegers, each numerical one bigger than the one before.
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testBigIntConversionAndOrdering() throws Exception {
// we need at least 3 bytes of storage.
int size = TestUtil.nextInt(random(), 3, 16);
BytesRef previous = null;
BytesRef current = new BytesRef(new byte[size]);
for (long value = -100000L; value < 100000L; value++) {
NumericUtils.bigIntToSortableBytes(BigInteger.valueOf(value), size, current.bytes, current.offset);
if (previous == null) {
previous = new BytesRef(new byte[size]);
} else {
// test if smaller
assertTrue("current bigger than previous: ", previous.compareTo(current) < 0);
}
// test is back and forward conversion works
assertEquals("forward and back conversion should generate same BigInteger",
BigInteger.valueOf(value),
NumericUtils.sortableBytesToBigInt(current.bytes, current.offset, current.length));
// next step
System.arraycopy(current.bytes, current.offset, previous.bytes, previous.offset, current.length);
}
}
/**
* check extreme values of longs
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testLongSpecialValues() throws Exception {
long[] values = new long[] {
Long.MIN_VALUE, Long.MIN_VALUE+1, Long.MIN_VALUE+2, -5003400000000L,
-4000L, -3000L, -2000L, -1000L, -1L, 0L, 1L, 10L, 300L, 50006789999999999L, Long.MAX_VALUE-2, Long.MAX_VALUE-1, Long.MAX_VALUE
};
BytesRef[] encoded = new BytesRef[values.length];
for (int i = 0; i < values.length; i++) {
encoded[i] = new BytesRef(new byte[Long.BYTES]);
NumericUtils.longToSortableBytes(values[i], encoded[i].bytes, encoded[i].offset);
// check forward and back conversion
assertEquals("forward and back conversion should generate same long",
values[i],
NumericUtils.sortableBytesToLong(encoded[i].bytes, encoded[i].offset));
}
// check sort order (encoded values should be ascending)
for (int i = 1; i < encoded.length; i++) {
assertTrue("check sort order", encoded[i-1].compareTo(encoded[i]) < 0);
}
}
/**
* check extreme values of ints
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testIntSpecialValues() throws Exception {
int[] values = new int[] {
Integer.MIN_VALUE, Integer.MIN_VALUE+1, Integer.MIN_VALUE+2, -64765767,
-4000, -3000, -2000, -1000, -1, 0, 1, 10, 300, 765878989, Integer.MAX_VALUE-2, Integer.MAX_VALUE-1, Integer.MAX_VALUE
};
BytesRef[] encoded = new BytesRef[values.length];
for (int i = 0; i < values.length; i++) {
encoded[i] = new BytesRef(new byte[Integer.BYTES]);
NumericUtils.intToSortableBytes(values[i], encoded[i].bytes, encoded[i].offset);
// check forward and back conversion
assertEquals("forward and back conversion should generate same int",
values[i],
NumericUtils.sortableBytesToInt(encoded[i].bytes, encoded[i].offset));
}
// check sort order (encoded values should be ascending)
for (int i = 1; i < encoded.length; i++) {
assertTrue("check sort order", encoded[i-1].compareTo(encoded[i]) < 0);
}
}
/**
* check extreme values of big integers (4 bytes)
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testBigIntSpecialValues() throws Exception {
BigInteger[] values = new BigInteger[] {
BigInteger.valueOf(Integer.MIN_VALUE), BigInteger.valueOf(Integer.MIN_VALUE+1),
BigInteger.valueOf(Integer.MIN_VALUE+2), BigInteger.valueOf(-64765767),
BigInteger.valueOf(-4000), BigInteger.valueOf(-3000), BigInteger.valueOf(-2000),
BigInteger.valueOf(-1000), BigInteger.valueOf(-1), BigInteger.valueOf(0),
BigInteger.valueOf(1), BigInteger.valueOf(10), BigInteger.valueOf(300),
BigInteger.valueOf(765878989), BigInteger.valueOf(Integer.MAX_VALUE-2),
BigInteger.valueOf(Integer.MAX_VALUE-1), BigInteger.valueOf(Integer.MAX_VALUE)
};
BytesRef[] encoded = new BytesRef[values.length];
for (int i = 0; i < values.length; i++) {
encoded[i] = new BytesRef(new byte[Integer.BYTES]);
NumericUtils.bigIntToSortableBytes(values[i], Integer.BYTES, encoded[i].bytes, encoded[i].offset);
// check forward and back conversion
assertEquals("forward and back conversion should generate same big integer",
values[i],
NumericUtils.sortableBytesToBigInt(encoded[i].bytes, encoded[i].offset, Integer.BYTES));
}
// check sort order (encoded values should be ascending)
for (int i = 1; i < encoded.length; i++) {
assertTrue("check sort order", encoded[i-1].compareTo(encoded[i]) < 0);
}
}
/**
* check various sorted values of doubles (including extreme values)
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testDoubles() throws Exception {
double[] values = new double[] {
Double.NEGATIVE_INFINITY, -2.3E25, -1.0E15, -1.0, -1.0E-1, -1.0E-2, -0.0,
+0.0, 1.0E-2, 1.0E-1, 1.0, 1.0E15, 2.3E25, Double.POSITIVE_INFINITY, Double.NaN
};
long[] encoded = new long[values.length];
// check forward and back conversion
for (int i = 0; i < values.length; i++) {
encoded[i] = NumericUtils.doubleToSortableLong(values[i]);
assertTrue("forward and back conversion should generate same double",
Double.compare(values[i], NumericUtils.sortableLongToDouble(encoded[i])) == 0);
}
// check sort order (encoded values should be ascending)
for (int i = 1; i < encoded.length; i++) {
assertTrue("check sort order", encoded[i-1] < encoded[i]);
}
}
public static final double[] DOUBLE_NANs = {
Double.NaN,
Double.longBitsToDouble(0x7ff0000000000001L),
Double.longBitsToDouble(0x7fffffffffffffffL),
Double.longBitsToDouble(0xfff0000000000001L),
Double.longBitsToDouble(0xffffffffffffffffL)
};
public void testSortableDoubleNaN() {
final long plusInf = NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY);
for (double nan : DOUBLE_NANs) {
assertTrue(Double.isNaN(nan));
final long sortable = NumericUtils.doubleToSortableLong(nan);
assertTrue("Double not sorted correctly: " + nan + ", long repr: "
+ sortable + ", positive inf.: " + plusInf, sortable > plusInf);
}
}
/**
* check various sorted values of floats (including extreme values)
* check for correct ordering of the encoded bytes and that values round-trip.
*/
public void testFloats() throws Exception {
float[] values = new float[] {
Float.NEGATIVE_INFINITY, -2.3E25f, -1.0E15f, -1.0f, -1.0E-1f, -1.0E-2f, -0.0f,
+0.0f, 1.0E-2f, 1.0E-1f, 1.0f, 1.0E15f, 2.3E25f, Float.POSITIVE_INFINITY, Float.NaN
};
int[] encoded = new int[values.length];
// check forward and back conversion
for (int i = 0; i < values.length; i++) {
encoded[i] = NumericUtils.floatToSortableInt(values[i]);
assertTrue("forward and back conversion should generate same float",
Float.compare(values[i], NumericUtils.sortableIntToFloat(encoded[i])) == 0);
}
// check sort order (encoded values should be ascending)
for (int i = 1; i < encoded.length; i++) {
assertTrue( "check sort order", encoded[i-1] < encoded[i] );
}
}
public static final float[] FLOAT_NANs = {
Float.NaN,
Float.intBitsToFloat(0x7f800001),
Float.intBitsToFloat(0x7fffffff),
Float.intBitsToFloat(0xff800001),
Float.intBitsToFloat(0xffffffff)
};
public void testSortableFloatNaN() {
final int plusInf = NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY);
for (float nan : FLOAT_NANs) {
assertTrue(Float.isNaN(nan));
final int sortable = NumericUtils.floatToSortableInt(nan);
assertTrue("Float not sorted correctly: " + nan + ", int repr: "
+ sortable + ", positive inf.: " + plusInf, sortable > plusInf);
}
}
public void testAdd() throws Exception {
int iters = atLeast(10000);
int numBytes = TestUtil.nextInt(random(), 1, 100);
for(int iter=0;iter<iters;iter++) {
BigInteger v1 = new BigInteger(8*numBytes-1, random());
BigInteger v2 = new BigInteger(8*numBytes-1, random());
byte[] v1Bytes = new byte[numBytes];
byte[] v1RawBytes = v1.toByteArray();
assert v1RawBytes.length <= numBytes;
System.arraycopy(v1RawBytes, 0, v1Bytes, v1Bytes.length-v1RawBytes.length, v1RawBytes.length);
byte[] v2Bytes = new byte[numBytes];
byte[] v2RawBytes = v2.toByteArray();
assert v1RawBytes.length <= numBytes;
System.arraycopy(v2RawBytes, 0, v2Bytes, v2Bytes.length-v2RawBytes.length, v2RawBytes.length);
byte[] result = new byte[numBytes];
NumericUtils.add(numBytes, 0, v1Bytes, v2Bytes, result);
BigInteger sum = v1.add(v2);
assertTrue("sum=" + sum + " v1=" + v1 + " v2=" + v2 + " but result=" + new BigInteger(1, result), sum.equals(new BigInteger(1, result)));
}
}
public void testIllegalAdd() throws Exception {
byte[] bytes = new byte[4];
Arrays.fill(bytes, (byte) 0xff);
byte[] one = new byte[4];
one[3] = 1;
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
NumericUtils.add(4, 0, bytes, one, new byte[4]);
});
assertEquals("a + b overflows bytesPerDim=4", expected.getMessage());
}
public void testSubtract() throws Exception {
int iters = atLeast(10000);
int numBytes = TestUtil.nextInt(random(), 1, 100);
for(int iter=0;iter<iters;iter++) {
BigInteger v1 = new BigInteger(8*numBytes-1, random());
BigInteger v2 = new BigInteger(8*numBytes-1, random());
if (v1.compareTo(v2) < 0) {
BigInteger tmp = v1;
v1 = v2;
v2 = tmp;
}
byte[] v1Bytes = new byte[numBytes];
byte[] v1RawBytes = v1.toByteArray();
assert v1RawBytes.length <= numBytes: "length=" + v1RawBytes.length + " vs numBytes=" + numBytes;
System.arraycopy(v1RawBytes, 0, v1Bytes, v1Bytes.length-v1RawBytes.length, v1RawBytes.length);
byte[] v2Bytes = new byte[numBytes];
byte[] v2RawBytes = v2.toByteArray();
assert v2RawBytes.length <= numBytes;
assert v2RawBytes.length <= numBytes: "length=" + v2RawBytes.length + " vs numBytes=" + numBytes;
System.arraycopy(v2RawBytes, 0, v2Bytes, v2Bytes.length-v2RawBytes.length, v2RawBytes.length);
byte[] result = new byte[numBytes];
NumericUtils.subtract(numBytes, 0, v1Bytes, v2Bytes, result);
BigInteger diff = v1.subtract(v2);
assertTrue("diff=" + diff + " vs result=" + new BigInteger(result) + " v1=" + v1 + " v2=" + v2, diff.equals(new BigInteger(result)));
}
}
public void testIllegalSubtract() throws Exception {
byte[] v1 = new byte[4];
v1[3] = (byte) 0xf0;
byte[] v2 = new byte[4];
v2[3] = (byte) 0xf1;
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
NumericUtils.subtract(4, 0, v1, v2, new byte[4]);
});
assertEquals("a < b", expected.getMessage());
}
/** test round-trip encoding of random integers */
public void testIntsRoundTrip() {
byte[] encoded = new byte[Integer.BYTES];
for (int i = 0; i < 10000; i++) {
int value = random().nextInt();
NumericUtils.intToSortableBytes(value, encoded, 0);
assertEquals(value, NumericUtils.sortableBytesToInt(encoded, 0));
}
}
/** test round-trip encoding of random longs */
public void testLongsRoundTrip() {
byte[] encoded = new byte[Long.BYTES];
for (int i = 0; i < 10000; i++) {
long value = TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE);
NumericUtils.longToSortableBytes(value, encoded, 0);
assertEquals(value, NumericUtils.sortableBytesToLong(encoded, 0));
}
}
/** test round-trip encoding of random floats */
public void testFloatsRoundTrip() {
byte[] encoded = new byte[Float.BYTES];
for (int i = 0; i < 10000; i++) {
float value = Float.intBitsToFloat(random().nextInt());
NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(value), encoded, 0);
float actual = NumericUtils.sortableIntToFloat(NumericUtils.sortableBytesToInt(encoded, 0));
assertEquals(Float.floatToIntBits(value), Float.floatToIntBits(actual));
}
}
/** test round-trip encoding of random doubles */
public void testDoublesRoundTrip() {
byte[] encoded = new byte[Double.BYTES];
for (int i = 0; i < 10000; i++) {
double value = Double.longBitsToDouble(TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE));
NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(value), encoded, 0);
double actual = NumericUtils.sortableLongToDouble(NumericUtils.sortableBytesToLong(encoded, 0));
assertEquals(Double.doubleToLongBits(value), Double.doubleToLongBits(actual));
}
}
/** test round-trip encoding of random big integers */
public void testBigIntsRoundTrip() {
for (int i = 0; i < 10000; i++) {
BigInteger value = TestUtil.nextBigInteger(random(), 16);
int length = value.toByteArray().length;
// make sure sign extension is tested: sometimes pad to more bytes when encoding.
int maxLength = TestUtil.nextInt(random(), length, length + 3);
byte[] encoded = new byte[maxLength];
NumericUtils.bigIntToSortableBytes(value, maxLength, encoded, 0);
assertEquals(value, NumericUtils.sortableBytesToBigInt(encoded, 0, maxLength));
}
}
/** check sort order of random integers consistent with Integer.compare */
public void testIntsCompare() {
BytesRef left = new BytesRef(new byte[Integer.BYTES]);
BytesRef right = new BytesRef(new byte[Integer.BYTES]);
for (int i = 0; i < 10000; i++) {
int leftValue = random().nextInt();
NumericUtils.intToSortableBytes(leftValue, left.bytes, left.offset);
int rightValue = random().nextInt();
NumericUtils.intToSortableBytes(rightValue, right.bytes, right.offset);
assertEquals(Integer.signum(Integer.compare(leftValue, rightValue)),
Integer.signum(left.compareTo(right)));
}
}
/** check sort order of random longs consistent with Long.compare */
public void testLongsCompare() {
BytesRef left = new BytesRef(new byte[Long.BYTES]);
BytesRef right = new BytesRef(new byte[Long.BYTES]);
for (int i = 0; i < 10000; i++) {
long leftValue = TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE);
NumericUtils.longToSortableBytes(leftValue, left.bytes, left.offset);
long rightValue = TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE);
NumericUtils.longToSortableBytes(rightValue, right.bytes, right.offset);
assertEquals(Integer.signum(Long.compare(leftValue, rightValue)),
Integer.signum(left.compareTo(right)));
}
}
/** check sort order of random floats consistent with Float.compare */
public void testFloatsCompare() {
BytesRef left = new BytesRef(new byte[Float.BYTES]);
BytesRef right = new BytesRef(new byte[Float.BYTES]);
for (int i = 0; i < 10000; i++) {
float leftValue = Float.intBitsToFloat(random().nextInt());
NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(leftValue), left.bytes, left.offset);
float rightValue = Float.intBitsToFloat(random().nextInt());
NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(rightValue), right.bytes, right.offset);
assertEquals(Integer.signum(Float.compare(leftValue, rightValue)),
Integer.signum(left.compareTo(right)));
}
}
/** check sort order of random doubles consistent with Double.compare */
public void testDoublesCompare() {
BytesRef left = new BytesRef(new byte[Double.BYTES]);
BytesRef right = new BytesRef(new byte[Double.BYTES]);
for (int i = 0; i < 10000; i++) {
double leftValue = Double.longBitsToDouble(TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE));
NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(leftValue), left.bytes, left.offset);
double rightValue = Double.longBitsToDouble(TestUtil.nextLong(random(), Long.MIN_VALUE, Long.MAX_VALUE));
NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(rightValue), right.bytes, right.offset);
assertEquals(Integer.signum(Double.compare(leftValue, rightValue)),
Integer.signum(left.compareTo(right)));
}
}
/** check sort order of random bigintegers consistent with BigInteger.compareTo */
public void testBigIntsCompare() {
for (int i = 0; i < 10000; i++) {
int maxLength = TestUtil.nextInt(random(), 1, 16);
BigInteger leftValue = TestUtil.nextBigInteger(random(), maxLength);
BytesRef left = new BytesRef(new byte[maxLength]);
NumericUtils.bigIntToSortableBytes(leftValue, maxLength, left.bytes, left.offset);
BigInteger rightValue = TestUtil.nextBigInteger(random(), maxLength);
BytesRef right = new BytesRef(new byte[maxLength]);
NumericUtils.bigIntToSortableBytes(rightValue, maxLength, right.bytes, right.offset);
assertEquals(Integer.signum(leftValue.compareTo(rightValue)),
Integer.signum(left.compareTo(right)));
}
}
}

View File

@ -45,7 +45,7 @@ public class TestBKD extends LuceneTestCase {
BKDWriter w = new BKDWriter(100, dir, "tmp", 1, 4, 2, 1.0f); BKDWriter w = new BKDWriter(100, dir, "tmp", 1, 4, 2, 1.0f);
byte[] scratch = new byte[4]; byte[] scratch = new byte[4];
for(int docID=0;docID<100;docID++) { for(int docID=0;docID<100;docID++) {
NumericUtils.intToBytes(docID, scratch, 0); NumericUtils.intToSortableBytes(docID, scratch, 0);
w.add(scratch, docID); w.add(scratch, docID);
} }
@ -74,7 +74,7 @@ public class TestBKD extends LuceneTestCase {
@Override @Override
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
int x = NumericUtils.bytesToInt(packedValue, 0); int x = NumericUtils.sortableBytesToInt(packedValue, 0);
if (VERBOSE) { if (VERBOSE) {
System.out.println("visit docID=" + docID + " x=" + x); System.out.println("visit docID=" + docID + " x=" + x);
} }
@ -85,8 +85,8 @@ public class TestBKD extends LuceneTestCase {
@Override @Override
public Relation compare(byte[] minPacked, byte[] maxPacked) { public Relation compare(byte[] minPacked, byte[] maxPacked) {
int min = NumericUtils.bytesToInt(minPacked, 0); int min = NumericUtils.sortableBytesToInt(minPacked, 0);
int max = NumericUtils.bytesToInt(maxPacked, 0); int max = NumericUtils.sortableBytesToInt(maxPacked, 0);
assert max >= min; assert max >= min;
if (VERBOSE) { if (VERBOSE) {
System.out.println("compare: min=" + min + " max=" + max + " vs queryMin=" + queryMin + " queryMax=" + queryMax); System.out.println("compare: min=" + min + " max=" + max + " vs queryMin=" + queryMin + " queryMax=" + queryMax);
@ -141,7 +141,7 @@ public class TestBKD extends LuceneTestCase {
if (values[dim] > maxValue[dim]) { if (values[dim] > maxValue[dim]) {
maxValue[dim] = values[dim]; maxValue[dim] = values[dim];
} }
NumericUtils.intToBytes(values[dim], scratch, dim * Integer.BYTES); NumericUtils.intToSortableBytes(values[dim], scratch, dim * Integer.BYTES);
if (VERBOSE) { if (VERBOSE) {
System.out.println(" " + dim + " -> " + values[dim]); System.out.println(" " + dim + " -> " + values[dim]);
} }
@ -162,8 +162,8 @@ public class TestBKD extends LuceneTestCase {
byte[] minPackedValue = r.getMinPackedValue(); byte[] minPackedValue = r.getMinPackedValue();
byte[] maxPackedValue = r.getMaxPackedValue(); byte[] maxPackedValue = r.getMaxPackedValue();
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
assertEquals(minValue[dim], NumericUtils.bytesToInt(minPackedValue, dim * Integer.BYTES)); assertEquals(minValue[dim], NumericUtils.sortableBytesToInt(minPackedValue, dim * Integer.BYTES));
assertEquals(maxValue[dim], NumericUtils.bytesToInt(maxPackedValue, dim * Integer.BYTES)); assertEquals(maxValue[dim], NumericUtils.sortableBytesToInt(maxPackedValue, dim * Integer.BYTES));
} }
int iters = atLeast(100); int iters = atLeast(100);
@ -197,7 +197,7 @@ public class TestBKD extends LuceneTestCase {
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
//System.out.println("visit check docID=" + docID); //System.out.println("visit check docID=" + docID);
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
int x = NumericUtils.bytesToInt(packedValue, dim * Integer.BYTES); int x = NumericUtils.sortableBytesToInt(packedValue, dim * Integer.BYTES);
if (x < queryMin[dim] || x > queryMax[dim]) { if (x < queryMin[dim] || x > queryMax[dim]) {
//System.out.println(" no"); //System.out.println(" no");
return; return;
@ -212,8 +212,8 @@ public class TestBKD extends LuceneTestCase {
public Relation compare(byte[] minPacked, byte[] maxPacked) { public Relation compare(byte[] minPacked, byte[] maxPacked) {
boolean crosses = false; boolean crosses = false;
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
int min = NumericUtils.bytesToInt(minPacked, dim * Integer.BYTES); int min = NumericUtils.sortableBytesToInt(minPacked, dim * Integer.BYTES);
int max = NumericUtils.bytesToInt(maxPacked, dim * Integer.BYTES); int max = NumericUtils.sortableBytesToInt(maxPacked, dim * Integer.BYTES);
assert max >= min; assert max >= min;
if (max < queryMin[dim] || min > queryMax[dim]) { if (max < queryMin[dim] || min > queryMax[dim]) {
@ -269,7 +269,7 @@ public class TestBKD extends LuceneTestCase {
} }
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
values[dim] = randomBigInt(numBytesPerDim); values[dim] = randomBigInt(numBytesPerDim);
NumericUtils.bigIntToBytes(values[dim], numBytesPerDim, scratch, dim * numBytesPerDim); NumericUtils.bigIntToSortableBytes(values[dim], numBytesPerDim, scratch, dim * numBytesPerDim);
if (VERBOSE) { if (VERBOSE) {
System.out.println(" " + dim + " -> " + values[dim]); System.out.println(" " + dim + " -> " + values[dim]);
} }
@ -318,7 +318,7 @@ public class TestBKD extends LuceneTestCase {
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
//System.out.println("visit check docID=" + docID); //System.out.println("visit check docID=" + docID);
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
BigInteger x = NumericUtils.bytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim); BigInteger x = NumericUtils.sortableBytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim);
if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) { if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) {
//System.out.println(" no"); //System.out.println(" no");
return; return;
@ -333,8 +333,8 @@ public class TestBKD extends LuceneTestCase {
public Relation compare(byte[] minPacked, byte[] maxPacked) { public Relation compare(byte[] minPacked, byte[] maxPacked) {
boolean crosses = false; boolean crosses = false;
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
BigInteger min = NumericUtils.bytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim); BigInteger min = NumericUtils.sortableBytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim);
BigInteger max = NumericUtils.bytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim); BigInteger max = NumericUtils.sortableBytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim);
assert max.compareTo(min) >= 0; assert max.compareTo(min) >= 0;
if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) { if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) {
@ -533,84 +533,7 @@ public class TestBKD extends LuceneTestCase {
verify(docValuesArray, docIDsArray, numDims, numBytesPerDim); verify(docValuesArray, docIDsArray, numDims, numBytesPerDim);
} }
public void testNumericUtilsAdd() throws Exception {
int iters = atLeast(10000);
int numBytes = TestUtil.nextInt(random(), 1, 100);
for(int iter=0;iter<iters;iter++) {
BigInteger v1 = new BigInteger(8*numBytes-1, random());
BigInteger v2 = new BigInteger(8*numBytes-1, random());
byte[] v1Bytes = new byte[numBytes];
byte[] v1RawBytes = v1.toByteArray();
assert v1RawBytes.length <= numBytes;
System.arraycopy(v1RawBytes, 0, v1Bytes, v1Bytes.length-v1RawBytes.length, v1RawBytes.length);
byte[] v2Bytes = new byte[numBytes];
byte[] v2RawBytes = v2.toByteArray();
assert v1RawBytes.length <= numBytes;
System.arraycopy(v2RawBytes, 0, v2Bytes, v2Bytes.length-v2RawBytes.length, v2RawBytes.length);
byte[] result = new byte[numBytes];
NumericUtils.add(numBytes, 0, v1Bytes, v2Bytes, result);
BigInteger sum = v1.add(v2);
assertTrue("sum=" + sum + " v1=" + v1 + " v2=" + v2 + " but result=" + new BigInteger(1, result), sum.equals(new BigInteger(1, result)));
}
}
public void testIllegalNumericUtilsAdd() throws Exception {
byte[] bytes = new byte[4];
Arrays.fill(bytes, (byte) 0xff);
byte[] one = new byte[4];
one[3] = 1;
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
NumericUtils.add(4, 0, bytes, one, new byte[4]);
});
assertEquals("a + b overflows bytesPerDim=4", expected.getMessage());
}
public void testNumericUtilsSubtract() throws Exception {
int iters = atLeast(10000);
int numBytes = TestUtil.nextInt(random(), 1, 100);
for(int iter=0;iter<iters;iter++) {
BigInteger v1 = new BigInteger(8*numBytes-1, random());
BigInteger v2 = new BigInteger(8*numBytes-1, random());
if (v1.compareTo(v2) < 0) {
BigInteger tmp = v1;
v1 = v2;
v2 = tmp;
}
byte[] v1Bytes = new byte[numBytes];
byte[] v1RawBytes = v1.toByteArray();
assert v1RawBytes.length <= numBytes: "length=" + v1RawBytes.length + " vs numBytes=" + numBytes;
System.arraycopy(v1RawBytes, 0, v1Bytes, v1Bytes.length-v1RawBytes.length, v1RawBytes.length);
byte[] v2Bytes = new byte[numBytes];
byte[] v2RawBytes = v2.toByteArray();
assert v2RawBytes.length <= numBytes;
assert v2RawBytes.length <= numBytes: "length=" + v2RawBytes.length + " vs numBytes=" + numBytes;
System.arraycopy(v2RawBytes, 0, v2Bytes, v2Bytes.length-v2RawBytes.length, v2RawBytes.length);
byte[] result = new byte[numBytes];
NumericUtils.subtract(numBytes, 0, v1Bytes, v2Bytes, result);
BigInteger diff = v1.subtract(v2);
assertTrue("diff=" + diff + " vs result=" + new BigInteger(result) + " v1=" + v1 + " v2=" + v2, diff.equals(new BigInteger(result)));
}
}
public void testIllegalNumericUtilsSubtract() throws Exception {
byte[] v1 = new byte[4];
v1[3] = (byte) 0xf0;
byte[] v2 = new byte[4];
v2[3] = (byte) 0xf1;
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
NumericUtils.subtract(4, 0, v1, v2, new byte[4]);
});
assertEquals("a < b", expected.getMessage());
}
/** docIDs can be null, for the single valued case, else it maps value to docID */ /** docIDs can be null, for the single valued case, else it maps value to docID */
private void verify(byte[][][] docValues, int[] docIDs, int numDims, int numBytesPerDim) throws Exception { private void verify(byte[][][] docValues, int[] docIDs, int numDims, int numBytesPerDim) throws Exception {

View File

@ -33,6 +33,7 @@ import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.TwoPhaseIterator;
import org.apache.lucene.search.Weight; import org.apache.lucene.search.Weight;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
/** Represents a range over double values. /** Represents a range over double values.
* *
@ -83,8 +84,8 @@ public final class DoubleRange extends Range {
LongRange toLongRange() { LongRange toLongRange() {
return new LongRange(label, return new LongRange(label,
LegacyNumericUtils.doubleToSortableLong(min), true, NumericUtils.doubleToSortableLong(min), true,
LegacyNumericUtils.doubleToSortableLong(max), true); NumericUtils.doubleToSortableLong(max), true);
} }
@Override @Override

View File

@ -37,7 +37,7 @@ import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight; import org.apache.lucene.search.Weight;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.NumericUtils;
/** {@link Facets} implementation that computes counts for /** {@link Facets} implementation that computes counts for
* dynamic double ranges from a provided {@link * dynamic double ranges from a provided {@link
@ -88,8 +88,8 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
for(int i=0;i<ranges.length;i++) { for(int i=0;i<ranges.length;i++) {
DoubleRange range = ranges[i]; DoubleRange range = ranges[i];
longRanges[i] = new LongRange(range.label, longRanges[i] = new LongRange(range.label,
LegacyNumericUtils.doubleToSortableLong(range.min), true, NumericUtils.doubleToSortableLong(range.min), true,
LegacyNumericUtils.doubleToSortableLong(range.max), true); NumericUtils.doubleToSortableLong(range.max), true);
} }
LongRangeCounter counter = new LongRangeCounter(longRanges); LongRangeCounter counter = new LongRangeCounter(longRanges);
@ -130,7 +130,7 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
} }
// Skip missing docs: // Skip missing docs:
if (fv.exists(doc)) { if (fv.exists(doc)) {
counter.add(LegacyNumericUtils.doubleToSortableLong(fv.doubleVal(doc))); counter.add(NumericUtils.doubleToSortableLong(fv.doubleVal(doc)));
} else { } else {
missingCount++; missingCount++;
} }

View File

@ -26,7 +26,7 @@ import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.SortField;
import org.apache.lucene.util.BitSet; import org.apache.lucene.util.BitSet;
import org.apache.lucene.util.Bits; import org.apache.lucene.util.Bits;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.NumericUtils;
import java.io.IOException; import java.io.IOException;
@ -198,7 +198,7 @@ public class ToParentBlockJoinSortField extends SortField {
return new NumericDocValues() { return new NumericDocValues() {
@Override @Override
public long get(int docID) { public long get(int docID) {
return LegacyNumericUtils.sortableFloatBits((int) view.get(docID)); return NumericUtils.sortableFloatBits((int) view.get(docID));
} }
}; };
} }
@ -223,7 +223,7 @@ public class ToParentBlockJoinSortField extends SortField {
return new NumericDocValues() { return new NumericDocValues() {
@Override @Override
public long get(int docID) { public long get(int docID) {
return LegacyNumericUtils.sortableDoubleBits(view.get(docID)); return NumericUtils.sortableDoubleBits(view.get(docID));
} }
}; };
} }

View File

@ -173,7 +173,7 @@ public abstract class SorterTestBase extends LuceneTestCase {
doc.add(new SortedNumericDocValuesField(SORTED_NUMERIC_DV_FIELD, id + 1)); doc.add(new SortedNumericDocValuesField(SORTED_NUMERIC_DV_FIELD, id + 1));
doc.add(new Field(TERM_VECTORS_FIELD, Integer.toString(id), TERM_VECTORS_TYPE)); doc.add(new Field(TERM_VECTORS_FIELD, Integer.toString(id), TERM_VECTORS_TYPE));
byte[] bytes = new byte[4]; byte[] bytes = new byte[4];
NumericUtils.intToBytes(id, bytes, 0); NumericUtils.intToSortableBytes(id, bytes, 0);
// TODO: index time sorting doesn't yet support points // TODO: index time sorting doesn't yet support points
//doc.add(new BinaryPoint(DIMENSIONAL_FIELD, bytes)); //doc.add(new BinaryPoint(DIMENSIONAL_FIELD, bytes));
return doc; return doc;

View File

@ -142,12 +142,12 @@ public class BigIntegerPoint extends Field {
/** Encode single BigInteger dimension */ /** Encode single BigInteger dimension */
public static void encodeDimension(BigInteger value, byte dest[], int offset) { public static void encodeDimension(BigInteger value, byte dest[], int offset) {
NumericUtils.bigIntToBytes(value, BYTES, dest, offset); NumericUtils.bigIntToSortableBytes(value, BYTES, dest, offset);
} }
/** Decode single BigInteger dimension */ /** Decode single BigInteger dimension */
public static BigInteger decodeDimension(byte value[], int offset) { public static BigInteger decodeDimension(byte value[], int offset) {
return NumericUtils.bytesToBigInt(value, offset, BYTES); return NumericUtils.sortableBytesToBigInt(value, offset, BYTES);
} }
// static methods for generating queries // static methods for generating queries

View File

@ -67,8 +67,8 @@ public class LatLonPoint extends Field {
*/ */
public void setLocationValue(double latitude, double longitude) { public void setLocationValue(double latitude, double longitude) {
byte[] bytes = new byte[8]; byte[] bytes = new byte[8];
NumericUtils.intToBytes(encodeLatitude(latitude), bytes, 0); NumericUtils.intToSortableBytes(encodeLatitude(latitude), bytes, 0);
NumericUtils.intToBytes(encodeLongitude(longitude), bytes, Integer.BYTES); NumericUtils.intToSortableBytes(encodeLongitude(longitude), bytes, Integer.BYTES);
fieldsData = new BytesRef(bytes); fieldsData = new BytesRef(bytes);
} }
@ -159,7 +159,7 @@ public class LatLonPoint extends Field {
* @return decoded latitude value. * @return decoded latitude value.
*/ */
public static double decodeLatitude(byte[] src, int offset) { public static double decodeLatitude(byte[] src, int offset) {
return decodeLatitude(NumericUtils.bytesToInt(src, offset)); return decodeLatitude(NumericUtils.sortableBytesToInt(src, offset));
} }
/** /**
@ -180,16 +180,16 @@ public class LatLonPoint extends Field {
* @return decoded longitude value. * @return decoded longitude value.
*/ */
public static double decodeLongitude(byte[] src, int offset) { public static double decodeLongitude(byte[] src, int offset) {
return decodeLongitude(NumericUtils.bytesToInt(src, offset)); return decodeLongitude(NumericUtils.sortableBytesToInt(src, offset));
} }
/** sugar encodes a single point as a 2D byte array */ /** sugar encodes a single point as a 2D byte array */
private static byte[][] encode(double latitude, double longitude) { private static byte[][] encode(double latitude, double longitude) {
byte[][] bytes = new byte[2][]; byte[][] bytes = new byte[2][];
bytes[0] = new byte[4]; bytes[0] = new byte[4];
NumericUtils.intToBytes(encodeLatitude(latitude), bytes[0], 0); NumericUtils.intToSortableBytes(encodeLatitude(latitude), bytes[0], 0);
bytes[1] = new byte[4]; bytes[1] = new byte[4];
NumericUtils.intToBytes(encodeLongitude(longitude), bytes[1], 0); NumericUtils.intToSortableBytes(encodeLongitude(longitude), bytes[1], 0);
return bytes; return bytes;
} }
@ -235,7 +235,7 @@ public class LatLonPoint extends Field {
leftOpen[0] = lower[0]; leftOpen[0] = lower[0];
// leave longitude open // leave longitude open
leftOpen[1] = new byte[Integer.BYTES]; leftOpen[1] = new byte[Integer.BYTES];
NumericUtils.intToBytes(Integer.MIN_VALUE, leftOpen[1], 0); NumericUtils.intToSortableBytes(Integer.MIN_VALUE, leftOpen[1], 0);
Query left = newBoxInternal(field, leftOpen, upper); Query left = newBoxInternal(field, leftOpen, upper);
q.add(new BooleanClause(left, BooleanClause.Occur.SHOULD)); q.add(new BooleanClause(left, BooleanClause.Occur.SHOULD));
@ -243,7 +243,7 @@ public class LatLonPoint extends Field {
rightOpen[0] = upper[0]; rightOpen[0] = upper[0];
// leave longitude open // leave longitude open
rightOpen[1] = new byte[Integer.BYTES]; rightOpen[1] = new byte[Integer.BYTES];
NumericUtils.intToBytes(Integer.MAX_VALUE, rightOpen[1], 0); NumericUtils.intToSortableBytes(Integer.MAX_VALUE, rightOpen[1], 0);
Query right = newBoxInternal(field, lower, rightOpen); Query right = newBoxInternal(field, lower, rightOpen);
q.add(new BooleanClause(right, BooleanClause.Occur.SHOULD)); q.add(new BooleanClause(right, BooleanClause.Occur.SHOULD));
return new ConstantScoreQuery(q.build()); return new ConstantScoreQuery(q.build());

View File

@ -81,7 +81,7 @@ public class TestDocValuesRangeQuery extends LuceneTestCase {
return null; return null;
} else { } else {
byte[] bytes = new byte[Long.BYTES]; byte[] bytes = new byte[Long.BYTES];
NumericUtils.longToBytes(l, bytes, 0); NumericUtils.longToSortableBytes(l, bytes, 0);
return new BytesRef(bytes); return new BytesRef(bytes);
} }
} }

View File

@ -40,6 +40,7 @@ import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
import org.apache.lucene.spatial.util.DistanceToShapeValueSource; import org.apache.lucene.spatial.util.DistanceToShapeValueSource;
import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
/** /**
@ -581,7 +582,7 @@ public class BBoxStrategy extends SpatialStrategy {
private Query makeNumberTermQuery(String field, double number) { private Query makeNumberTermQuery(String field, double number) {
BytesRefBuilder bytes = new BytesRefBuilder(); BytesRefBuilder bytes = new BytesRefBuilder();
LegacyNumericUtils.longToPrefixCoded(LegacyNumericUtils.doubleToSortableLong(number), 0, bytes); LegacyNumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(number), 0, bytes);
return new TermQuery(new Term(field, bytes.get())); return new TermQuery(new Term(field, bytes.get()));
} }

View File

@ -81,12 +81,12 @@ public final class Geo3DPoint extends Field {
/** Encode single dimension */ /** Encode single dimension */
public static void encodeDimension(PlanetModel planetModel, double value, byte bytes[], int offset) { public static void encodeDimension(PlanetModel planetModel, double value, byte bytes[], int offset) {
NumericUtils.intToBytes(Geo3DUtil.encodeValue(planetModel.getMaximumMagnitude(), value), bytes, offset); NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(planetModel.getMaximumMagnitude(), value), bytes, offset);
} }
/** Decode single dimension */ /** Decode single dimension */
public static double decodeDimension(PlanetModel planetModel, byte value[], int offset) { public static double decodeDimension(PlanetModel planetModel, byte value[], int offset) {
return Geo3DUtil.decodeValueCenter(planetModel.getMaximumMagnitude(), NumericUtils.bytesToInt(value, offset)); return Geo3DUtil.decodeValueCenter(planetModel.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
} }
/** Returns a query matching all points inside the provided shape. /** Returns a query matching all points inside the provided shape.

View File

@ -117,12 +117,12 @@ class PointInGeo3DShapeQuery extends Query {
// here are inclusive, we need to extend the bounds to the largest un-quantized values that // here are inclusive, we need to extend the bounds to the largest un-quantized values that
// could quantize into these bounds. The encoding (Geo3DUtil.encodeValue) does // could quantize into these bounds. The encoding (Geo3DUtil.encodeValue) does
// a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1: // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.bytesToInt(minPackedValue, 0)); double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 0));
double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.bytesToInt(maxPackedValue, 0)); double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 0));
double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.bytesToInt(minPackedValue, 1 * Integer.BYTES)); double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.bytesToInt(maxPackedValue, 1 * Integer.BYTES)); double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.bytesToInt(minPackedValue, 2 * Integer.BYTES)); double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.bytesToInt(maxPackedValue, 2 * Integer.BYTES)); double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
//System.out.println(" compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax); //System.out.println(" compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
assert xMin <= xMax; assert xMin <= xMax;

View File

@ -69,7 +69,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
byte[] point = new byte[4]; byte[] point = new byte[4];
for(int i=0;i<20;i++) { for(int i=0;i<20;i++) {
Document doc = new Document(); Document doc = new Document();
NumericUtils.intToBytes(i, point, 0); NumericUtils.intToSortableBytes(i, point, 0);
doc.add(new BinaryPoint("dim", point)); doc.add(new BinaryPoint("dim", point));
w.addDocument(doc); w.addDocument(doc);
} }
@ -93,7 +93,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
} }
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
seen.set(docID); seen.set(docID);
assertEquals(docID, NumericUtils.bytesToInt(packedValue, 0)); assertEquals(docID, NumericUtils.sortableBytesToInt(packedValue, 0));
} }
}); });
assertEquals(20, seen.cardinality()); assertEquals(20, seen.cardinality());
@ -108,7 +108,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
byte[] point = new byte[4]; byte[] point = new byte[4];
for(int i=0;i<20;i++) { for(int i=0;i<20;i++) {
Document doc = new Document(); Document doc = new Document();
NumericUtils.intToBytes(i, point, 0); NumericUtils.intToSortableBytes(i, point, 0);
doc.add(new BinaryPoint("dim", point)); doc.add(new BinaryPoint("dim", point));
w.addDocument(doc); w.addDocument(doc);
if (i == 10) { if (i == 10) {
@ -135,7 +135,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
} }
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
seen.set(docID); seen.set(docID);
assertEquals(docID, NumericUtils.bytesToInt(packedValue, 0)); assertEquals(docID, NumericUtils.sortableBytesToInt(packedValue, 0));
} }
}); });
assertEquals(20, seen.cardinality()); assertEquals(20, seen.cardinality());
@ -149,7 +149,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
byte[] point = new byte[4]; byte[] point = new byte[4];
for(int i=0;i<10;i++) { for(int i=0;i<10;i++) {
Document doc = new Document(); Document doc = new Document();
NumericUtils.intToBytes(i, point, 0); NumericUtils.intToSortableBytes(i, point, 0);
doc.add(new BinaryPoint("dim", point)); doc.add(new BinaryPoint("dim", point));
doc.add(new NumericDocValuesField("id", i)); doc.add(new NumericDocValuesField("id", i));
doc.add(newStringField("x", "x", Field.Store.NO)); doc.add(newStringField("x", "x", Field.Store.NO));
@ -183,7 +183,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
if (liveDocs.get(docID)) { if (liveDocs.get(docID)) {
seen.set(docID); seen.set(docID);
} }
assertEquals(idValues.get(docID), NumericUtils.bytesToInt(packedValue, 0)); assertEquals(idValues.get(docID), NumericUtils.sortableBytesToInt(packedValue, 0));
} }
}); });
assertEquals(0, seen.cardinality()); assertEquals(0, seen.cardinality());
@ -349,7 +349,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
values[dim] = randomBigInt(numBytesPerDim); values[dim] = randomBigInt(numBytesPerDim);
bytes[dim] = new byte[numBytesPerDim]; bytes[dim] = new byte[numBytesPerDim];
NumericUtils.bigIntToBytes(values[dim], numBytesPerDim, bytes[dim], 0); NumericUtils.bigIntToSortableBytes(values[dim], numBytesPerDim, bytes[dim], 0);
if (VERBOSE) { if (VERBOSE) {
System.out.println(" " + dim + " -> " + values[dim]); System.out.println(" " + dim + " -> " + values[dim]);
} }
@ -405,7 +405,7 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
public void visit(int docID, byte[] packedValue) { public void visit(int docID, byte[] packedValue) {
//System.out.println("visit check docID=" + docID); //System.out.println("visit check docID=" + docID);
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
BigInteger x = NumericUtils.bytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim); BigInteger x = NumericUtils.sortableBytesToBigInt(packedValue, dim * numBytesPerDim, numBytesPerDim);
if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) { if (x.compareTo(queryMin[dim]) < 0 || x.compareTo(queryMax[dim]) > 0) {
//System.out.println(" no"); //System.out.println(" no");
return; return;
@ -420,8 +420,8 @@ public abstract class BasePointFormatTestCase extends BaseIndexFileFormatTestCas
public Relation compare(byte[] minPacked, byte[] maxPacked) { public Relation compare(byte[] minPacked, byte[] maxPacked) {
boolean crosses = false; boolean crosses = false;
for(int dim=0;dim<numDims;dim++) { for(int dim=0;dim<numDims;dim++) {
BigInteger min = NumericUtils.bytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim); BigInteger min = NumericUtils.sortableBytesToBigInt(minPacked, dim * numBytesPerDim, numBytesPerDim);
BigInteger max = NumericUtils.bytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim); BigInteger max = NumericUtils.sortableBytesToBigInt(maxPacked, dim * numBytesPerDim, numBytesPerDim);
assert max.compareTo(min) >= 0; assert max.compareTo(min) >= 0;
if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) { if (max.compareTo(queryMin[dim]) < 0 || min.compareTo(queryMax[dim]) > 0) {

View File

@ -448,6 +448,16 @@ public final class TestUtil {
return result; return result;
} }
} }
/**
* Returns a randomish big integer with {@code 1 .. maxBytes} storage.
*/
public static BigInteger nextBigInteger(Random random, int maxBytes) {
int length = TestUtil.nextInt(random, 1, maxBytes);
byte[] buffer = new byte[length];
random.nextBytes(buffer);
return new BigInteger(buffer);
}
public static String randomSimpleString(Random r, int maxLength) { public static String randomSimpleString(Random r, int maxLength) {
return randomSimpleString(r, 0, maxLength); return randomSimpleString(r, 0, maxLength);

View File

@ -22,6 +22,7 @@ import java.util.Date;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
import org.apache.solr.schema.FieldType; import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.TrieDateField; import org.apache.solr.schema.TrieDateField;
import org.apache.solr.schema.TrieDoubleField; import org.apache.solr.schema.TrieDoubleField;
@ -113,14 +114,14 @@ public class AnalyticsParsers {
public static final NumericParser FLOAT_DOC_VALUES_PARSER = new NumericParser() { public static final NumericParser FLOAT_DOC_VALUES_PARSER = new NumericParser() {
public String parse(BytesRef bytes) throws IOException { public String parse(BytesRef bytes) throws IOException {
try { try {
return ""+ LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes)); return ""+ NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a float."); throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a float.");
} }
} }
@Override @Override
public String parseNum(long l) { public String parseNum(long l) {
return ""+ LegacyNumericUtils.sortableIntToFloat((int) l); return ""+ NumericUtils.sortableIntToFloat((int) l);
} }
}; };
@ -130,14 +131,14 @@ public class AnalyticsParsers {
public static final NumericParser DOUBLE_DOC_VALUES_PARSER = new NumericParser() { public static final NumericParser DOUBLE_DOC_VALUES_PARSER = new NumericParser() {
public String parse(BytesRef bytes) throws IOException { public String parse(BytesRef bytes) throws IOException {
try { try {
return ""+ LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes)); return ""+ NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a double."); throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a double.");
} }
} }
@Override @Override
public String parseNum(long l) { public String parseNum(long l) {
return ""+ LegacyNumericUtils.sortableLongToDouble(l); return ""+ NumericUtils.sortableLongToDouble(l);
} }
}; };

View File

@ -35,7 +35,7 @@ import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.util.Bits; import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.NumericUtils;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SolrParams;
@ -554,10 +554,10 @@ public class IntervalFacets implements Iterable<FacetInterval> {
startLimit = ((Integer) schemaField.getType().toObject(schemaField, start)).longValue(); startLimit = ((Integer) schemaField.getType().toObject(schemaField, start)).longValue();
break; break;
case FLOAT: case FLOAT:
startLimit = LegacyNumericUtils.floatToSortableInt((float) schemaField.getType().toObject(schemaField, start)); startLimit = NumericUtils.floatToSortableInt((float) schemaField.getType().toObject(schemaField, start));
break; break;
case DOUBLE: case DOUBLE:
startLimit = LegacyNumericUtils.doubleToSortableLong((double) schemaField.getType().toObject(schemaField, start)); startLimit = NumericUtils.doubleToSortableLong((double) schemaField.getType().toObject(schemaField, start));
break; break;
default: default:
throw new AssertionError(); throw new AssertionError();
@ -583,10 +583,10 @@ public class IntervalFacets implements Iterable<FacetInterval> {
endLimit = ((Integer) schemaField.getType().toObject(schemaField, end)).longValue(); endLimit = ((Integer) schemaField.getType().toObject(schemaField, end)).longValue();
break; break;
case FLOAT: case FLOAT:
endLimit = LegacyNumericUtils.floatToSortableInt((float) schemaField.getType().toObject(schemaField, end)); endLimit = NumericUtils.floatToSortableInt((float) schemaField.getType().toObject(schemaField, end));
break; break;
case DOUBLE: case DOUBLE:
endLimit = LegacyNumericUtils.doubleToSortableLong((double) schemaField.getType().toObject(schemaField, end)); endLimit = NumericUtils.doubleToSortableLong((double) schemaField.getType().toObject(schemaField, end));
break; break;
default: default:
throw new AssertionError(); throw new AssertionError();
@ -753,8 +753,8 @@ public class IntervalFacets implements Iterable<FacetInterval> {
* <li>{@link IntervalCompareResult#GREATER_THAN_END} if the value is greater than {@code endLimit} * <li>{@link IntervalCompareResult#GREATER_THAN_END} if the value is greater than {@code endLimit}
* <li>{@link IntervalCompareResult#LOWER_THAN_START} if the value is lower than {@code startLimit} * <li>{@link IntervalCompareResult#LOWER_THAN_START} if the value is lower than {@code startLimit}
* </ul> * </ul>
* @see org.apache.lucene.util.LegacyNumericUtils#floatToSortableInt(float) * @see org.apache.lucene.util.NumericUtils#floatToSortableInt(float)
* @see org.apache.lucene.util.LegacyNumericUtils#doubleToSortableLong(double) * @see org.apache.lucene.util.NumericUtils#doubleToSortableLong(double)
*/ */
public IntervalCompareResult includes(long value) { public IntervalCompareResult includes(long value) {
if (startLimit > value) { if (startLimit > value) {

View File

@ -30,6 +30,7 @@ import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
import org.apache.lucene.search.SortedSetSelector; import org.apache.lucene.search.SortedSetSelector;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.mutable.MutableValue; import org.apache.lucene.util.mutable.MutableValue;
import org.apache.lucene.util.mutable.MutableValueDouble; import org.apache.lucene.util.mutable.MutableValueDouble;
@ -82,7 +83,7 @@ public class TrieDoubleField extends TrieField implements DoubleValueFieldType {
assert !exists(doc) : "zero bytes for doc, but exists is true"; assert !exists(doc) : "zero bytes for doc, but exists is true";
return 0D; return 0D;
} }
return LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes)); return NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes));
} }
@Override @Override
@ -107,7 +108,7 @@ public class TrieDoubleField extends TrieField implements DoubleValueFieldType {
//mval.value = mval.exists ? doubleVal(doc) : 0.0D; //mval.value = mval.exists ? doubleVal(doc) : 0.0D;
BytesRef bytes = view.get(doc); BytesRef bytes = view.get(doc);
mval.exists = (0 == bytes.length); mval.exists = (0 == bytes.length);
mval.value = mval.exists ? LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes)) : 0D; mval.value = mval.exists ? NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes)) : 0D;
} }
}; };
} }

View File

@ -51,6 +51,7 @@ import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.CharsRef; import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.CharsRefBuilder; import org.apache.lucene.util.CharsRefBuilder;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.mutable.MutableValueDate; import org.apache.lucene.util.mutable.MutableValueDate;
import org.apache.lucene.util.mutable.MutableValueLong; import org.apache.lucene.util.mutable.MutableValueLong;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
@ -351,8 +352,8 @@ public class TrieField extends PrimitiveFieldType {
case FLOAT: case FLOAT:
if (matchOnly) { if (matchOnly) {
query = DocValuesRangeQuery.newLongRange(field.getName(), query = DocValuesRangeQuery.newLongRange(field.getName(),
min == null ? null : (long) LegacyNumericUtils.floatToSortableInt(Float.parseFloat(min)), min == null ? null : (long) NumericUtils.floatToSortableInt(Float.parseFloat(min)),
max == null ? null : (long) LegacyNumericUtils.floatToSortableInt(Float.parseFloat(max)), max == null ? null : (long) NumericUtils.floatToSortableInt(Float.parseFloat(max)),
minInclusive, maxInclusive); minInclusive, maxInclusive);
} else { } else {
query = LegacyNumericRangeQuery.newFloatRange(field.getName(), ps, query = LegacyNumericRangeQuery.newFloatRange(field.getName(), ps,
@ -377,8 +378,8 @@ public class TrieField extends PrimitiveFieldType {
case DOUBLE: case DOUBLE:
if (matchOnly) { if (matchOnly) {
query = DocValuesRangeQuery.newLongRange(field.getName(), query = DocValuesRangeQuery.newLongRange(field.getName(),
min == null ? null : LegacyNumericUtils.doubleToSortableLong(Double.parseDouble(min)), min == null ? null : NumericUtils.doubleToSortableLong(Double.parseDouble(min)),
max == null ? null : LegacyNumericUtils.doubleToSortableLong(Double.parseDouble(max)), max == null ? null : NumericUtils.doubleToSortableLong(Double.parseDouble(max)),
minInclusive, maxInclusive); minInclusive, maxInclusive);
} else { } else {
query = LegacyNumericRangeQuery.newDoubleRange(field.getName(), ps, query = LegacyNumericRangeQuery.newDoubleRange(field.getName(), ps,
@ -439,13 +440,13 @@ public class TrieField extends PrimitiveFieldType {
LegacyNumericUtils.intToPrefixCoded(Integer.parseInt(s), 0, result); LegacyNumericUtils.intToPrefixCoded(Integer.parseInt(s), 0, result);
break; break;
case FLOAT: case FLOAT:
LegacyNumericUtils.intToPrefixCoded(LegacyNumericUtils.floatToSortableInt(Float.parseFloat(s)), 0, result); LegacyNumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(Float.parseFloat(s)), 0, result);
break; break;
case LONG: case LONG:
LegacyNumericUtils.longToPrefixCoded(Long.parseLong(s), 0, result); LegacyNumericUtils.longToPrefixCoded(Long.parseLong(s), 0, result);
break; break;
case DOUBLE: case DOUBLE:
LegacyNumericUtils.longToPrefixCoded(LegacyNumericUtils.doubleToSortableLong(Double.parseDouble(s)), 0, result); LegacyNumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(Double.parseDouble(s)), 0, result);
break; break;
case DATE: case DATE:
LegacyNumericUtils.longToPrefixCoded(DateFormatUtil.parseMath(null, s).getTime(), 0, result); LegacyNumericUtils.longToPrefixCoded(DateFormatUtil.parseMath(null, s).getTime(), 0, result);
@ -483,11 +484,11 @@ public class TrieField extends PrimitiveFieldType {
case INTEGER: case INTEGER:
return Integer.toString( LegacyNumericUtils.prefixCodedToInt(indexedForm) ); return Integer.toString( LegacyNumericUtils.prefixCodedToInt(indexedForm) );
case FLOAT: case FLOAT:
return Float.toString( LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(indexedForm)) ); return Float.toString( NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(indexedForm)) );
case LONG: case LONG:
return Long.toString( LegacyNumericUtils.prefixCodedToLong(indexedForm) ); return Long.toString( LegacyNumericUtils.prefixCodedToLong(indexedForm) );
case DOUBLE: case DOUBLE:
return Double.toString( LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(indexedForm)) ); return Double.toString( NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(indexedForm)) );
case DATE: case DATE:
return DateFormatUtil.formatExternal(new Date(LegacyNumericUtils.prefixCodedToLong(indexedForm))); return DateFormatUtil.formatExternal(new Date(LegacyNumericUtils.prefixCodedToLong(indexedForm)));
default: default:
@ -503,13 +504,13 @@ public class TrieField extends PrimitiveFieldType {
value = Integer.toString( LegacyNumericUtils.prefixCodedToInt(indexedForm) ); value = Integer.toString( LegacyNumericUtils.prefixCodedToInt(indexedForm) );
break; break;
case FLOAT: case FLOAT:
value = Float.toString( LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(indexedForm)) ); value = Float.toString( NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(indexedForm)) );
break; break;
case LONG: case LONG:
value = Long.toString( LegacyNumericUtils.prefixCodedToLong(indexedForm) ); value = Long.toString( LegacyNumericUtils.prefixCodedToLong(indexedForm) );
break; break;
case DOUBLE: case DOUBLE:
value = Double.toString( LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(indexedForm)) ); value = Double.toString( NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(indexedForm)) );
break; break;
case DATE: case DATE:
value = DateFormatUtil.formatExternal(new Date(LegacyNumericUtils.prefixCodedToLong(indexedForm))); value = DateFormatUtil.formatExternal(new Date(LegacyNumericUtils.prefixCodedToLong(indexedForm)));
@ -529,11 +530,11 @@ public class TrieField extends PrimitiveFieldType {
case INTEGER: case INTEGER:
return LegacyNumericUtils.prefixCodedToInt(term); return LegacyNumericUtils.prefixCodedToInt(term);
case FLOAT: case FLOAT:
return LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(term)); return NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(term));
case LONG: case LONG:
return LegacyNumericUtils.prefixCodedToLong(term); return LegacyNumericUtils.prefixCodedToLong(term);
case DOUBLE: case DOUBLE:
return LegacyNumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(term)); return NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(term));
case DATE: case DATE:
return new Date(LegacyNumericUtils.prefixCodedToLong(term)); return new Date(LegacyNumericUtils.prefixCodedToLong(term));
default: default:
@ -556,14 +557,14 @@ public class TrieField extends PrimitiveFieldType {
LegacyNumericUtils.intToPrefixCoded(val.intValue(), 0, bytes); LegacyNumericUtils.intToPrefixCoded(val.intValue(), 0, bytes);
break; break;
case FLOAT: case FLOAT:
LegacyNumericUtils.intToPrefixCoded(LegacyNumericUtils.floatToSortableInt(val.floatValue()), 0, bytes); LegacyNumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(val.floatValue()), 0, bytes);
break; break;
case LONG: //fallthrough! case LONG: //fallthrough!
case DATE: case DATE:
LegacyNumericUtils.longToPrefixCoded(val.longValue(), 0, bytes); LegacyNumericUtils.longToPrefixCoded(val.longValue(), 0, bytes);
break; break;
case DOUBLE: case DOUBLE:
LegacyNumericUtils.longToPrefixCoded(LegacyNumericUtils.doubleToSortableLong(val.doubleValue()), 0, bytes); LegacyNumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(val.doubleValue()), 0, bytes);
break; break;
default: default:
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name()); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + f.name());

View File

@ -30,6 +30,7 @@ import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
import org.apache.lucene.search.SortedSetSelector; import org.apache.lucene.search.SortedSetSelector;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.mutable.MutableValue; import org.apache.lucene.util.mutable.MutableValue;
import org.apache.lucene.util.mutable.MutableValueFloat; import org.apache.lucene.util.mutable.MutableValueFloat;
@ -82,7 +83,7 @@ public class TrieFloatField extends TrieField implements FloatValueFieldType {
assert !exists(doc) : "zero bytes for doc, but exists is true"; assert !exists(doc) : "zero bytes for doc, but exists is true";
return 0F; return 0F;
} }
return LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes)); return NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes));
} }
@Override @Override
@ -108,7 +109,7 @@ public class TrieFloatField extends TrieField implements FloatValueFieldType {
// //
BytesRef bytes = view.get(doc); BytesRef bytes = view.get(doc);
mval.exists = (0 == bytes.length); mval.exists = (0 == bytes.length);
mval.value = mval.exists ? LegacyNumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes)) : 0F; mval.value = mval.exists ? NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes)) : 0F;
} }
}; };
} }

View File

@ -25,7 +25,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.NumericUtils;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.FacetParams; import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.SimpleOrderedMap;
@ -470,7 +470,7 @@ class FacetRangeProcessor extends FacetProcessor<FacetRange> {
@Override @Override
public long bitsToSortableBits(long bits) { public long bitsToSortableBits(long bits) {
return LegacyNumericUtils.sortableDoubleBits(bits); return NumericUtils.sortableDoubleBits(bits);
} }
public FloatCalc(final SchemaField f) { super(f); } public FloatCalc(final SchemaField f) { super(f); }
@ -491,7 +491,7 @@ class FacetRangeProcessor extends FacetProcessor<FacetRange> {
@Override @Override
public long bitsToSortableBits(long bits) { public long bitsToSortableBits(long bits) {
return LegacyNumericUtils.sortableDoubleBits(bits); return NumericUtils.sortableDoubleBits(bits);
} }
public DoubleCalc(final SchemaField f) { super(f); } public DoubleCalc(final SchemaField f) { super(f); }