diff --git a/solr/core/src/java/org/apache/solr/schema/PointField.java b/solr/core/src/java/org/apache/solr/schema/PointField.java index 1168386dca5..8746dac515f 100644 --- a/solr/core/src/java/org/apache/solr/schema/PointField.java +++ b/solr/core/src/java/org/apache/solr/schema/PointField.java @@ -28,6 +28,7 @@ import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.document.StoredField; import org.apache.lucene.index.IndexableField; import org.apache.lucene.queries.function.ValueSource; +import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortedNumericSelector; import org.apache.lucene.util.BytesRef; @@ -117,6 +118,10 @@ public abstract class PointField extends NumericFieldType { if (!field.indexed() && field.hasDocValues()) { // currently implemented as singleton range return getRangeQuery(parser, field, externalVal, externalVal, true, true); + } else if (field.indexed() && field.hasDocValues()) { + Query pointsQuery = getExactQuery(field, externalVal); + Query dvQuery = getDocValuesRangeQuery(parser, field, externalVal, externalVal, true, true); + return new IndexOrDocValuesQuery(pointsQuery, dvQuery); } else { return getExactQuery(field, externalVal); } @@ -132,6 +137,10 @@ public abstract class PointField extends NumericFieldType { boolean maxInclusive) { if (!field.indexed() && field.hasDocValues()) { return getDocValuesRangeQuery(parser, field, min, max, minInclusive, maxInclusive); + } else if (field.indexed() && field.hasDocValues()) { + Query pointsQuery = getPointRangeQuery(parser, field, min, max, minInclusive, maxInclusive); + Query dvQuery = getDocValuesRangeQuery(parser, field, min, max, minInclusive, maxInclusive); + return new IndexOrDocValuesQuery(pointsQuery, dvQuery); } else { return getPointRangeQuery(parser, field, min, max, minInclusive, maxInclusive); } diff --git a/solr/core/src/test-files/solr/collection1/conf/schema.xml b/solr/core/src/test-files/solr/collection1/conf/schema.xml index ef7fc8df7bf..c53be9b537f 100644 --- a/solr/core/src/test-files/solr/collection1/conf/schema.xml +++ b/solr/core/src/test-files/solr/collection1/conf/schema.xml @@ -395,7 +395,7 @@ - + @@ -620,6 +620,7 @@ + diff --git a/solr/core/src/test/org/apache/solr/schema/PolyFieldTest.java b/solr/core/src/test/org/apache/solr/schema/PolyFieldTest.java index 56eb7e04d4f..f788ba0f721 100644 --- a/solr/core/src/test/org/apache/solr/schema/PolyFieldTest.java +++ b/solr/core/src/test/org/apache/solr/schema/PolyFieldTest.java @@ -111,13 +111,17 @@ public class PolyFieldTest extends SolrTestCaseJ4 { // } - // + SchemaField s1 = schema.getField("test_p"); SchemaField s2 = schema.getField("test_p"); - ValueSource v1 = s1.getType().getValueSource(s1, null); - ValueSource v2 = s2.getType().getValueSource(s2, null); - assertEquals(v1, v2); - assertEquals(v1.hashCode(), v2.hashCode()); + // If we use [Int/Double/Long/Float]PointField, we can't get the valueSource, since docValues is false + if (s1.createFields("1,2", 0).get(0).fieldType().pointDimensionCount() == 0) { + assertFalse(s2.getType().isPointField()); + ValueSource v1 = s1.getType().getValueSource(s1, null); + ValueSource v2 = s2.getType().getValueSource(s2, null); + assertEquals(v1, v2); + assertEquals(v1.hashCode(), v2.hashCode()); + } } @Test diff --git a/solr/core/src/test/org/apache/solr/schema/TestPointFields.java b/solr/core/src/test/org/apache/solr/schema/TestPointFields.java index bf34ce4f560..b3d0b97fa1d 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestPointFields.java +++ b/solr/core/src/test/org/apache/solr/schema/TestPointFields.java @@ -21,6 +21,8 @@ import java.util.Locale; import java.util.Set; import java.util.TreeSet; +import org.apache.lucene.search.IndexOrDocValuesQuery; +import org.apache.lucene.search.PointRangeQuery; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrException; import org.junit.After; @@ -71,6 +73,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testIntPointFieldRangeQuery() throws Exception { doTestIntPointFieldRangeQuery("number_p_i", "int", false); doTestIntPointFieldRangeQuery("number_p_i_ni_ns_dv", "int", false); + doTestIntPointFieldRangeQuery("number_p_i_dv", "int", false); } @Test @@ -120,6 +123,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testIntPointFieldMultiValuedRangeQuery() throws Exception { testPointFieldMultiValuedRangeQuery("number_p_i_mv", "int", getSequentialStringArrayWithInts(20)); testPointFieldMultiValuedRangeQuery("number_p_i_ni_mv_dv", "int", getSequentialStringArrayWithInts(20)); + testPointFieldMultiValuedRangeQuery("number_p_i_mv_dv", "int", getSequentialStringArrayWithInts(20)); } //TODO MV SORT? @@ -198,6 +202,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testDoublePointFieldRangeQuery() throws Exception { doTestFloatPointFieldRangeQuery("number_p_d", "double", true); doTestFloatPointFieldRangeQuery("number_p_d_ni_ns_dv", "double", true); + doTestFloatPointFieldRangeQuery("number_p_d_dv", "double", true); } @Test @@ -249,6 +254,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testDoublePointFieldMultiValuedRangeQuery() throws Exception { testPointFieldMultiValuedRangeQuery("number_p_d_mv", "double", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_d_ni_mv_dv", "double", getSequentialStringArrayWithDoubles(20)); + testPointFieldMultiValuedRangeQuery("number_p_d_mv_dv", "double", getSequentialStringArrayWithDoubles(20)); } @Test @@ -360,6 +366,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testFloatPointFieldRangeQuery() throws Exception { doTestFloatPointFieldRangeQuery("number_p_f", "float", false); doTestFloatPointFieldRangeQuery("number_p_f_ni_ns_dv", "float", false); + doTestFloatPointFieldRangeQuery("number_p_f_dv", "float", false); } @Test @@ -411,6 +418,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testFloatPointFieldMultiValuedRangeQuery() throws Exception { testPointFieldMultiValuedRangeQuery("number_p_f_mv", "float", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_f_ni_mv_dv", "float", getSequentialStringArrayWithDoubles(20)); + testPointFieldMultiValuedRangeQuery("number_p_f_mv_dv", "float", getSequentialStringArrayWithDoubles(20)); } @Test @@ -481,6 +489,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testLongPointFieldRangeQuery() throws Exception { doTestIntPointFieldRangeQuery("number_p_l", "long", true); doTestIntPointFieldRangeQuery("number_p_l_ni_ns_dv", "long", true); + doTestIntPointFieldRangeQuery("number_p_l_dv", "long", true); } @Test @@ -533,6 +542,7 @@ public class TestPointFields extends SolrTestCaseJ4 { public void testLongPointFieldMultiValuedRangeQuery() throws Exception { testPointFieldMultiValuedRangeQuery("number_p_l_mv", "long", getSequentialStringArrayWithInts(20)); testPointFieldMultiValuedRangeQuery("number_p_l_ni_mv_dv", "long", getSequentialStringArrayWithInts(20)); + testPointFieldMultiValuedRangeQuery("number_p_l_mv_dv", "long", getSequentialStringArrayWithInts(20)); } @Test @@ -578,6 +588,27 @@ public class TestPointFields extends SolrTestCaseJ4 { doTestSetQueries("number_p_l_ni_dv", getRandomStringArrayWithLongs(10, false), false); } + @Test + public void testIndexOrDocValuesQuery() throws Exception { + String[] fieldTypeNames = new String[]{"_p_i", "_p_l", "_p_d", "_p_f"}; + FieldType[] fieldTypes = new FieldType[]{new IntPointField(), new LongPointField(), new DoublePointField(), new FloatPointField()}; + assert fieldTypeNames.length == fieldTypes.length; + for (int i = 0; i < fieldTypeNames.length; i++) { + SchemaField fieldIndexed = h.getCore().getLatestSchema().getField("foo_" + fieldTypeNames[i]); + SchemaField fieldIndexedAndDv = h.getCore().getLatestSchema().getField("foo_" + fieldTypeNames[i] + "_dv"); + SchemaField fieldIndexedMv = h.getCore().getLatestSchema().getField("foo_" + fieldTypeNames[i] + "_mv"); + SchemaField fieldIndexedAndDvMv = h.getCore().getLatestSchema().getField("foo_" + fieldTypeNames[i] + "_mv_dv"); + assertTrue(fieldTypes[i].getRangeQuery(null, fieldIndexed, "0", "10", true, true) instanceof PointRangeQuery); + assertTrue(fieldTypes[i].getRangeQuery(null, fieldIndexedAndDv, "0", "10", true, true) instanceof IndexOrDocValuesQuery); + assertTrue(fieldTypes[i].getRangeQuery(null, fieldIndexedMv, "0", "10", true, true) instanceof PointRangeQuery); + assertTrue(fieldTypes[i].getRangeQuery(null, fieldIndexedAndDvMv, "0", "10", true, true) instanceof IndexOrDocValuesQuery); + assertTrue(fieldTypes[i].getFieldQuery(null, fieldIndexed, "0") instanceof PointRangeQuery); + assertTrue(fieldTypes[i].getFieldQuery(null, fieldIndexedAndDv, "0") instanceof IndexOrDocValuesQuery); + assertTrue(fieldTypes[i].getFieldQuery(null, fieldIndexedMv, "0") instanceof PointRangeQuery); + assertTrue(fieldTypes[i].getFieldQuery(null, fieldIndexedAndDvMv, "0") instanceof IndexOrDocValuesQuery); + } + } + // Helper methods private String[] getRandomStringArrayWithDoubles(int length, boolean sorted) { @@ -803,14 +834,29 @@ public class TestPointFields extends SolrTestCaseJ4 { "//result/doc[1]/" + type + "[@name='" + fieldName + "'][.='0']", "//result/doc[10]/" + type + "[@name='" + fieldName + "'][.='9']"); + assertQ(req("q", fieldName + ":[0 TO 1] OR " + fieldName + ":[8 TO 9]" , "fl", "id, " + fieldName), + "//*[@numFound='4']", + "//result/doc[1]/" + type + "[@name='" + fieldName + "'][.='0']", + "//result/doc[2]/" + type + "[@name='" + fieldName + "'][.='1']", + "//result/doc[3]/" + type + "[@name='" + fieldName + "'][.='8']", + "//result/doc[4]/" + type + "[@name='" + fieldName + "'][.='9']"); + + assertQ(req("q", fieldName + ":[0 TO 1] AND " + fieldName + ":[1 TO 2]" , "fl", "id, " + fieldName), + "//*[@numFound='1']", + "//result/doc[1]/" + type + "[@name='" + fieldName + "'][.='1']"); + + assertQ(req("q", fieldName + ":[0 TO 1] AND NOT " + fieldName + ":[1 TO 2]" , "fl", "id, " + fieldName), + "//*[@numFound='1']", + "//result/doc[1]/" + type + "[@name='" + fieldName + "'][.='0']"); + clearIndex(); assertU(commit()); String[] arr; if (testLong) { - arr = getRandomStringArrayWithLongs(10, true); + arr = getRandomStringArrayWithLongs(100, true); } else { - arr = getRandomStringArrayWithInts(10, true); + arr = getRandomStringArrayWithInts(100, true); } for (int i = 0; i < arr.length; i++) { assertU(adoc("id", String.valueOf(i), fieldName, arr[i])); @@ -821,6 +867,8 @@ public class TestPointFields extends SolrTestCaseJ4 { "//*[@numFound='" + (i + 1) + "']"); assertQ(req("q", fieldName + ":{" + arr[0] + " TO " + arr[i] + "}", "fl", "id, " + fieldName), "//*[@numFound='" + (Math.max(0, i-1)) + "']"); + assertQ(req("q", fieldName + ":[" + arr[0] + " TO " + arr[i] + "] AND " + fieldName + ":" + arr[0].replace("-", "\\-"), "fl", "id, " + fieldName), + "//*[@numFound='1']"); } } @@ -1092,6 +1140,17 @@ public class TestPointFields extends SolrTestCaseJ4 { "//*[@numFound='10']", "//result/doc[1]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[0] + "']", "//result/doc[10]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[9] + "']"); + + assertQ(req("q", fieldName + ":[0 TO 1] OR " + fieldName + ":[8 TO 9]", "fl", "id, " + fieldName), + "//*[@numFound='4']", + "//result/doc[1]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[0] + "']", + "//result/doc[2]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[1] + "']", + "//result/doc[3]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[8] + "']", + "//result/doc[4]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[9] + "']"); + + assertQ(req("q", fieldName + ":[0 TO 0] AND " + fieldName + ":[10 TO 10]", "fl", "id, " + fieldName), + "//*[@numFound='1']", + "//result/doc[1]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[0] + "']"); } private void testPointFieldMultiValuedFacetField(String nonDocValuesField, String dvFieldName, String[] numbers) throws Exception { diff --git a/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java b/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java index 610e9982d4a..4699a6653c5 100644 --- a/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java +++ b/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java @@ -46,7 +46,8 @@ public class TestMaxScoreQueryParser extends AbstractSolrTestCase { assertEquals(new BoostQuery(new TermQuery(new Term("text", "foo")), 3f), q); q = parse("price:[0 TO 10]"); - assertTrue(q instanceof LegacyNumericRangeQuery || q instanceof PointRangeQuery); + assertTrue(q instanceof LegacyNumericRangeQuery + || (q instanceof IndexOrDocValuesQuery && ((IndexOrDocValuesQuery)q).getIndexQuery() instanceof PointRangeQuery)); } @Test