LUCENE-10087: Validate number of dimensions and bytes per dimension for numeric SortFields. (#283)

This commit is contained in:
Adrien Grand 2021-09-07 13:28:39 +02:00 committed by GitHub
parent bc161e6dcc
commit 7eb35be045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 4 deletions

View File

@ -19,6 +19,10 @@ package org.apache.lucene.search;
import java.io.IOException; import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.Objects; import java.util.Objects;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexSorter; import org.apache.lucene.index.IndexSorter;
import org.apache.lucene.index.SortFieldProvider; import org.apache.lucene.index.SortFieldProvider;
@ -68,25 +72,25 @@ public class SortField {
/** /**
* Sort using term values as encoded Integers. Sort values are Integer and lower values are at * Sort using term values as encoded Integers. Sort values are Integer and lower values are at
* the front. * the front. Fields must either be not indexed, or indexed with {@link IntPoint}.
*/ */
INT, INT,
/** /**
* Sort using term values as encoded Floats. Sort values are Float and lower values are at the * Sort using term values as encoded Floats. Sort values are Float and lower values are at the
* front. * front. Fields must either be not indexed, or indexed with {@link FloatPoint}.
*/ */
FLOAT, FLOAT,
/** /**
* Sort using term values as encoded Longs. Sort values are Long and lower values are at the * Sort using term values as encoded Longs. Sort values are Long and lower values are at the
* front. * front. Fields must either be not indexed, or indexed with {@link LongPoint}.
*/ */
LONG, LONG,
/** /**
* Sort using term values as encoded Doubles. Sort values are Double and lower values are at the * Sort using term values as encoded Doubles. Sort values are Double and lower values are at the
* front. * front. Fields must either be not indexed, or indexed with {@link DoublePoint}.
*/ */
DOUBLE, DOUBLE,

View File

@ -20,6 +20,7 @@ package org.apache.lucene.search.comparators;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.PointValues; import org.apache.lucene.index.PointValues;
@ -90,6 +91,26 @@ public abstract class NumericComparator<T extends Number> extends FieldComparato
this.docValues = getNumericDocValues(context, field); this.docValues = getNumericDocValues(context, field);
this.pointValues = canSkipDocuments ? context.reader().getPointValues(field) : null; this.pointValues = canSkipDocuments ? context.reader().getPointValues(field) : null;
if (pointValues != null) { if (pointValues != null) {
FieldInfo info = context.reader().getFieldInfos().fieldInfo(field);
if (info == null || info.getPointDimensionCount() == 0) {
throw new IllegalStateException(
"Field "
+ field
+ " doesn't index points according to FieldInfos yet returns non-null PointValues");
} else if (info.getPointDimensionCount() > 1) {
throw new IllegalArgumentException(
"Field " + field + " is indexed with multiple dimensions, sorting is not supported");
} else if (info.getPointNumBytes() != bytesCount) {
throw new IllegalArgumentException(
"Field "
+ field
+ " is indexed with "
+ info.getPointNumBytes()
+ " bytes per dimension, but "
+ NumericComparator.this
+ " expected "
+ bytesCount);
}
this.enableSkipping = true; // skipping is enabled when points are available this.enableSkipping = true; // skipping is enabled when points are available
this.maxDoc = context.reader().maxDoc(); this.maxDoc = context.reader().maxDoc();
this.maxValueAsBytes = this.maxValueAsBytes =

View File

@ -25,6 +25,7 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.FloatDocValuesField; import org.apache.lucene.document.FloatDocValuesField;
import org.apache.lucene.document.FloatPoint; import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.IntRange;
import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField; import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StoredField; import org.apache.lucene.document.StoredField;
@ -33,6 +34,7 @@ import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
@ -583,4 +585,49 @@ public class TestSortOptimization extends LuceneTestCase {
reader.close(); reader.close();
dir.close(); dir.close();
} }
public void testPointValidation() throws IOException {
final Directory dir = newDirectory();
final RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document doc = new Document();
doc.add(new IntPoint("intField", 4));
doc.add(new NumericDocValuesField("intField", 4));
doc.add(new LongPoint("longField", 42));
doc.add(new NumericDocValuesField("longField", 42));
doc.add(new IntRange("intRange", new int[] {1}, new int[] {10}));
doc.add(new NumericDocValuesField("intRange", 4));
writer.addDocument(doc);
IndexReader reader = writer.getReader();
writer.close();
IndexSearcher searcher = newSearcher(reader);
assertThrows(
IllegalArgumentException.class,
() ->
searcher.search(
new MatchAllDocsQuery(),
1,
new Sort(new SortField("intField", SortField.Type.LONG))));
assertThrows(
IllegalArgumentException.class,
() ->
searcher.search(
new MatchAllDocsQuery(),
1,
new Sort(new SortField("longField", SortField.Type.INT))));
assertThrows(
IllegalArgumentException.class,
() ->
searcher.search(
new MatchAllDocsQuery(),
1,
new Sort(new SortField("intRange", SortField.Type.INT))));
reader.close();
dir.close();
}
} }