Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public abstract class FieldProperties {
protected static final int USE_DOCVALUES_AS_STORED = 0b100000000000000000;
protected static final int LARGE_FIELD = 0b1000000000000000000;
protected static final int UNINVERTIBLE = 0b10000000000000000000;
protected static final int DOC_VALUES_SKIP_LIST = 0b100000000000000000000;

static final String[] propertyNames = {
"indexed",
Expand All @@ -73,7 +74,8 @@ public abstract class FieldProperties {
"termPayloads",
"useDocValuesAsStored",
"large",
"uninvertible"
"uninvertible",
"skipList"
};

static final Map<String, Integer> propertyMap = new HashMap<>();
Expand Down
32 changes: 32 additions & 0 deletions solr/core/src/java/org/apache/solr/schema/FieldType.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.DocValuesSkipIndexType;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.IndexableFieldType;
import org.apache.lucene.index.Term;
Expand Down Expand Up @@ -1148,6 +1150,26 @@ public void checkSchemaField(final SchemaField field) {
if (field.hasDocValues()) {
checkSupportsDocValues();
}
if (field.docValuesSkipIndexType() != DocValuesSkipIndexType.NONE) {
if (!field.hasDocValues()) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"Field " + field.getName() + " cannot use skipList=true without docValues=true");
}
final DocValuesType docValuesType = getDocValuesTypeForSkipIndex(field);
if (docValuesType != DocValuesType.NUMERIC && docValuesType != DocValuesType.SORTED_NUMERIC) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"Field "
+ field.getName()
+ " of type "
+ this
+ " cannot use skipList=true because it is currently only supported on PointField"
+ "-based numeric and date fields; docValues type "
+ docValuesType
+ " is unsupported");
}
}
if (field.isLarge() && field.multiValued()) {
throw new SolrException(
ErrorCode.SERVER_ERROR, "Field type " + this + " is 'large'; can't support multiValued");
Expand All @@ -1167,6 +1189,16 @@ protected void checkSupportsDocValues() {
ErrorCode.SERVER_ERROR, "Field type " + this + " does not support doc values");
}

/**
* Returns the concrete docValues type used for the field when indexing. Field types that support
* {@code skipList=true} must override this method so schema validation can reject unsupported
* docValues shapes during core load. The default implementation means the field type does not
* currently support {@code skipList=true}.
*/
protected DocValuesType getDocValuesTypeForSkipIndex(SchemaField field) {
return DocValuesType.NONE;
}

