You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cp...@apache.org on 2017/05/30 11:28:28 UTC
[19/25] lucene-solr:jira/solr-8668: LUCENE-7850: Move support for
legacy numerics to solr/.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/TrieLongField.java b/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
index a93d0ce..56b964f 100644
--- a/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
+++ b/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
@@ -23,7 +23,7 @@ import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedSetDocValues;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.docvalues.LongDocValues;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/search/LegacyNumericRangeQueryBuilder.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/LegacyNumericRangeQueryBuilder.java b/solr/core/src/java/org/apache/solr/search/LegacyNumericRangeQueryBuilder.java
index a2d0ed6..931634f 100644
--- a/solr/core/src/java/org/apache/solr/search/LegacyNumericRangeQueryBuilder.java
+++ b/solr/core/src/java/org/apache/solr/search/LegacyNumericRangeQueryBuilder.java
@@ -17,8 +17,8 @@
package org.apache.solr.search;
import org.apache.lucene.search.Query;
-import org.apache.lucene.legacy.LegacyNumericRangeQuery;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericRangeQuery;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.queryparser.xml.DOMUtils;
import org.apache.lucene.queryparser.xml.ParserException;
import org.apache.lucene.queryparser.xml.QueryBuilder;
@@ -26,10 +26,10 @@ import org.apache.lucene.queryparser.xml.builders.PointRangeQueryBuilder;
import org.w3c.dom.Element;
/**
- * Creates a {@link org.apache.lucene.legacy.LegacyNumericRangeQuery}. The table below specifies the required
+ * Creates a {@link org.apache.solr.legacy.LegacyNumericRangeQuery}. The table below specifies the required
* attributes and the defaults if optional attributes are omitted. For more
* detail on what each of the attributes actually do, consult the documentation
- * for {@link org.apache.lucene.legacy.LegacyNumericRangeQuery}:
+ * for {@link org.apache.solr.legacy.LegacyNumericRangeQuery}:
* <table summary="supported attributes">
* <tr>
* <th>Attribute name</th>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/search/QueryParsing.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QueryParsing.java b/solr/core/src/java/org/apache/solr/search/QueryParsing.java
index 381276c..bbce610 100644
--- a/solr/core/src/java/org/apache/solr/search/QueryParsing.java
+++ b/solr/core/src/java/org/apache/solr/search/QueryParsing.java
@@ -17,7 +17,7 @@
package org.apache.solr.search;
import org.apache.lucene.index.Term;
-import org.apache.lucene.legacy.LegacyNumericRangeQuery;
+import org.apache.solr.legacy.LegacyNumericRangeQuery;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java b/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java
index d526cf3..fa6e87c 100644
--- a/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java
+++ b/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java
@@ -34,7 +34,7 @@ import org.apache.lucene.util.Bits;
* Constrains search results to only match those which also match a provided
* query.
*
- * <p> This could be used, for example, with a {@link org.apache.lucene.legacy.LegacyNumericRangeQuery} on a suitably
+ * <p> This could be used, for example, with a {@link org.apache.solr.legacy.LegacyNumericRangeQuery} on a suitably
* formatted date field to implement date filtering. One could re-use a single
* CachingWrapperFilter(QueryWrapperFilter) that matches, e.g., only documents modified
* within the last week. This would only need to be reconstructed once per day.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/search/mlt/CloudMLTQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/mlt/CloudMLTQParser.java b/solr/core/src/java/org/apache/solr/search/mlt/CloudMLTQParser.java
index 3ff432d..17b7d3b 100644
--- a/solr/core/src/java/org/apache/solr/search/mlt/CloudMLTQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/mlt/CloudMLTQParser.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.queries.mlt.MoreLikeThis;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/search/mlt/SimpleMLTQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/mlt/SimpleMLTQParser.java b/solr/core/src/java/org/apache/solr/search/mlt/SimpleMLTQParser.java
index dea161d..cc87e09 100644
--- a/solr/core/src/java/org/apache/solr/search/mlt/SimpleMLTQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/mlt/SimpleMLTQParser.java
@@ -16,7 +16,7 @@
*/
package org.apache.solr.search.mlt;
import org.apache.lucene.index.Term;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.queries.mlt.MoreLikeThis;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/uninverting/FieldCache.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/uninverting/FieldCache.java b/solr/core/src/java/org/apache/solr/uninverting/FieldCache.java
index 89e6f0b..87f5f4c 100644
--- a/solr/core/src/java/org/apache/solr/uninverting/FieldCache.java
+++ b/solr/core/src/java/org/apache/solr/uninverting/FieldCache.java
@@ -27,7 +27,7 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.util.Accountable;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
@@ -159,8 +159,8 @@ public interface FieldCache {
};
/**
- * A parser instance for int values encoded by {@link org.apache.lucene.legacy.LegacyNumericUtils}, e.g. when indexed
- * via {@link org.apache.lucene.legacy.LegacyIntField}/{@link org.apache.lucene.legacy.LegacyNumericTokenStream}.
+ * A parser instance for int values encoded by {@link org.apache.solr.legacy.LegacyNumericUtils}, e.g. when indexed
+ * via {@link org.apache.solr.legacy.LegacyIntField}/{@link org.apache.solr.legacy.LegacyNumericTokenStream}.
* @deprecated Index with points and use {@link #INT_POINT_PARSER} instead.
*/
@Deprecated
@@ -182,8 +182,8 @@ public interface FieldCache {
};
/**
- * A parser instance for float values encoded with {@link org.apache.lucene.legacy.LegacyNumericUtils}, e.g. when indexed
- * via {@link org.apache.lucene.legacy.LegacyFloatField}/{@link org.apache.lucene.legacy.LegacyNumericTokenStream}.
+ * A parser instance for float values encoded with {@link org.apache.solr.legacy.LegacyNumericUtils}, e.g. when indexed
+ * via {@link org.apache.solr.legacy.LegacyFloatField}/{@link org.apache.solr.legacy.LegacyNumericTokenStream}.
* @deprecated Index with points and use {@link #FLOAT_POINT_PARSER} instead.
*/
@Deprecated
@@ -207,8 +207,8 @@ public interface FieldCache {
};
/**
- * A parser instance for long values encoded by {@link org.apache.lucene.legacy.LegacyNumericUtils}, e.g. when indexed
- * via {@link org.apache.lucene.legacy.LegacyLongField}/{@link org.apache.lucene.legacy.LegacyNumericTokenStream}.
+ * A parser instance for long values encoded by {@link org.apache.solr.legacy.LegacyNumericUtils}, e.g. when indexed
+ * via {@link org.apache.solr.legacy.LegacyLongField}/{@link org.apache.solr.legacy.LegacyNumericTokenStream}.
* @deprecated Index with points and use {@link #LONG_POINT_PARSER} instead.
*/
@Deprecated
@@ -229,8 +229,8 @@ public interface FieldCache {
};
/**
- * A parser instance for double values encoded with {@link org.apache.lucene.legacy.LegacyNumericUtils}, e.g. when indexed
- * via {@link org.apache.lucene.legacy.LegacyDoubleField}/{@link org.apache.lucene.legacy.LegacyNumericTokenStream}.
+ * A parser instance for double values encoded with {@link org.apache.solr.legacy.LegacyNumericUtils}, e.g. when indexed
+ * via {@link org.apache.solr.legacy.LegacyDoubleField}/{@link org.apache.solr.legacy.LegacyNumericTokenStream}.
* @deprecated Index with points and use {@link #DOUBLE_POINT_PARSER} instead.
*/
@Deprecated
@@ -277,7 +277,7 @@ public interface FieldCache {
* @param parser
* Computes long for string values. May be {@code null} if the
* requested field was indexed as {@link NumericDocValuesField} or
- * {@link org.apache.lucene.legacy.LegacyLongField}.
+ * {@link org.apache.solr.legacy.LegacyLongField}.
* @return The values in the given field for each document.
* @throws IOException
* If any error occurs.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/uninverting/UninvertingReader.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/uninverting/UninvertingReader.java b/solr/core/src/java/org/apache/solr/uninverting/UninvertingReader.java
index 7006b4a..7158e31 100644
--- a/solr/core/src/java/org/apache/solr/uninverting/UninvertingReader.java
+++ b/solr/core/src/java/org/apache/solr/uninverting/UninvertingReader.java
@@ -87,7 +87,7 @@ public class UninvertingReader extends FilterLeafReader {
*/
DOUBLE_POINT,
/**
- * Single-valued Integer, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyIntField})
+ * Single-valued Integer, (e.g. indexed with {@link org.apache.solr.legacy.LegacyIntField})
* <p>
* Fields with this type act as if they were indexed with
* {@link NumericDocValuesField}.
@@ -96,7 +96,7 @@ public class UninvertingReader extends FilterLeafReader {
@Deprecated
LEGACY_INTEGER,
/**
- * Single-valued Long, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyLongField})
+ * Single-valued Long, (e.g. indexed with {@link org.apache.solr.legacy.LegacyLongField})
* <p>
* Fields with this type act as if they were indexed with
* {@link NumericDocValuesField}.
@@ -105,7 +105,7 @@ public class UninvertingReader extends FilterLeafReader {
@Deprecated
LEGACY_LONG,
/**
- * Single-valued Float, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyFloatField})
+ * Single-valued Float, (e.g. indexed with {@link org.apache.solr.legacy.LegacyFloatField})
* <p>
* Fields with this type act as if they were indexed with
* {@link NumericDocValuesField}.
@@ -114,7 +114,7 @@ public class UninvertingReader extends FilterLeafReader {
@Deprecated
LEGACY_FLOAT,
/**
- * Single-valued Double, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyDoubleField})
+ * Single-valued Double, (e.g. indexed with {@link org.apache.solr.legacy.LegacyDoubleField})
* <p>
* Fields with this type act as if they were indexed with
* {@link NumericDocValuesField}.
@@ -144,28 +144,28 @@ public class UninvertingReader extends FilterLeafReader {
*/
SORTED_SET_BINARY,
/**
- * Multi-valued Integer, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyIntField})
+ * Multi-valued Integer, (e.g. indexed with {@link org.apache.solr.legacy.LegacyIntField})
* <p>
* Fields with this type act as if they were indexed with
* {@link SortedSetDocValuesField}.
*/
SORTED_SET_INTEGER,
/**
- * Multi-valued Float, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyFloatField})
+ * Multi-valued Float, (e.g. indexed with {@link org.apache.solr.legacy.LegacyFloatField})
* <p>
* Fields with this type act as if they were indexed with
* {@link SortedSetDocValuesField}.
*/
SORTED_SET_FLOAT,
/**
- * Multi-valued Long, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyLongField})
+ * Multi-valued Long, (e.g. indexed with {@link org.apache.solr.legacy.LegacyLongField})
* <p>
* Fields with this type act as if they were indexed with
* {@link SortedSetDocValuesField}.
*/
SORTED_SET_LONG,
/**
- * Multi-valued Double, (e.g. indexed with {@link org.apache.lucene.legacy.LegacyDoubleField})
+ * Multi-valued Double, (e.g. indexed with {@link org.apache.solr.legacy.LegacyDoubleField})
* <p>
* Fields with this type act as if they were indexed with
* {@link SortedSetDocValuesField}.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/java/org/apache/solr/update/VersionInfo.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/VersionInfo.java b/solr/core/src/java/org/apache/solr/update/VersionInfo.java
index 061e7f6..67b4042 100644
--- a/solr/core/src/java/org/apache/solr/update/VersionInfo.java
+++ b/solr/core/src/java/org/apache/solr/update/VersionInfo.java
@@ -25,7 +25,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Terms;
-import org.apache.lucene.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericUtils;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.IndexSearcher;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestLegacyField.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestLegacyField.java b/solr/core/src/test/org/apache/solr/legacy/TestLegacyField.java
new file mode 100644
index 0000000..5cfac9a
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestLegacyField.java
@@ -0,0 +1,186 @@
+/*
+ * 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.solr.legacy;
+
+import java.io.StringReader;
+
+import org.apache.lucene.analysis.CannedTokenStream;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestLegacyField extends LuceneTestCase {
+
+ public void testLegacyDoubleField() throws Exception {
+ Field fields[] = new Field[] {
+ new LegacyDoubleField("foo", 5d, Field.Store.NO),
+ new LegacyDoubleField("foo", 5d, Field.Store.YES)
+ };
+
+ for (Field field : fields) {
+ trySetByteValue(field);
+ trySetBytesValue(field);
+ trySetBytesRefValue(field);
+ field.setDoubleValue(6d); // ok
+ trySetIntValue(field);
+ trySetFloatValue(field);
+ trySetLongValue(field);
+ trySetReaderValue(field);
+ trySetShortValue(field);
+ trySetStringValue(field);
+ trySetTokenStreamValue(field);
+
+ assertEquals(6d, field.numericValue().doubleValue(), 0.0d);
+ }
+ }
+
+ public void testLegacyFloatField() throws Exception {
+ Field fields[] = new Field[] {
+ new LegacyFloatField("foo", 5f, Field.Store.NO),
+ new LegacyFloatField("foo", 5f, Field.Store.YES)
+ };
+
+ for (Field field : fields) {
+ trySetByteValue(field);
+ trySetBytesValue(field);
+ trySetBytesRefValue(field);
+ trySetDoubleValue(field);
+ trySetIntValue(field);
+ field.setFloatValue(6f); // ok
+ trySetLongValue(field);
+ trySetReaderValue(field);
+ trySetShortValue(field);
+ trySetStringValue(field);
+ trySetTokenStreamValue(field);
+
+ assertEquals(6f, field.numericValue().floatValue(), 0.0f);
+ }
+ }
+
+ public void testLegacyIntField() throws Exception {
+ Field fields[] = new Field[] {
+ new LegacyIntField("foo", 5, Field.Store.NO),
+ new LegacyIntField("foo", 5, Field.Store.YES)
+ };
+
+ for (Field field : fields) {
+ trySetByteValue(field);
+ trySetBytesValue(field);
+ trySetBytesRefValue(field);
+ trySetDoubleValue(field);
+ field.setIntValue(6); // ok
+ trySetFloatValue(field);
+ trySetLongValue(field);
+ trySetReaderValue(field);
+ trySetShortValue(field);
+ trySetStringValue(field);
+ trySetTokenStreamValue(field);
+
+ assertEquals(6, field.numericValue().intValue());
+ }
+ }
+
+ public void testLegacyLongField() throws Exception {
+ Field fields[] = new Field[] {
+ new LegacyLongField("foo", 5L, Field.Store.NO),
+ new LegacyLongField("foo", 5L, Field.Store.YES)
+ };
+
+ for (Field field : fields) {
+ trySetByteValue(field);
+ trySetBytesValue(field);
+ trySetBytesRefValue(field);
+ trySetDoubleValue(field);
+ trySetIntValue(field);
+ trySetFloatValue(field);
+ field.setLongValue(6); // ok
+ trySetReaderValue(field);
+ trySetShortValue(field);
+ trySetStringValue(field);
+ trySetTokenStreamValue(field);
+
+ assertEquals(6L, field.numericValue().longValue());
+ }
+ }
+
+ private void trySetByteValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setByteValue((byte) 10);
+ });
+ }
+
+ private void trySetBytesValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setBytesValue(new byte[] { 5, 5 });
+ });
+ }
+
+ private void trySetBytesRefValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setBytesValue(new BytesRef("bogus"));
+ });
+ }
+
+ private void trySetDoubleValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setDoubleValue(Double.MAX_VALUE);
+ });
+ }
+
+ private void trySetIntValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setIntValue(Integer.MAX_VALUE);
+ });
+ }
+
+ private void trySetLongValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setLongValue(Long.MAX_VALUE);
+ });
+ }
+
+ private void trySetFloatValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setFloatValue(Float.MAX_VALUE);
+ });
+ }
+
+ private void trySetReaderValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setReaderValue(new StringReader("BOO!"));
+ });
+ }
+
+ private void trySetShortValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setShortValue(Short.MAX_VALUE);
+ });
+ }
+
+ private void trySetStringValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setStringValue("BOO!");
+ });
+ }
+
+ private void trySetTokenStreamValue(Field f) {
+ expectThrows(IllegalArgumentException.class, () -> {
+ f.setTokenStream(new CannedTokenStream(new Token("foo", 0, 3)));
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestLegacyFieldReuse.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestLegacyFieldReuse.java b/solr/core/src/test/org/apache/solr/legacy/TestLegacyFieldReuse.java
new file mode 100644
index 0000000..39d8d01
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestLegacyFieldReuse.java
@@ -0,0 +1,81 @@
+/*
+ * 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.solr.legacy;
+
+
+import java.io.IOException;
+
+import org.apache.lucene.analysis.BaseTokenStreamTestCase;
+import org.apache.lucene.analysis.CannedTokenStream;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.document.Field;
+import org.apache.solr.legacy.LegacyIntField;
+import org.apache.solr.legacy.LegacyNumericTokenStream;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.solr.legacy.LegacyNumericTokenStream.LegacyNumericTermAttribute;
+
+/** test tokenstream reuse by DefaultIndexingChain */
+public class TestLegacyFieldReuse extends BaseTokenStreamTestCase {
+
+ public void testNumericReuse() throws IOException {
+ LegacyIntField legacyIntField = new LegacyIntField("foo", 5, Field.Store.NO);
+
+ // passing null
+ TokenStream ts = legacyIntField.tokenStream(null, null);
+ assertTrue(ts instanceof LegacyNumericTokenStream);
+ assertEquals(LegacyNumericUtils.PRECISION_STEP_DEFAULT_32, ((LegacyNumericTokenStream)ts).getPrecisionStep());
+ assertNumericContents(5, ts);
+
+ // now reuse previous stream
+ legacyIntField = new LegacyIntField("foo", 20, Field.Store.NO);
+ TokenStream ts2 = legacyIntField.tokenStream(null, ts);
+ assertSame(ts, ts2);
+ assertNumericContents(20, ts);
+
+ // pass a bogus stream and ensure it's still ok
+ legacyIntField = new LegacyIntField("foo", 2343, Field.Store.NO);
+ TokenStream bogus = new CannedTokenStream(new Token("bogus", 0, 5));
+ ts = legacyIntField.tokenStream(null, bogus);
+ assertNotSame(bogus, ts);
+ assertNumericContents(2343, ts);
+
+ // pass another bogus stream (numeric, but different precision step!)
+ legacyIntField = new LegacyIntField("foo", 42, Field.Store.NO);
+ assert 3 != LegacyNumericUtils.PRECISION_STEP_DEFAULT;
+ bogus = new LegacyNumericTokenStream(3);
+ ts = legacyIntField.tokenStream(null, bogus);
+ assertNotSame(bogus, ts);
+ assertNumericContents(42, ts);
+ }
+
+ private void assertNumericContents(int value, TokenStream ts) throws IOException {
+ assertTrue(ts instanceof LegacyNumericTokenStream);
+ LegacyNumericTermAttribute numericAtt = ts.getAttribute(LegacyNumericTermAttribute.class);
+ ts.reset();
+ boolean seen = false;
+ while (ts.incrementToken()) {
+ if (numericAtt.getShift() == 0) {
+ assertEquals(value, numericAtt.getRawValue());
+ seen = true;
+ }
+ }
+ ts.end();
+ ts.close();
+ assertTrue(seen);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java b/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
new file mode 100644
index 0000000..a87e28a
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
@@ -0,0 +1,571 @@
+/*
+ * 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.solr.legacy;
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Random;
+
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.lucene.util.BytesRefBuilder;
+import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.LongBitSet;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.NumericUtils;
+
+public class TestLegacyNumericUtils extends LuceneTestCase {
+
+ public void testLongConversionAndOrdering() throws Exception {
+ // generate a series of encoded longs, each numerical one bigger than the one before
+ BytesRefBuilder last = new BytesRefBuilder();
+ BytesRefBuilder act = new BytesRefBuilder();
+ for (long l=-100000L; l<100000L; l++) {
+ LegacyNumericUtils.longToPrefixCoded(l, 0, act);
+ if (last!=null) {
+ // test if smaller
+ assertTrue("actual bigger than last (BytesRef)", last.get().compareTo(act.get()) < 0 );
+ assertTrue("actual bigger than last (as String)", last.get().utf8ToString().compareTo(act.get().utf8ToString()) < 0 );
+ }
+ // test is back and forward conversion works
+ assertEquals("forward and back conversion should generate same long", l, LegacyNumericUtils.prefixCodedToLong(act.get()));
+ // next step
+ last.copyBytes(act);
+ }
+ }
+
+ public void testIntConversionAndOrdering() throws Exception {
+ // generate a series of encoded ints, each numerical one bigger than the one before
+ BytesRefBuilder act = new BytesRefBuilder();
+ BytesRefBuilder last = new BytesRefBuilder();
+ for (int i=-100000; i<100000; i++) {
+ LegacyNumericUtils.intToPrefixCoded(i, 0, act);
+ if (last!=null) {
+ // test if smaller
+ assertTrue("actual bigger than last (BytesRef)", last.get().compareTo(act.get()) < 0 );
+ assertTrue("actual bigger than last (as String)", last.get().utf8ToString().compareTo(act.get().utf8ToString()) < 0 );
+ }
+ // test is back and forward conversion works
+ assertEquals("forward and back conversion should generate same int", i, LegacyNumericUtils.prefixCodedToInt(act.get()));
+ // next step
+ last.copyBytes(act.get());
+ }
+ }
+
+ public void testLongSpecialValues() throws Exception {
+ long[] vals=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
+ };
+ BytesRefBuilder[] prefixVals = new BytesRefBuilder[vals.length];
+
+ for (int i=0; i<vals.length; i++) {
+ prefixVals[i] = new BytesRefBuilder();
+ LegacyNumericUtils.longToPrefixCoded(vals[i], 0, prefixVals[i]);
+
+ // check forward and back conversion
+ assertEquals( "forward and back conversion should generate same long", vals[i], LegacyNumericUtils.prefixCodedToLong(prefixVals[i].get()) );
+
+ // test if decoding values as int fails correctly
+ final int index = i;
+ expectThrows(NumberFormatException.class, () -> {
+ LegacyNumericUtils.prefixCodedToInt(prefixVals[index].get());
+ });
+ }
+
+ // check sort order (prefixVals should be ascending)
+ for (int i=1; i<prefixVals.length; i++) {
+ assertTrue( "check sort order", prefixVals[i-1].get().compareTo(prefixVals[i].get()) < 0 );
+ }
+
+ // check the prefix encoding, lower precision should have the difference to original value equal to the lower removed bits
+ final BytesRefBuilder ref = new BytesRefBuilder();
+ for (int i=0; i<vals.length; i++) {
+ for (int j=0; j<64; j++) {
+ LegacyNumericUtils.longToPrefixCoded(vals[i], j, ref);
+ long prefixVal= LegacyNumericUtils.prefixCodedToLong(ref.get());
+ long mask=(1L << j) - 1L;
+ assertEquals( "difference between prefix val and original value for "+vals[i]+" with shift="+j, vals[i] & mask, vals[i]-prefixVal );
+ }
+ }
+ }
+
+ public void testIntSpecialValues() throws Exception {
+ int[] vals=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
+ };
+ BytesRefBuilder[] prefixVals=new BytesRefBuilder[vals.length];
+
+ for (int i=0; i<vals.length; i++) {
+ prefixVals[i] = new BytesRefBuilder();
+ LegacyNumericUtils.intToPrefixCoded(vals[i], 0, prefixVals[i]);
+
+ // check forward and back conversion
+ assertEquals( "forward and back conversion should generate same int", vals[i], LegacyNumericUtils.prefixCodedToInt(prefixVals[i].get()) );
+
+ // test if decoding values as long fails correctly
+ final int index = i;
+ expectThrows(NumberFormatException.class, () -> {
+ LegacyNumericUtils.prefixCodedToLong(prefixVals[index].get());
+ });
+ }
+
+ // check sort order (prefixVals should be ascending)
+ for (int i=1; i<prefixVals.length; i++) {
+ assertTrue( "check sort order", prefixVals[i-1].get().compareTo(prefixVals[i].get()) < 0 );
+ }
+
+ // check the prefix encoding, lower precision should have the difference to original value equal to the lower removed bits
+ final BytesRefBuilder ref = new BytesRefBuilder();
+ for (int i=0; i<vals.length; i++) {
+ for (int j=0; j<32; j++) {
+ LegacyNumericUtils.intToPrefixCoded(vals[i], j, ref);
+ int prefixVal= LegacyNumericUtils.prefixCodedToInt(ref.get());
+ int mask=(1 << j) - 1;
+ assertEquals( "difference between prefix val and original value for "+vals[i]+" with shift="+j, vals[i] & mask, vals[i]-prefixVal );
+ }
+ }
+ }
+
+ public void testDoubles() throws Exception {
+ double[] vals=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[] longVals=new long[vals.length];
+
+ // check forward and back conversion
+ for (int i=0; i<vals.length; i++) {
+ longVals[i]= NumericUtils.doubleToSortableLong(vals[i]);
+ 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)
+ for (int i=1; i<longVals.length; i++) {
+ assertTrue( "check sort order", longVals[i-1] < longVals[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);
+ }
+ }
+
+ public void testFloats() throws Exception {
+ float[] vals=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[] intVals=new int[vals.length];
+
+ // check forward and back conversion
+ for (int i=0; i<vals.length; i++) {
+ intVals[i]= NumericUtils.floatToSortableInt(vals[i]);
+ 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)
+ for (int i=1; i<intVals.length; i++) {
+ assertTrue( "check sort order", intVals[i-1] < intVals[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);
+ }
+ }
+
+ // INFO: Tests for trieCodeLong()/trieCodeInt() not needed because implicitely tested by range filter tests
+
+ /** Note: The neededBounds Iterable must be unsigned (easier understanding what's happening) */
+ private void assertLongRangeSplit(final long lower, final long upper, int precisionStep,
+ final boolean useBitSet, final Iterable<Long> expectedBounds, final Iterable<Integer> expectedShifts
+ ) {
+ // Cannot use FixedBitSet since the range could be long:
+ final LongBitSet bits=useBitSet ? new LongBitSet(upper-lower+1) : null;
+ final Iterator<Long> neededBounds = (expectedBounds == null) ? null : expectedBounds.iterator();
+ final Iterator<Integer> neededShifts = (expectedShifts == null) ? null : expectedShifts.iterator();
+
+ LegacyNumericUtils.splitLongRange(new LegacyNumericUtils.LongRangeBuilder() {
+ @Override
+ public void addRange(long min, long max, int shift) {
+ assertTrue("min, max should be inside bounds", min >= lower && min <= upper && max >= lower && max <= upper);
+ if (useBitSet) for (long l = min; l <= max; l++) {
+ assertFalse("ranges should not overlap", bits.getAndSet(l - lower));
+ // extra exit condition to prevent overflow on MAX_VALUE
+ if (l == max) break;
+ }
+ if (neededBounds == null || neededShifts == null)
+ return;
+ // make unsigned longs for easier display and understanding
+ min ^= 0x8000000000000000L;
+ max ^= 0x8000000000000000L;
+ //System.out.println("0x"+Long.toHexString(min>>>shift)+"L,0x"+Long.toHexString(max>>>shift)+"L)/*shift="+shift+"*/,");
+ assertEquals("shift", neededShifts.next().intValue(), shift);
+ assertEquals("inner min bound", neededBounds.next().longValue(), min >>> shift);
+ assertEquals("inner max bound", neededBounds.next().longValue(), max >>> shift);
+ }
+ }, precisionStep, lower, upper);
+
+ if (useBitSet) {
+ // after flipping all bits in the range, the cardinality should be zero
+ bits.flip(0,upper-lower+1);
+ assertEquals("The sub-range concenated should match the whole range", 0, bits.cardinality());
+ }
+ }
+
+ /** LUCENE-2541: LegacyNumericRangeQuery errors with endpoints near long min and max values */
+ public void testLongExtremeValues() throws Exception {
+ // upper end extremes
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 1, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 2, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 4, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 6, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 8, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE, Long.MAX_VALUE, 64, true, Arrays.asList(
+ 0xffffffffffffffffL,0xffffffffffffffffL
+ ), Arrays.asList(
+ 0
+ ));
+
+ assertLongRangeSplit(Long.MAX_VALUE-0xfL, Long.MAX_VALUE, 4, true, Arrays.asList(
+ 0xfffffffffffffffL,0xfffffffffffffffL
+ ), Arrays.asList(
+ 4
+ ));
+ assertLongRangeSplit(Long.MAX_VALUE-0x10L, Long.MAX_VALUE, 4, true, Arrays.asList(
+ 0xffffffffffffffefL,0xffffffffffffffefL,
+ 0xfffffffffffffffL,0xfffffffffffffffL
+ ), Arrays.asList(
+ 0, 4
+ ));
+
+ // lower end extremes
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 1, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 2, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 4, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 6, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 8, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE, 64, true, Arrays.asList(
+ 0x0000000000000000L,0x0000000000000000L
+ ), Arrays.asList(
+ 0
+ ));
+
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE+0xfL, 4, true, Arrays.asList(
+ 0x000000000000000L,0x000000000000000L
+ ), Arrays.asList(
+ 4
+ ));
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MIN_VALUE+0x10L, 4, true, Arrays.asList(
+ 0x0000000000000010L,0x0000000000000010L,
+ 0x000000000000000L,0x000000000000000L
+ ), Arrays.asList(
+ 0, 4
+ ));
+ }
+
+ public void testRandomSplit() throws Exception {
+ long num = (long) atLeast(10);
+ for (long i=0; i < num; i++) {
+ executeOneRandomSplit(random());
+ }
+ }
+
+ private void executeOneRandomSplit(final Random random) throws Exception {
+ long lower = randomLong(random);
+ long len = random.nextInt(16384*1024); // not too large bitsets, else OOME!
+ while (lower + len < lower) { // overflow
+ lower >>= 1;
+ }
+ assertLongRangeSplit(lower, lower + len, random.nextInt(64) + 1, true, null, null);
+ }
+
+ private long randomLong(final Random random) {
+ long val;
+ switch(random.nextInt(4)) {
+ case 0:
+ val = 1L << (random.nextInt(63)); // patterns like 0x000000100000 (-1 yields patterns like 0x0000fff)
+ break;
+ case 1:
+ val = -1L << (random.nextInt(63)); // patterns like 0xfffff00000
+ break;
+ default:
+ val = random.nextLong();
+ }
+
+ val += random.nextInt(5)-2;
+
+ if (random.nextBoolean()) {
+ if (random.nextBoolean()) val += random.nextInt(100)-50;
+ if (random.nextBoolean()) val = ~val;
+ if (random.nextBoolean()) val = val<<1;
+ if (random.nextBoolean()) val = val>>>1;
+ }
+
+ return val;
+ }
+
+ public void testSplitLongRange() throws Exception {
+ // a hard-coded "standard" range
+ assertLongRangeSplit(-5000L, 9500L, 4, true, Arrays.asList(
+ 0x7fffffffffffec78L,0x7fffffffffffec7fL,
+ 0x8000000000002510L,0x800000000000251cL,
+ 0x7fffffffffffec8L, 0x7fffffffffffecfL,
+ 0x800000000000250L, 0x800000000000250L,
+ 0x7fffffffffffedL, 0x7fffffffffffefL,
+ 0x80000000000020L, 0x80000000000024L,
+ 0x7ffffffffffffL, 0x8000000000001L
+ ), Arrays.asList(
+ 0, 0,
+ 4, 4,
+ 8, 8,
+ 12
+ ));
+
+ // the same with no range splitting
+ assertLongRangeSplit(-5000L, 9500L, 64, true, Arrays.asList(
+ 0x7fffffffffffec78L,0x800000000000251cL
+ ), Arrays.asList(
+ 0
+ ));
+
+ // this tests optimized range splitting, if one of the inner bounds
+ // is also the bound of the next lower precision, it should be used completely
+ assertLongRangeSplit(0L, 1024L+63L, 4, true, Arrays.asList(
+ 0x800000000000040L, 0x800000000000043L,
+ 0x80000000000000L, 0x80000000000003L
+ ), Arrays.asList(
+ 4, 8
+ ));
+
+ // the full long range should only consist of a lowest precision range; no bitset testing here, as too much memory needed :-)
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MAX_VALUE, 8, false, Arrays.asList(
+ 0x00L,0xffL
+ ), Arrays.asList(
+ 56
+ ));
+
+ // the same with precisionStep=4
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MAX_VALUE, 4, false, Arrays.asList(
+ 0x0L,0xfL
+ ), Arrays.asList(
+ 60
+ ));
+
+ // the same with precisionStep=2
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MAX_VALUE, 2, false, Arrays.asList(
+ 0x0L,0x3L
+ ), Arrays.asList(
+ 62
+ ));
+
+ // the same with precisionStep=1
+ assertLongRangeSplit(Long.MIN_VALUE, Long.MAX_VALUE, 1, false, Arrays.asList(
+ 0x0L,0x1L
+ ), Arrays.asList(
+ 63
+ ));
+
+ // a inverse range should produce no sub-ranges
+ assertLongRangeSplit(9500L, -5000L, 4, false, Collections.<Long>emptyList(), Collections.<Integer>emptyList());
+
+ // a 0-length range should reproduce the range itself
+ assertLongRangeSplit(9500L, 9500L, 4, false, Arrays.asList(
+ 0x800000000000251cL,0x800000000000251cL
+ ), Arrays.asList(
+ 0
+ ));
+ }
+
+ /** Note: The neededBounds Iterable must be unsigned (easier understanding what's happening) */
+ private void assertIntRangeSplit(final int lower, final int upper, int precisionStep,
+ final boolean useBitSet, final Iterable<Integer> expectedBounds, final Iterable<Integer> expectedShifts
+ ) {
+ final FixedBitSet bits=useBitSet ? new FixedBitSet(upper-lower+1) : null;
+ final Iterator<Integer> neededBounds = (expectedBounds == null) ? null : expectedBounds.iterator();
+ final Iterator<Integer> neededShifts = (expectedShifts == null) ? null : expectedShifts.iterator();
+
+ LegacyNumericUtils.splitIntRange(new LegacyNumericUtils.IntRangeBuilder() {
+ @Override
+ public void addRange(int min, int max, int shift) {
+ assertTrue("min, max should be inside bounds", min >= lower && min <= upper && max >= lower && max <= upper);
+ if (useBitSet) for (int i = min; i <= max; i++) {
+ assertFalse("ranges should not overlap", bits.getAndSet(i - lower));
+ // extra exit condition to prevent overflow on MAX_VALUE
+ if (i == max) break;
+ }
+ if (neededBounds == null)
+ return;
+ // make unsigned ints for easier display and understanding
+ min ^= 0x80000000;
+ max ^= 0x80000000;
+ //System.out.println("0x"+Integer.toHexString(min>>>shift)+",0x"+Integer.toHexString(max>>>shift)+")/*shift="+shift+"*/,");
+ assertEquals("shift", neededShifts.next().intValue(), shift);
+ assertEquals("inner min bound", neededBounds.next().intValue(), min >>> shift);
+ assertEquals("inner max bound", neededBounds.next().intValue(), max >>> shift);
+ }
+ }, precisionStep, lower, upper);
+
+ if (useBitSet) {
+ // after flipping all bits in the range, the cardinality should be zero
+ bits.flip(0, upper-lower+1);
+ assertEquals("The sub-range concenated should match the whole range", 0, bits.cardinality());
+ }
+ }
+
+ public void testSplitIntRange() throws Exception {
+ // a hard-coded "standard" range
+ assertIntRangeSplit(-5000, 9500, 4, true, Arrays.asList(
+ 0x7fffec78,0x7fffec7f,
+ 0x80002510,0x8000251c,
+ 0x7fffec8, 0x7fffecf,
+ 0x8000250, 0x8000250,
+ 0x7fffed, 0x7fffef,
+ 0x800020, 0x800024,
+ 0x7ffff, 0x80001
+ ), Arrays.asList(
+ 0, 0,
+ 4, 4,
+ 8, 8,
+ 12
+ ));
+
+ // the same with no range splitting
+ assertIntRangeSplit(-5000, 9500, 32, true, Arrays.asList(
+ 0x7fffec78,0x8000251c
+ ), Arrays.asList(
+ 0
+ ));
+
+ // this tests optimized range splitting, if one of the inner bounds
+ // is also the bound of the next lower precision, it should be used completely
+ assertIntRangeSplit(0, 1024+63, 4, true, Arrays.asList(
+ 0x8000040, 0x8000043,
+ 0x800000, 0x800003
+ ), Arrays.asList(
+ 4, 8
+ ));
+
+ // the full int range should only consist of a lowest precision range; no bitset testing here, as too much memory needed :-)
+ assertIntRangeSplit(Integer.MIN_VALUE, Integer.MAX_VALUE, 8, false, Arrays.asList(
+ 0x00,0xff
+ ), Arrays.asList(
+ 24
+ ));
+
+ // the same with precisionStep=4
+ assertIntRangeSplit(Integer.MIN_VALUE, Integer.MAX_VALUE, 4, false, Arrays.asList(
+ 0x0,0xf
+ ), Arrays.asList(
+ 28
+ ));
+
+ // the same with precisionStep=2
+ assertIntRangeSplit(Integer.MIN_VALUE, Integer.MAX_VALUE, 2, false, Arrays.asList(
+ 0x0,0x3
+ ), Arrays.asList(
+ 30
+ ));
+
+ // the same with precisionStep=1
+ assertIntRangeSplit(Integer.MIN_VALUE, Integer.MAX_VALUE, 1, false, Arrays.asList(
+ 0x0,0x1
+ ), Arrays.asList(
+ 31
+ ));
+
+ // a inverse range should produce no sub-ranges
+ assertIntRangeSplit(9500, -5000, 4, false, Collections.<Integer>emptyList(), Collections.<Integer>emptyList());
+
+ // a 0-length range should reproduce the range itself
+ assertIntRangeSplit(9500, 9500, 4, false, Arrays.asList(
+ 0x8000251c,0x8000251c
+ ), Arrays.asList(
+ 0
+ ));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestLegacyTerms.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestLegacyTerms.java b/solr/core/src/test/org/apache/solr/legacy/TestLegacyTerms.java
new file mode 100644
index 0000000..d91ba88
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestLegacyTerms.java
@@ -0,0 +1,164 @@
+/*
+ * 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.solr.legacy;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.MultiFields;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.index.TermsEnum;
+import org.apache.solr.legacy.LegacyDoubleField;
+import org.apache.solr.legacy.LegacyFloatField;
+import org.apache.solr.legacy.LegacyIntField;
+import org.apache.solr.legacy.LegacyLongField;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.NumericUtils;
+
+public class TestLegacyTerms extends LuceneTestCase {
+
+ public void testEmptyIntFieldMinMax() throws Exception {
+ assertNull(LegacyNumericUtils.getMinInt(EMPTY_TERMS));
+ assertNull(LegacyNumericUtils.getMaxInt(EMPTY_TERMS));
+ }
+
+ public void testIntFieldMinMax() throws Exception {
+ Directory dir = newDirectory();
+ RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+ int numDocs = atLeast(100);
+ int minValue = Integer.MAX_VALUE;
+ int maxValue = Integer.MIN_VALUE;
+ for(int i=0;i<numDocs;i++ ){
+ Document doc = new Document();
+ int num = random().nextInt();
+ minValue = Math.min(num, minValue);
+ maxValue = Math.max(num, maxValue);
+ doc.add(new LegacyIntField("field", num, Field.Store.NO));
+ w.addDocument(doc);
+ }
+
+ IndexReader r = w.getReader();
+ Terms terms = MultiFields.getTerms(r, "field");
+ assertEquals(new Integer(minValue), LegacyNumericUtils.getMinInt(terms));
+ assertEquals(new Integer(maxValue), LegacyNumericUtils.getMaxInt(terms));
+
+ r.close();
+ w.close();
+ dir.close();
+ }
+
+ public void testEmptyLongFieldMinMax() throws Exception {
+ assertNull(LegacyNumericUtils.getMinLong(EMPTY_TERMS));
+ assertNull(LegacyNumericUtils.getMaxLong(EMPTY_TERMS));
+ }
+
+ public void testLongFieldMinMax() throws Exception {
+ Directory dir = newDirectory();
+ RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+ int numDocs = atLeast(100);
+ long minValue = Long.MAX_VALUE;
+ long maxValue = Long.MIN_VALUE;
+ for(int i=0;i<numDocs;i++ ){
+ Document doc = new Document();
+ long num = random().nextLong();
+ minValue = Math.min(num, minValue);
+ maxValue = Math.max(num, maxValue);
+ doc.add(new LegacyLongField("field", num, Field.Store.NO));
+ w.addDocument(doc);
+ }
+
+ IndexReader r = w.getReader();
+
+ Terms terms = MultiFields.getTerms(r, "field");
+ assertEquals(new Long(minValue), LegacyNumericUtils.getMinLong(terms));
+ assertEquals(new Long(maxValue), LegacyNumericUtils.getMaxLong(terms));
+
+ r.close();
+ w.close();
+ dir.close();
+ }
+
+ public void testFloatFieldMinMax() throws Exception {
+ Directory dir = newDirectory();
+ RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+ int numDocs = atLeast(100);
+ float minValue = Float.POSITIVE_INFINITY;
+ float maxValue = Float.NEGATIVE_INFINITY;
+ for(int i=0;i<numDocs;i++ ){
+ Document doc = new Document();
+ float num = random().nextFloat();
+ minValue = Math.min(num, minValue);
+ maxValue = Math.max(num, maxValue);
+ doc.add(new LegacyFloatField("field", num, Field.Store.NO));
+ w.addDocument(doc);
+ }
+
+ IndexReader r = w.getReader();
+ Terms terms = MultiFields.getTerms(r, "field");
+ assertEquals(minValue, NumericUtils.sortableIntToFloat(LegacyNumericUtils.getMinInt(terms)), 0.0f);
+ assertEquals(maxValue, NumericUtils.sortableIntToFloat(LegacyNumericUtils.getMaxInt(terms)), 0.0f);
+
+ r.close();
+ w.close();
+ dir.close();
+ }
+
+ public void testDoubleFieldMinMax() throws Exception {
+ Directory dir = newDirectory();
+ RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+ int numDocs = atLeast(100);
+ double minValue = Double.POSITIVE_INFINITY;
+ double maxValue = Double.NEGATIVE_INFINITY;
+ for(int i=0;i<numDocs;i++ ){
+ Document doc = new Document();
+ double num = random().nextDouble();
+ minValue = Math.min(num, minValue);
+ maxValue = Math.max(num, maxValue);
+ doc.add(new LegacyDoubleField("field", num, Field.Store.NO));
+ w.addDocument(doc);
+ }
+
+ IndexReader r = w.getReader();
+
+ Terms terms = MultiFields.getTerms(r, "field");
+
+ assertEquals(minValue, NumericUtils.sortableLongToDouble(LegacyNumericUtils.getMinLong(terms)), 0.0);
+ assertEquals(maxValue, NumericUtils.sortableLongToDouble(LegacyNumericUtils.getMaxLong(terms)), 0.0);
+
+ r.close();
+ w.close();
+ dir.close();
+ }
+
+ /**
+ * A complete empty Terms instance that has no terms in it and supports no optional statistics
+ */
+ private static Terms EMPTY_TERMS = new Terms() {
+ public TermsEnum iterator() { return TermsEnum.EMPTY; }
+ public long size() { return -1; }
+ public long getSumTotalTermFreq() { return -1; }
+ public long getSumDocFreq() { return -1; }
+ public int getDocCount() { return -1; }
+ public boolean hasFreqs() { return false; }
+ public boolean hasOffsets() { return false; }
+ public boolean hasPositions() { return false; }
+ public boolean hasPayloads() { return false; }
+ };
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestMultiValuedNumericRangeQuery.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestMultiValuedNumericRangeQuery.java b/solr/core/src/test/org/apache/solr/legacy/TestMultiValuedNumericRangeQuery.java
new file mode 100644
index 0000000..80b1524
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestMultiValuedNumericRangeQuery.java
@@ -0,0 +1,84 @@
+/*
+ * 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.solr.legacy;
+
+
+import java.util.Locale;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+
+import org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.solr.legacy.LegacyIntField;
+import org.apache.solr.legacy.LegacyNumericRangeQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.TermRangeQuery;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+
+public class TestMultiValuedNumericRangeQuery extends LuceneTestCase {
+
+ /** Tests LegacyNumericRangeQuery on a multi-valued field (multiple numeric values per document).
+ * This test ensures, that a classical TermRangeQuery returns exactly the same document numbers as
+ * LegacyNumericRangeQuery (see SOLR-1322 for discussion) and the multiple precision terms per numeric value
+ * do not interfere with multiple numeric values.
+ */
+ public void testMultiValuedNRQ() throws Exception {
+ Directory directory = newDirectory();
+ RandomIndexWriter writer = new RandomIndexWriter(random(), directory,
+ newIndexWriterConfig(new MockAnalyzer(random()))
+ .setMaxBufferedDocs(TestUtil.nextInt(random(), 50, 1000)));
+
+ DecimalFormat format = new DecimalFormat("00000000000", new DecimalFormatSymbols(Locale.ROOT));
+
+ int num = atLeast(500);
+ for (int l = 0; l < num; l++) {
+ Document doc = new Document();
+ for (int m=0, c=random().nextInt(10); m<=c; m++) {
+ int value = random().nextInt(Integer.MAX_VALUE);
+ doc.add(newStringField("asc", format.format(value), Field.Store.NO));
+ doc.add(new LegacyIntField("trie", value, Field.Store.NO));
+ }
+ writer.addDocument(doc);
+ }
+ IndexReader reader = writer.getReader();
+ writer.close();
+
+ IndexSearcher searcher=newSearcher(reader);
+ num = atLeast(50);
+ for (int i = 0; i < num; i++) {
+ int lower=random().nextInt(Integer.MAX_VALUE);
+ int upper=random().nextInt(Integer.MAX_VALUE);
+ if (lower>upper) {
+ int a=lower; lower=upper; upper=a;
+ }
+ TermRangeQuery cq=TermRangeQuery.newStringRange("asc", format.format(lower), format.format(upper), true, true);
+ LegacyNumericRangeQuery<Integer> tq= LegacyNumericRangeQuery.newIntRange("trie", lower, upper, true, true);
+ TopDocs trTopDocs = searcher.search(cq, 1);
+ TopDocs nrTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count for LegacyNumericRangeQuery and TermRangeQuery must be equal", trTopDocs.totalHits, nrTopDocs.totalHits );
+ }
+ reader.close();
+ directory.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/759fa42b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
new file mode 100644
index 0000000..5c02913
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
@@ -0,0 +1,461 @@
+/*
+ * 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.solr.legacy;
+
+
+import org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MultiTermQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.QueryUtils;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.TestUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestNumericRangeQuery32 extends LuceneTestCase {
+ // distance of entries
+ private static int distance;
+ // shift the starting of the values to the left, to also have negative values:
+ private static final int startOffset = - 1 << 15;
+ // number of docs to generate for testing
+ private static int noDocs;
+
+ private static Directory directory = null;
+ private static IndexReader reader = null;
+ private static IndexSearcher searcher = null;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ noDocs = atLeast(4096);
+ distance = (1 << 30) / noDocs;
+ directory = newDirectory();
+ RandomIndexWriter writer = new RandomIndexWriter(random(), directory,
+ newIndexWriterConfig(new MockAnalyzer(random()))
+ .setMaxBufferedDocs(TestUtil.nextInt(random(), 100, 1000))
+ .setMergePolicy(newLogMergePolicy()));
+
+ final LegacyFieldType storedInt = new LegacyFieldType(LegacyIntField.TYPE_NOT_STORED);
+ storedInt.setStored(true);
+ storedInt.freeze();
+
+ final LegacyFieldType storedInt8 = new LegacyFieldType(storedInt);
+ storedInt8.setNumericPrecisionStep(8);
+
+ final LegacyFieldType storedInt4 = new LegacyFieldType(storedInt);
+ storedInt4.setNumericPrecisionStep(4);
+
+ final LegacyFieldType storedInt2 = new LegacyFieldType(storedInt);
+ storedInt2.setNumericPrecisionStep(2);
+
+ final LegacyFieldType storedIntNone = new LegacyFieldType(storedInt);
+ storedIntNone.setNumericPrecisionStep(Integer.MAX_VALUE);
+
+ final LegacyFieldType unstoredInt = LegacyIntField.TYPE_NOT_STORED;
+
+ final LegacyFieldType unstoredInt8 = new LegacyFieldType(unstoredInt);
+ unstoredInt8.setNumericPrecisionStep(8);
+
+ final LegacyFieldType unstoredInt4 = new LegacyFieldType(unstoredInt);
+ unstoredInt4.setNumericPrecisionStep(4);
+
+ final LegacyFieldType unstoredInt2 = new LegacyFieldType(unstoredInt);
+ unstoredInt2.setNumericPrecisionStep(2);
+
+ LegacyIntField
+ field8 = new LegacyIntField("field8", 0, storedInt8),
+ field4 = new LegacyIntField("field4", 0, storedInt4),
+ field2 = new LegacyIntField("field2", 0, storedInt2),
+ fieldNoTrie = new LegacyIntField("field"+Integer.MAX_VALUE, 0, storedIntNone),
+ ascfield8 = new LegacyIntField("ascfield8", 0, unstoredInt8),
+ ascfield4 = new LegacyIntField("ascfield4", 0, unstoredInt4),
+ ascfield2 = new LegacyIntField("ascfield2", 0, unstoredInt2);
+
+ Document doc = new Document();
+ // add fields, that have a distance to test general functionality
+ doc.add(field8); doc.add(field4); doc.add(field2); doc.add(fieldNoTrie);
+ // add ascending fields with a distance of 1, beginning at -noDocs/2 to test the correct splitting of range and inclusive/exclusive
+ doc.add(ascfield8); doc.add(ascfield4); doc.add(ascfield2);
+
+ // Add a series of noDocs docs with increasing int values
+ for (int l=0; l<noDocs; l++) {
+ int val=distance*l+startOffset;
+ field8.setIntValue(val);
+ field4.setIntValue(val);
+ field2.setIntValue(val);
+ fieldNoTrie.setIntValue(val);
+
+ val=l-(noDocs/2);
+ ascfield8.setIntValue(val);
+ ascfield4.setIntValue(val);
+ ascfield2.setIntValue(val);
+ writer.addDocument(doc);
+ }
+
+ reader = writer.getReader();
+ searcher=newSearcher(reader);
+ writer.close();
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ searcher = null;
+ reader.close();
+ reader = null;
+ directory.close();
+ directory = null;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ // set the theoretical maximum term count for 8bit (see docs for the number)
+ // super.tearDown will restore the default
+ BooleanQuery.setMaxClauseCount(3*255*2 + 255);
+ }
+
+ /** test for both constant score and boolean query, the other tests only use the constant score mode */
+ private void testRange(int precisionStep) throws Exception {
+ String field="field"+precisionStep;
+ int count=3000;
+ int lower=(distance*3/2)+startOffset, upper=lower + count*distance + (distance/3);
+ LegacyNumericRangeQuery<Integer> q = LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
+ for (byte i=0; i<2; i++) {
+ TopDocs topDocs;
+ String type;
+ switch (i) {
+ case 0:
+ type = " (constant score filter rewrite)";
+ q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_REWRITE);
+ topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ break;
+ case 1:
+ type = " (constant score boolean rewrite)";
+ q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE);
+ topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ break;
+ default:
+ return;
+ }
+ ScoreDoc[] sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count"+type, count, sd.length );
+ Document doc=searcher.doc(sd[0].doc);
+ assertEquals("First doc"+type, 2*distance+startOffset, doc.getField(field).numericValue().intValue());
+ doc=searcher.doc(sd[sd.length-1].doc);
+ assertEquals("Last doc"+type, (1+count)*distance+startOffset, doc.getField(field).numericValue().intValue());
+ }
+ }
+
+ @Test
+ public void testRange_8bit() throws Exception {
+ testRange(8);
+ }
+
+ @Test
+ public void testRange_4bit() throws Exception {
+ testRange(4);
+ }
+
+ @Test
+ public void testRange_2bit() throws Exception {
+ testRange(2);
+ }
+
+ @Test
+ public void testOneMatchQuery() throws Exception {
+ LegacyNumericRangeQuery<Integer> q = LegacyNumericRangeQuery.newIntRange("ascfield8", 8, 1000, 1000, true, true);
+ TopDocs topDocs = searcher.search(q, noDocs);
+ ScoreDoc[] sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count", 1, sd.length );
+ }
+
+ private void testLeftOpenRange(int precisionStep) throws Exception {
+ String field="field"+precisionStep;
+ int count=3000;
+ int upper=(count-1)*distance + (distance/3) + startOffset;
+ LegacyNumericRangeQuery<Integer> q= LegacyNumericRangeQuery.newIntRange(field, precisionStep, null, upper, true, true);
+ TopDocs topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ ScoreDoc[] sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count", count, sd.length );
+ Document doc=searcher.doc(sd[0].doc);
+ assertEquals("First doc", startOffset, doc.getField(field).numericValue().intValue());
+ doc=searcher.doc(sd[sd.length-1].doc);
+ assertEquals("Last doc", (count-1)*distance+startOffset, doc.getField(field).numericValue().intValue());
+
+ q= LegacyNumericRangeQuery.newIntRange(field, precisionStep, null, upper, false, true);
+ topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count", count, sd.length );
+ doc=searcher.doc(sd[0].doc);
+ assertEquals("First doc", startOffset, doc.getField(field).numericValue().intValue());
+ doc=searcher.doc(sd[sd.length-1].doc);
+ assertEquals("Last doc", (count-1)*distance+startOffset, doc.getField(field).numericValue().intValue());
+ }
+
+ @Test
+ public void testLeftOpenRange_8bit() throws Exception {
+ testLeftOpenRange(8);
+ }
+
+ @Test
+ public void testLeftOpenRange_4bit() throws Exception {
+ testLeftOpenRange(4);
+ }
+
+ @Test
+ public void testLeftOpenRange_2bit() throws Exception {
+ testLeftOpenRange(2);
+ }
+
+ private void testRightOpenRange(int precisionStep) throws Exception {
+ String field="field"+precisionStep;
+ int count=3000;
+ int lower=(count-1)*distance + (distance/3) +startOffset;
+ LegacyNumericRangeQuery<Integer> q= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, true);
+ TopDocs topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ ScoreDoc[] sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count", noDocs-count, sd.length );
+ Document doc=searcher.doc(sd[0].doc);
+ assertEquals("First doc", count*distance+startOffset, doc.getField(field).numericValue().intValue());
+ doc=searcher.doc(sd[sd.length-1].doc);
+ assertEquals("Last doc", (noDocs-1)*distance+startOffset, doc.getField(field).numericValue().intValue());
+
+ q= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, false);
+ topDocs = searcher.search(q, noDocs, Sort.INDEXORDER);
+ sd = topDocs.scoreDocs;
+ assertNotNull(sd);
+ assertEquals("Score doc count", noDocs-count, sd.length );
+ doc=searcher.doc(sd[0].doc);
+ assertEquals("First doc", count*distance+startOffset, doc.getField(field).numericValue().intValue() );
+ doc=searcher.doc(sd[sd.length-1].doc);
+ assertEquals("Last doc", (noDocs-1)*distance+startOffset, doc.getField(field).numericValue().intValue() );
+ }
+
+ @Test
+ public void testRightOpenRange_8bit() throws Exception {
+ testRightOpenRange(8);
+ }
+
+ @Test
+ public void testRightOpenRange_4bit() throws Exception {
+ testRightOpenRange(4);
+ }
+
+ @Test
+ public void testRightOpenRange_2bit() throws Exception {
+ testRightOpenRange(2);
+ }
+
+ @Test
+ public void testInfiniteValues() throws Exception {
+ Directory dir = newDirectory();
+ RandomIndexWriter writer = new RandomIndexWriter(random(), dir,
+ newIndexWriterConfig(new MockAnalyzer(random())));
+ Document doc = new Document();
+ doc.add(new LegacyFloatField("float", Float.NEGATIVE_INFINITY, Field.Store.NO));
+ doc.add(new LegacyIntField("int", Integer.MIN_VALUE, Field.Store.NO));
+ writer.addDocument(doc);
+
+ doc = new Document();
+ doc.add(new LegacyFloatField("float", Float.POSITIVE_INFINITY, Field.Store.NO));
+ doc.add(new LegacyIntField("int", Integer.MAX_VALUE, Field.Store.NO));
+ writer.addDocument(doc);
+
+ doc = new Document();
+ doc.add(new LegacyFloatField("float", 0.0f, Field.Store.NO));
+ doc.add(new LegacyIntField("int", 0, Field.Store.NO));
+ writer.addDocument(doc);
+
+ for (float f : TestLegacyNumericUtils.FLOAT_NANs) {
+ doc = new Document();
+ doc.add(new LegacyFloatField("float", f, Field.Store.NO));
+ writer.addDocument(doc);
+ }
+
+ writer.close();
+
+ IndexReader r = DirectoryReader.open(dir);
+ IndexSearcher s = newSearcher(r);
+
+ Query q= LegacyNumericRangeQuery.newIntRange("int", null, null, true, true);
+ TopDocs topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newIntRange("int", null, null, false, false);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, true, true);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, false, false);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 1, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newFloatRange("float", null, null, true, true);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newFloatRange("float", null, null, false, false);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newFloatRange("float", Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, true, true);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 3, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newFloatRange("float", Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, false, false);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", 1, topDocs.scoreDocs.length );
+
+ q= LegacyNumericRangeQuery.newFloatRange("float", Float.NaN, Float.NaN, true, true);
+ topDocs = s.search(q, 10);
+ assertEquals("Score doc count", TestLegacyNumericUtils.FLOAT_NANs.length, topDocs.scoreDocs.length );
+
+ r.close();
+ dir.close();
+ }
+
+ private void testRangeSplit(int precisionStep) throws Exception {
+ String field="ascfield"+precisionStep;
+ // 10 random tests
+ int num = TestUtil.nextInt(random(), 10, 20);
+ for (int i =0; i< num; i++) {
+ int lower=(int)(random().nextDouble()*noDocs - noDocs/2);
+ int upper=(int)(random().nextDouble()*noDocs - noDocs/2);
+ if (lower>upper) {
+ int a=lower; lower=upper; upper=a;
+ }
+ // test inclusive range
+ Query tq= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
+ TopDocs tTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
+ // test exclusive range
+ tq= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, false);
+ tTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count of range query must be equal to exclusive range length", Math.max(upper-lower-1, 0), tTopDocs.totalHits );
+ // test left exclusive range
+ tq= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, true);
+ tTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
+ // test right exclusive range
+ tq= LegacyNumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, false);
+ tTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
+ }
+ }
+
+ @Test
+ public void testRangeSplit_8bit() throws Exception {
+ testRangeSplit(8);
+ }
+
+ @Test
+ public void testRangeSplit_4bit() throws Exception {
+ testRangeSplit(4);
+ }
+
+ @Test
+ public void testRangeSplit_2bit() throws Exception {
+ testRangeSplit(2);
+ }
+
+ /** we fake a float test using int2float conversion of LegacyNumericUtils */
+ private void testFloatRange(int precisionStep) throws Exception {
+ final String field="ascfield"+precisionStep;
+ final int lower=-1000, upper=+2000;
+
+ Query tq= LegacyNumericRangeQuery.newFloatRange(field, precisionStep,
+ NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
+ TopDocs tTopDocs = searcher.search(tq, 1);
+ assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
+ }
+
+ @Test
+ public void testFloatRange_8bit() throws Exception {
+ testFloatRange(8);
+ }
+
+ @Test
+ public void testFloatRange_4bit() throws Exception {
+ testFloatRange(4);
+ }
+
+ @Test
+ public void testFloatRange_2bit() throws Exception {
+ testFloatRange(2);
+ }
+
+ @Test
+ public void testEqualsAndHash() throws Exception {
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test1", 4, 10, 20, true, true));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test2", 4, 10, 20, false, true));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test3", 4, 10, 20, true, false));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test4", 4, 10, 20, false, false));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test5", 4, 10, null, true, true));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test6", 4, null, 20, true, true));
+ QueryUtils.checkHashEquals(LegacyNumericRangeQuery.newIntRange("test7", 4, null, null, true, true));
+ QueryUtils.checkEqual(
+ LegacyNumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true)
+ );
+ QueryUtils.checkUnequal(
+ LegacyNumericRangeQuery.newIntRange("test9", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newIntRange("test9", 8, 10, 20, true, true)
+ );
+ QueryUtils.checkUnequal(
+ LegacyNumericRangeQuery.newIntRange("test10a", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newIntRange("test10b", 4, 10, 20, true, true)
+ );
+ QueryUtils.checkUnequal(
+ LegacyNumericRangeQuery.newIntRange("test11", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newIntRange("test11", 4, 20, 10, true, true)
+ );
+ QueryUtils.checkUnequal(
+ LegacyNumericRangeQuery.newIntRange("test12", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newIntRange("test12", 4, 10, 20, false, true)
+ );
+ QueryUtils.checkUnequal(
+ LegacyNumericRangeQuery.newIntRange("test13", 4, 10, 20, true, true),
+ LegacyNumericRangeQuery.newFloatRange("test13", 4, 10f, 20f, true, true)
+ );
+ // the following produces a hash collision, because Long and Integer have the same hashcode, so only test equality:
+ Query q1 = LegacyNumericRangeQuery.newIntRange("test14", 4, 10, 20, true, true);
+ Query q2 = LegacyNumericRangeQuery.newLongRange("test14", 4, 10L, 20L, true, true);
+ assertFalse(q1.equals(q2));
+ assertFalse(q2.equals(q1));
+ }
+
+}