SOLR-10143: PointFields will create IndexOrDocValuesQuery when a field is both, indexed=true and docValues=true

This commit is contained in:
Tomas Fernandez Lobbe 2017-02-22 10:28:53 -08:00
parent 6ddf3693bb
commit 21690f5e12
5 changed files with 83 additions and 9 deletions

View File

@ -28,6 +28,7 @@ import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.StoredField; import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortedNumericSelector; import org.apache.lucene.search.SortedNumericSelector;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
@ -117,6 +118,10 @@ public abstract class PointField extends NumericFieldType {
if (!field.indexed() && field.hasDocValues()) { if (!field.indexed() && field.hasDocValues()) {
// currently implemented as singleton range // currently implemented as singleton range
return getRangeQuery(parser, field, externalVal, externalVal, true, true); 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 { } else {
return getExactQuery(field, externalVal); return getExactQuery(field, externalVal);
} }
@ -132,6 +137,10 @@ public abstract class PointField extends NumericFieldType {
boolean maxInclusive) { boolean maxInclusive) {
if (!field.indexed() && field.hasDocValues()) { if (!field.indexed() && field.hasDocValues()) {
return getDocValuesRangeQuery(parser, field, min, max, minInclusive, maxInclusive); 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 { } else {
return getPointRangeQuery(parser, field, min, max, minInclusive, maxInclusive); return getPointRangeQuery(parser, field, min, max, minInclusive, maxInclusive);
} }

View File

@ -395,7 +395,7 @@
<fieldType name="x" class="solr.PointType" dimension="1" subFieldType="double"/> <fieldType name="x" class="solr.PointType" dimension="1" subFieldType="double"/>
<fieldType name="tenD" class="solr.PointType" dimension="10" subFieldType="double"/> <fieldType name="tenD" class="solr.PointType" dimension="10" subFieldType="double"/>
<!-- Use the sub field suffix --> <!-- Use the sub field suffix -->
<fieldType name="xyd" class="solr.PointType" dimension="2" subFieldSuffix="_d1"/> <fieldType name="xyd" class="solr.PointType" dimension="2" subFieldSuffix="_d1_ndv"/>
<fieldType name="geohash" class="solr.GeoHashField"/> <fieldType name="geohash" class="solr.GeoHashField"/>
@ -620,6 +620,7 @@
<dynamicField name="*_f1" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true" multiValued="false"/> <dynamicField name="*_f1" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="*_d" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true"/> <dynamicField name="*_d" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true"/>
<dynamicField name="*_d1" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true" multiValued="false"/> <dynamicField name="*_d1" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="*_d1_ndv" type="${solr.tests.doubleClass:pdouble}" indexed="true" docValues="false" stored="true" multiValued="false"/>
<dynamicField name="*_dt" type="date" indexed="true" stored="true"/> <dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
<dynamicField name="*_dt1" type="date" indexed="true" stored="true" multiValued="false"/> <dynamicField name="*_dt1" type="date" indexed="true" stored="true" multiValued="false"/>

View File

@ -111,14 +111,18 @@ public class PolyFieldTest extends SolrTestCaseJ4 {
// //
} }
//
SchemaField s1 = schema.getField("test_p"); SchemaField s1 = schema.getField("test_p");
SchemaField s2 = schema.getField("test_p"); SchemaField s2 = schema.getField("test_p");
// 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 v1 = s1.getType().getValueSource(s1, null);
ValueSource v2 = s2.getType().getValueSource(s2, null); ValueSource v2 = s2.getType().getValueSource(s2, null);
assertEquals(v1, v2); assertEquals(v1, v2);
assertEquals(v1.hashCode(), v2.hashCode()); assertEquals(v1.hashCode(), v2.hashCode());
} }
}
@Test @Test
public void testSearching() throws Exception { public void testSearching() throws Exception {

View File

@ -21,6 +21,8 @@ import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; 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.SolrTestCaseJ4;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.junit.After; import org.junit.After;
@ -71,6 +73,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testIntPointFieldRangeQuery() throws Exception { public void testIntPointFieldRangeQuery() throws Exception {
doTestIntPointFieldRangeQuery("number_p_i", "int", false); doTestIntPointFieldRangeQuery("number_p_i", "int", false);
doTestIntPointFieldRangeQuery("number_p_i_ni_ns_dv", "int", false); doTestIntPointFieldRangeQuery("number_p_i_ni_ns_dv", "int", false);
doTestIntPointFieldRangeQuery("number_p_i_dv", "int", false);
} }
@Test @Test
@ -120,6 +123,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testIntPointFieldMultiValuedRangeQuery() throws Exception { public void testIntPointFieldMultiValuedRangeQuery() throws Exception {
testPointFieldMultiValuedRangeQuery("number_p_i_mv", "int", getSequentialStringArrayWithInts(20)); testPointFieldMultiValuedRangeQuery("number_p_i_mv", "int", getSequentialStringArrayWithInts(20));
testPointFieldMultiValuedRangeQuery("number_p_i_ni_mv_dv", "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? //TODO MV SORT?
@ -198,6 +202,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testDoublePointFieldRangeQuery() throws Exception { public void testDoublePointFieldRangeQuery() throws Exception {
doTestFloatPointFieldRangeQuery("number_p_d", "double", true); doTestFloatPointFieldRangeQuery("number_p_d", "double", true);
doTestFloatPointFieldRangeQuery("number_p_d_ni_ns_dv", "double", true); doTestFloatPointFieldRangeQuery("number_p_d_ni_ns_dv", "double", true);
doTestFloatPointFieldRangeQuery("number_p_d_dv", "double", true);
} }
@Test @Test
@ -249,6 +254,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testDoublePointFieldMultiValuedRangeQuery() throws Exception { public void testDoublePointFieldMultiValuedRangeQuery() throws Exception {
testPointFieldMultiValuedRangeQuery("number_p_d_mv", "double", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_d_mv", "double", getSequentialStringArrayWithDoubles(20));
testPointFieldMultiValuedRangeQuery("number_p_d_ni_mv_dv", "double", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_d_ni_mv_dv", "double", getSequentialStringArrayWithDoubles(20));
testPointFieldMultiValuedRangeQuery("number_p_d_mv_dv", "double", getSequentialStringArrayWithDoubles(20));
} }
@Test @Test
@ -360,6 +366,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testFloatPointFieldRangeQuery() throws Exception { public void testFloatPointFieldRangeQuery() throws Exception {
doTestFloatPointFieldRangeQuery("number_p_f", "float", false); doTestFloatPointFieldRangeQuery("number_p_f", "float", false);
doTestFloatPointFieldRangeQuery("number_p_f_ni_ns_dv", "float", false); doTestFloatPointFieldRangeQuery("number_p_f_ni_ns_dv", "float", false);
doTestFloatPointFieldRangeQuery("number_p_f_dv", "float", false);
} }
@Test @Test
@ -411,6 +418,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testFloatPointFieldMultiValuedRangeQuery() throws Exception { public void testFloatPointFieldMultiValuedRangeQuery() throws Exception {
testPointFieldMultiValuedRangeQuery("number_p_f_mv", "float", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_f_mv", "float", getSequentialStringArrayWithDoubles(20));
testPointFieldMultiValuedRangeQuery("number_p_f_ni_mv_dv", "float", getSequentialStringArrayWithDoubles(20)); testPointFieldMultiValuedRangeQuery("number_p_f_ni_mv_dv", "float", getSequentialStringArrayWithDoubles(20));
testPointFieldMultiValuedRangeQuery("number_p_f_mv_dv", "float", getSequentialStringArrayWithDoubles(20));
} }
@Test @Test
@ -481,6 +489,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testLongPointFieldRangeQuery() throws Exception { public void testLongPointFieldRangeQuery() throws Exception {
doTestIntPointFieldRangeQuery("number_p_l", "long", true); doTestIntPointFieldRangeQuery("number_p_l", "long", true);
doTestIntPointFieldRangeQuery("number_p_l_ni_ns_dv", "long", true); doTestIntPointFieldRangeQuery("number_p_l_ni_ns_dv", "long", true);
doTestIntPointFieldRangeQuery("number_p_l_dv", "long", true);
} }
@Test @Test
@ -533,6 +542,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
public void testLongPointFieldMultiValuedRangeQuery() throws Exception { public void testLongPointFieldMultiValuedRangeQuery() throws Exception {
testPointFieldMultiValuedRangeQuery("number_p_l_mv", "long", getSequentialStringArrayWithInts(20)); testPointFieldMultiValuedRangeQuery("number_p_l_mv", "long", getSequentialStringArrayWithInts(20));
testPointFieldMultiValuedRangeQuery("number_p_l_ni_mv_dv", "long", getSequentialStringArrayWithInts(20)); testPointFieldMultiValuedRangeQuery("number_p_l_ni_mv_dv", "long", getSequentialStringArrayWithInts(20));
testPointFieldMultiValuedRangeQuery("number_p_l_mv_dv", "long", getSequentialStringArrayWithInts(20));
} }
@Test @Test
@ -578,6 +588,27 @@ public class TestPointFields extends SolrTestCaseJ4 {
doTestSetQueries("number_p_l_ni_dv", getRandomStringArrayWithLongs(10, false), false); 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 // Helper methods
private String[] getRandomStringArrayWithDoubles(int length, boolean sorted) { 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[1]/" + type + "[@name='" + fieldName + "'][.='0']",
"//result/doc[10]/" + type + "[@name='" + fieldName + "'][.='9']"); "//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(); clearIndex();
assertU(commit()); assertU(commit());
String[] arr; String[] arr;
if (testLong) { if (testLong) {
arr = getRandomStringArrayWithLongs(10, true); arr = getRandomStringArrayWithLongs(100, true);
} else { } else {
arr = getRandomStringArrayWithInts(10, true); arr = getRandomStringArrayWithInts(100, true);
} }
for (int i = 0; i < arr.length; i++) { for (int i = 0; i < arr.length; i++) {
assertU(adoc("id", String.valueOf(i), fieldName, arr[i])); assertU(adoc("id", String.valueOf(i), fieldName, arr[i]));
@ -821,6 +867,8 @@ public class TestPointFields extends SolrTestCaseJ4 {
"//*[@numFound='" + (i + 1) + "']"); "//*[@numFound='" + (i + 1) + "']");
assertQ(req("q", fieldName + ":{" + arr[0] + " TO " + arr[i] + "}", "fl", "id, " + fieldName), assertQ(req("q", fieldName + ":{" + arr[0] + " TO " + arr[i] + "}", "fl", "id, " + fieldName),
"//*[@numFound='" + (Math.max(0, i-1)) + "']"); "//*[@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']", "//*[@numFound='10']",
"//result/doc[1]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[0] + "']", "//result/doc[1]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[0] + "']",
"//result/doc[10]/arr[@name='" + fieldName + "']/" + type + "[1][.='" + numbers[9] + "']"); "//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 { private void testPointFieldMultiValuedFacetField(String nonDocValuesField, String dvFieldName, String[] numbers) throws Exception {

View File

@ -46,7 +46,8 @@ public class TestMaxScoreQueryParser extends AbstractSolrTestCase {
assertEquals(new BoostQuery(new TermQuery(new Term("text", "foo")), 3f), q); assertEquals(new BoostQuery(new TermQuery(new Term("text", "foo")), 3f), q);
q = parse("price:[0 TO 10]"); 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 @Test