Skip to content

Commit b9eeebd

Browse files
authored
Fix NPE when executing doc value queries over shape geometries with empty segments (elastic#112139) (elastic#112198)
Return empty scorer instead of null.
1 parent dc56dfe commit b9eeebd

File tree

4 files changed

+82
-12
lines changed

4 files changed

+82
-12
lines changed

docs/changelog/112139.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 112139
2+
summary: Fix NPE when executing doc value queries over shape geometries with empty
3+
segments
4+
area: Geo
5+
type: bug
6+
issues: []

server/src/main/java/org/elasticsearch/lucene/spatial/ShapeDocValuesQuery.java

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.apache.lucene.index.LeafReaderContext;
1616
import org.apache.lucene.search.ConstantScoreScorer;
1717
import org.apache.lucene.search.ConstantScoreWeight;
18+
import org.apache.lucene.search.DocIdSetIterator;
1819
import org.apache.lucene.search.IndexSearcher;
1920
import org.apache.lucene.search.Query;
2021
import org.apache.lucene.search.QueryVisitor;
@@ -109,11 +110,7 @@ private ConstantScoreWeight getStandardWeight(ScoreMode scoreMode, float boost)
109110

110111
@Override
111112
public Scorer scorer(LeafReaderContext context) throws IOException {
112-
final ScorerSupplier scorerSupplier = scorerSupplier(context);
113-
if (scorerSupplier == null) {
114-
return null;
115-
}
116-
return scorerSupplier.get(Long.MAX_VALUE);
113+
return scorerSupplier(context).get(Long.MAX_VALUE);
117114
}
118115

119116
@Override
@@ -127,7 +124,7 @@ public Scorer get(long leadCost) throws IOException {
127124
// binary doc values allocate an array upfront, lets only allocate it if we are going to use it
128125
final BinaryDocValues values = context.reader().getBinaryDocValues(field);
129126
if (values == null) {
130-
return null;
127+
return new ConstantScoreScorer(weight, 0f, scoreMode, DocIdSetIterator.empty());
131128
}
132129
final GeometryDocValueReader reader = new GeometryDocValueReader();
133130
final Component2DVisitor visitor = Component2DVisitor.getVisitor(component2D, relation, encoder);
@@ -171,11 +168,7 @@ private ConstantScoreWeight getContainsWeight(ScoreMode scoreMode, float boost)
171168

172169
@Override
173170
public Scorer scorer(LeafReaderContext context) throws IOException {
174-
final ScorerSupplier scorerSupplier = scorerSupplier(context);
175-
if (scorerSupplier == null) {
176-
return null;
177-
}
178-
return scorerSupplier.get(Long.MAX_VALUE);
171+
return scorerSupplier(context).get(Long.MAX_VALUE);
179172
}
180173

181174
@Override
@@ -189,7 +182,7 @@ public Scorer get(long leadCost) throws IOException {
189182
// binary doc values allocate an array upfront, lets only allocate it if we are going to use it
190183
final BinaryDocValues values = context.reader().getBinaryDocValues(field);
191184
if (values == null) {
192-
return null;
185+
return new ConstantScoreScorer(weight, 0f, scoreMode, DocIdSetIterator.empty());
193186
}
194187
final Component2DVisitor[] visitors = new Component2DVisitor[components2D.size()];
195188
for (int i = 0; i < components2D.size(); i++) {

server/src/test/java/org/elasticsearch/lucene/spatial/CartesianShapeDocValuesQueryTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.lucene.index.IndexWriter;
2020
import org.apache.lucene.index.IndexWriterConfig;
2121
import org.apache.lucene.index.IndexableField;
22+
import org.apache.lucene.index.NoMergeScheduler;
2223
import org.apache.lucene.index.SerialMergeScheduler;
2324
import org.apache.lucene.search.IndexSearcher;
2425
import org.apache.lucene.search.Query;
@@ -30,6 +31,7 @@
3031
import org.elasticsearch.geo.ShapeTestUtils;
3132
import org.elasticsearch.geo.XShapeTestUtil;
3233
import org.elasticsearch.geometry.Geometry;
34+
import org.elasticsearch.index.mapper.ShapeIndexer;
3335
import org.elasticsearch.test.ESTestCase;
3436

3537
import java.io.IOException;
@@ -54,6 +56,40 @@ public void testEqualsAndHashcode() {
5456
QueryUtils.checkUnequal(q1, q4);
5557
}
5658

59+
public void testEmptySegment() throws Exception {
60+
IndexWriterConfig iwc = newIndexWriterConfig();
61+
// No merges
62+
iwc.setMergeScheduler(NoMergeScheduler.INSTANCE);
63+
Directory dir = newDirectory();
64+
IndexWriter w = new IndexWriter(dir, iwc);
65+
ShapeIndexer indexer = new CartesianShapeIndexer(FIELD_NAME);
66+
Geometry geometry = new org.elasticsearch.geometry.Point(0, 0);
67+
Document document = new Document();
68+
List<IndexableField> fields = indexer.indexShape(geometry);
69+
for (IndexableField field : fields) {
70+
document.add(field);
71+
}
72+
BinaryShapeDocValuesField docVal = new BinaryShapeDocValuesField(FIELD_NAME, CoordinateEncoder.CARTESIAN);
73+
docVal.add(fields, geometry);
74+
document.add(docVal);
75+
w.addDocument(document);
76+
w.flush();
77+
// add empty segment
78+
w.addDocument(new Document());
79+
w.flush();
80+
final IndexReader r = DirectoryReader.open(w);
81+
w.close();
82+
83+
IndexSearcher s = newSearcher(r);
84+
XYRectangle rectangle = new XYRectangle(-10, 10, -10, 10);
85+
for (ShapeField.QueryRelation relation : ShapeField.QueryRelation.values()) {
86+
Query indexQuery = XYShape.newGeometryQuery(FIELD_NAME, relation, rectangle);
87+
Query docValQuery = new CartesianShapeDocValuesQuery(FIELD_NAME, relation, rectangle);
88+
assertQueries(s, indexQuery, docValQuery, 1);
89+
}
90+
IOUtils.close(r, dir);
91+
}
92+
5793
public void testIndexSimpleShapes() throws Exception {
5894
IndexWriterConfig iwc = newIndexWriterConfig();
5995
// Else seeds may not reproduce:

server/src/test/java/org/elasticsearch/lucene/spatial/LatLonShapeDocValuesQueryTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.lucene.index.IndexWriter;
2121
import org.apache.lucene.index.IndexWriterConfig;
2222
import org.apache.lucene.index.IndexableField;
23+
import org.apache.lucene.index.NoMergeScheduler;
2324
import org.apache.lucene.index.SerialMergeScheduler;
2425
import org.apache.lucene.search.IndexSearcher;
2526
import org.apache.lucene.search.Query;
@@ -56,6 +57,40 @@ public void testEqualsAndHashcode() {
5657
QueryUtils.checkUnequal(q1, q4);
5758
}
5859

60+
public void testEmptySegment() throws Exception {
61+
IndexWriterConfig iwc = newIndexWriterConfig();
62+
// No merges
63+
iwc.setMergeScheduler(NoMergeScheduler.INSTANCE);
64+
Directory dir = newDirectory();
65+
IndexWriter w = new IndexWriter(dir, iwc);
66+
GeoShapeIndexer indexer = new GeoShapeIndexer(Orientation.CCW, FIELD_NAME);
67+
Geometry geometry = new org.elasticsearch.geometry.Point(0, 0);
68+
Document document = new Document();
69+
List<IndexableField> fields = indexer.indexShape(geometry);
70+
for (IndexableField field : fields) {
71+
document.add(field);
72+
}
73+
BinaryShapeDocValuesField docVal = new BinaryShapeDocValuesField(FIELD_NAME, CoordinateEncoder.GEO);
74+
docVal.add(fields, geometry);
75+
document.add(docVal);
76+
w.addDocument(document);
77+
w.flush();
78+
// add empty segment
79+
w.addDocument(new Document());
80+
w.flush();
81+
final IndexReader r = DirectoryReader.open(w);
82+
w.close();
83+
84+
IndexSearcher s = newSearcher(r);
85+
Rectangle rectangle = new Rectangle(-10, 10, -10, 10);
86+
for (ShapeField.QueryRelation relation : ShapeField.QueryRelation.values()) {
87+
Query indexQuery = LatLonShape.newGeometryQuery(FIELD_NAME, relation, rectangle);
88+
Query docValQuery = new LatLonShapeDocValuesQuery(FIELD_NAME, relation, rectangle);
89+
assertQueries(s, indexQuery, docValQuery, 1);
90+
}
91+
IOUtils.close(r, dir);
92+
}
93+
5994
public void testIndexSimpleShapes() throws Exception {
6095
IndexWriterConfig iwc = newIndexWriterConfig();
6196
// Else seeds may not reproduce:

0 commit comments

Comments
 (0)