/**
* Returns whether this field type should enable docValues by default for schemaVersion &gt;= 1.7.
* This should not be enabled for fields that did not have docValues implemented by Solr 9.7, as
Expand Down
16 changes: 14 additions & 2 deletions solr/core/src/java/org/apache/solr/schema/PointField.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.IndexOrDocValuesQuery;
Expand Down Expand Up @@ -292,7 +293,10 @@ public List<IndexableField> createFields(SchemaField sf, Object value) {
assert numericValue instanceof Double;
bits = Double.doubleToLongBits(numericValue.doubleValue());
}
fields.add(new NumericDocValuesField(sf.getName(), bits));
fields.add(
sf.hasDocValuesSkipList()
? NumericDocValuesField.indexedField(sf.getName(), bits)
: new NumericDocValuesField(sf.getName(), bits));
} else {
// MultiValued
if (numericValue instanceof Integer || numericValue instanceof Long) {
Expand All @@ -303,7 +307,10 @@ public List<IndexableField> createFields(SchemaField sf, Object value) {
assert numericValue instanceof Double;
bits = NumericUtils.doubleToSortableLong(numericValue.doubleValue());
}
fields.add(new SortedNumericDocValuesField(sf.getName(), bits));
fields.add(
sf.hasDocValuesSkipList()
? SortedNumericDocValuesField.indexedField(sf.getName(), bits)
: new SortedNumericDocValuesField(sf.getName(), bits));
}
}
if (sf.stored()) {
Expand All @@ -314,6 +321,11 @@ public List<IndexableField> createFields(SchemaField sf, Object value) {

protected abstract StoredField getStoredField(SchemaField sf, Object value);

@Override
protected DocValuesType getDocValuesTypeForSkipIndex(SchemaField field) {
return field.multiValued() ? DocValuesType.SORTED_NUMERIC : DocValuesType.NUMERIC;
}

@Override
public SortField getSortField(SchemaField field, boolean top) {
return getNumericSort(field, getNumberType(), top);
Expand Down
7 changes: 6 additions & 1 deletion solr/core/src/java/org/apache/solr/schema/SchemaField.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ public String getDocValuesFormat() {
return (String) args.getOrDefault(DOC_VALUES_FORMAT, type.getDocValuesFormat());
}

public boolean hasDocValuesSkipList() {
return (properties & DOC_VALUES_SKIP_LIST) != 0;
}

/**
* Sanity checks that the properties of this field type are plausible for a field that may be used
* in sorting, throwing an appropriate exception (including the field name) if it is not.
Expand Down Expand Up @@ -466,6 +470,7 @@ public SimpleOrderedMap<Object> getNamedPropertyValues(boolean showDefaults) {
properties.add(getPropertyName(REQUIRED), isRequired());
properties.add(getPropertyName(TOKENIZED), isTokenized());
properties.add(getPropertyName(USE_DOCVALUES_AS_STORED), useDocValuesAsStored());
properties.add(getPropertyName(DOC_VALUES_SKIP_LIST), hasDocValuesSkipList());
// The BINARY property is always false
// properties.add(getPropertyName(BINARY), isBinary());
} else {
Expand Down Expand Up @@ -534,7 +539,7 @@ public DocValuesType docValuesType() {

@Override
public DocValuesSkipIndexType docValuesSkipIndexType() {
return DocValuesSkipIndexType.NONE;
return hasDocValuesSkipList() ? DocValuesSkipIndexType.RANGE : DocValuesSkipIndexType.NONE;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" ?>
<!--
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.
-->

<schema name="bad-schema-skip-list-unsupported" version="1.7">
<fieldType name="string" class="solr.StrField" />

<field name="id" type="string" stored="false" indexed="false" docValues="true" skipList="true"/>
</schema>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<fieldType name="string_disk" class="solr.StrField" />

<fieldType name="string" class="solr.StrField"/>
<fieldType name="pint" class="solr.IntPointField"/>
<fieldType name="plong" class="solr.LongPointField"/>

<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
Expand All @@ -41,6 +43,8 @@
<field name="string_standard_f" type="string_standard" indexed="true" stored="true"/>

<field name="string_disk_f" type="string_disk" indexed="false" stored="false" default=""/>
<field name="int_skip_f" type="pint" indexed="false" stored="false" docValues="true" skipList="true"/>
<field name="long_skip_mv_f" type="plong" indexed="false" stored="false" docValues="true" multiValued="true" skipList="true"/>

<field name="string_f" type="string" indexed="true" stored="true" required="true"/>
<field name="text" type="text_general" indexed="true" stored="true"/>
Expand All @@ -49,6 +53,8 @@
<dynamicField name="*_standard" type="string_standard" indexed="true" stored="true"/>

<dynamicField name="*_disk" type="string_disk" indexed="false" stored="false"/>
<dynamicField name="*_skip_i" type="pint" indexed="false" stored="false" docValues="true" skipList="true"/>
<dynamicField name="*_skip_l" type="plong" indexed="false" stored="false" docValues="true" multiValued="true" skipList="true"/>

<uniqueKey>string_f</uniqueKey>
</schema>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<fieldType name="str_none" class="solr.StrField"/>
<fieldType name="str_direct_asserting" class="solr.StrField" postingsFormat="Direct" docValuesFormat="Asserting"/>
<fieldType name="str_standard_simple" class="solr.StrField" postingsFormat="Lucene84" docValuesFormat="Lucene80"/>
<fieldType name="pint" class="solr.IntPointField"/>
<fieldType name="plong" class="solr.LongPointField"/>

<field name="str_none_f" type="str_none"/>
<field name="str_direct_asserting_f" type="str_direct_asserting"/>
Expand All @@ -30,12 +32,16 @@

<field name="str_none_asserting_f" type="str_none" docValuesFormat="Asserting"/>
<field name="str_standard_asserting_f" type="str_standard_simple" docValuesFormat="Asserting"/>
<field name="int_skip_f" type="pint" indexed="false" stored="false" docValues="true" skipList="true"/>
<field name="long_skip_mv_f" type="plong" indexed="false" stored="false" docValues="true" multiValued="true" skipList="true"/>

<dynamicField name="*_lucene80" type="str_direct_asserting" postingsFormat="Lucene80"/>
<dynamicField name="*_direct" type="str_direct_asserting"/>
<dynamicField name="*_lucene70" type="str_none" postingsFormat="Lucene70"/>

<dynamicField name="*_asserting" type="str_none" docValuesFormat="Asserting"/>
<dynamicField name="*_simple" type="str_direct_asserting" docValuesFormat="Lucene80"/>
<dynamicField name="*_skip_i" type="pint" indexed="false" stored="false" docValues="true" skipList="true"/>
<dynamicField name="*_skip_l" type="plong" indexed="false" stored="false" docValues="true" multiValued="true" skipList="true"/>

</schema>
22 changes: 22 additions & 0 deletions solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.apache.lucene.codecs.lucene104.Lucene104Codec;
import org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat;
import org.apache.lucene.codecs.perfield.PerFieldPostingsFormat;
import org.apache.lucene.index.DocValuesSkipIndexType;
import org.apache.lucene.index.FieldInfos;
import org.apache.lucene.index.SegmentInfo;
import org.apache.lucene.index.SegmentInfos;
import org.apache.lucene.tests.util.TestUtil;
Expand Down Expand Up @@ -107,6 +109,26 @@ public void testDynamicFieldsDocValuesFormats() {
assertEquals("Asserting", format.getDocValuesFormatForField("bar_direct").getName());
}

public void testDocValuesSkipListPersistsFieldInfo() throws Exception {
assertU(delQ("*:*"));
assertU(commit());
assertU(add(doc("string_f", "id", "int_skip_f", "7", "long_skip_mv_f", "11")));
assertU(commit());

h.getCore()
.withSearcher(
searcher -> {
FieldInfos fieldInfos = FieldInfos.getMergedFieldInfos(searcher.getIndexReader());
assertEquals(
DocValuesSkipIndexType.RANGE,
fieldInfos.fieldInfo("int_skip_f").docValuesSkipIndexType());
assertEquals(
DocValuesSkipIndexType.RANGE,
fieldInfos.fieldInfo("long_skip_mv_f").docValuesSkipIndexType());
return null;
});
}

private void reloadCoreAndRecreateIndex() {
h.getCoreContainer().reload(h.coreName);
assertU(delQ("*:*"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void testGetField() {
assertQ(
"/schema/fields/test_postv?indent=on&wt=xml&showDefaults=true",
"count(/response/lst[@name='field']) = 1",
"count(/response/lst[@name='field']/*) = 19",
"count(/response/lst[@name='field']/*) = 20",
"/response/lst[@name='field']/str[@name='name'] = 'test_postv'",
"/response/lst[@name='field']/str[@name='type'] = 'text'",
"/response/lst[@name='field']/bool[@name='indexed'] = 'true'",
Expand All @@ -44,7 +44,8 @@ public void testGetField() {
"/response/lst[@name='field']/bool[@name='large'] = 'false'",
"/response/lst[@name='field']/bool[@name='required'] = 'false'",
"/response/lst[@name='field']/bool[@name='tokenized'] = 'true'",
"/response/lst[@name='field']/bool[@name='useDocValuesAsStored'] = 'true'");
"/response/lst[@name='field']/bool[@name='useDocValuesAsStored'] = 'true'",
"/response/lst[@name='field']/bool[@name='skipList'] = 'false'");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ public void testDocValuesUnsupported() throws Exception {
doTest("bad-schema-unsupported-docValues.xml", "does not support doc values");
}

public void testDocValuesSkipListUnsupported() throws Exception {
doTest(
"bad-schema-unsupported-skip-list.xml",
"currently only supported on PointField-based numeric and date fields");
}

public void testRootTypeMissmatchWithUniqueKey() throws Exception {
doTest(
"bad-schema-uniquekey-diff-type-root.xml",
Expand Down
19 changes: 19 additions & 0 deletions solr/core/src/test/org/apache/solr/schema/TestSchemaField.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public void testFields() {

assertFieldFormats("str_none_asserting_f", null, "Asserting");
assertFieldFormats("str_standard_asserting_f", "Lucene84", "Asserting");
assertFieldHasSkipList("int_skip_f", true);
assertFieldHasSkipList("long_skip_mv_f", true);
}

public void testDynamicFields() {
Expand All @@ -84,6 +86,23 @@ public void testDynamicFields() {

assertFieldFormats("any_asserting", null, "Asserting");
assertFieldFormats("any_simple", "Direct", "Lucene80");
assertFieldHasSkipList("any_skip_i", true);
assertFieldHasSkipList("any_skip_l", true);
}

private void assertFieldHasSkipList(String fieldName, boolean expectedSkipList) {
SchemaField field = h.getCore().getLatestSchema().getField(fieldName);
assertNotNull("Field " + fieldName + " not found - schema got changed?", field);
final String skipListPropertyName =
FieldProperties.getPropertyName(FieldProperties.DOC_VALUES_SKIP_LIST);
assertEquals(
"Field " + field.getName() + " wrong " + skipListPropertyName + " value",
expectedSkipList,
field.hasDocValuesSkipList());
assertEquals(
"Field " + field.getName() + " wrong schema property value for " + skipListPropertyName,
expectedSkipList,
field.getNamedPropertyValues(true).get(skipListPropertyName));
}

private void assertFieldFormats(
Expand Down
Loading