Skip to content

Commit 85092e3

Browse files
committed
Fix NPE in semantic highlighter
This PR fixes an NPE in the semantic highlighter when the document being highlighted doesn't contain value for the semantic text field. Closes #128975
1 parent a0bfe61 commit 85092e3

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ private List<OffsetAndScore> extractOffsetAndScores(
209209
leafQueries.stream().forEach(q -> bq.add(q, BooleanClause.Occur.SHOULD));
210210
Weight weight = new IndexSearcher(reader).createWeight(bq.build(), ScoreMode.COMPLETE, 1);
211211
Scorer scorer = weight.scorer(reader.getContext());
212+
if (scorer == null) {
213+
return List.of();
214+
}
212215
if (previousParent != -1) {
213216
if (scorer.iterator().advance(previousParent) == DocIdSetIterator.NO_MORE_DOCS) {
214217
return List.of();

x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighterTests.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.elasticsearch.index.mapper.MapperService;
3333
import org.elasticsearch.index.mapper.MapperServiceTestCase;
3434
import org.elasticsearch.index.mapper.SourceToParse;
35+
import org.elasticsearch.index.query.BoolQueryBuilder;
36+
import org.elasticsearch.index.query.MatchAllQueryBuilder;
3537
import org.elasticsearch.index.query.NestedQueryBuilder;
3638
import org.elasticsearch.index.query.QueryBuilder;
3739
import org.elasticsearch.index.shard.ShardId;
@@ -170,6 +172,34 @@ public void testSparseVector() throws Exception {
170172
);
171173
}
172174

175+
@SuppressWarnings("unchecked")
176+
public void testNoSemanticField() throws Exception {
177+
var mapperService = createDefaultMapperService(useLegacyFormat);
178+
Map<String, Object> queryMap = (Map<String, Object>) queries.get("sparse_vector_1");
179+
List<WeightedToken> tokens = readSparseVector(queryMap.get("embeddings"));
180+
var fieldType = (SemanticTextFieldMapper.SemanticTextFieldType) mapperService.mappingLookup().getFieldType(SEMANTIC_FIELD_ELSER);
181+
SparseVectorQueryBuilder sparseQuery = new SparseVectorQueryBuilder(
182+
fieldType.getEmbeddingsField().fullPath(),
183+
tokens,
184+
null,
185+
null,
186+
null,
187+
null
188+
);
189+
var query = new BoolQueryBuilder().should(sparseQuery).should(new MatchAllQueryBuilder());
190+
var shardRequest = createShardSearchRequest(query);
191+
var sourceToParse = new SourceToParse("0", new BytesArray("{}"), XContentType.JSON);
192+
assertHighlightOneDoc(
193+
mapperService,
194+
shardRequest,
195+
sourceToParse,
196+
SEMANTIC_FIELD_ELSER,
197+
10,
198+
HighlightBuilder.Order.SCORE,
199+
new String[0]
200+
);
201+
}
202+
173203
private MapperService createDefaultMapperService(boolean useLegacyFormat) throws IOException {
174204
var mappings = Streams.readFully(SemanticTextHighlighterTests.class.getResourceAsStream("mappings.json"));
175205
var settings = Settings.builder()
@@ -264,9 +294,13 @@ private void assertHighlightOneDoc(
264294
new HashMap<>()
265295
);
266296
var result = highlighter.highlight(context);
267-
assertThat(result.fragments().length, equalTo(expectedPassages.length));
268-
for (int i = 0; i < result.fragments().length; i++) {
269-
assertThat(result.fragments()[i].string(), equalTo(expectedPassages[i]));
297+
if (result == null) {
298+
assertThat(expectedPassages.length, equalTo(0));
299+
} else {
300+
assertThat(result.fragments().length, equalTo(expectedPassages.length));
301+
for (int i = 0; i < result.fragments().length; i++) {
302+
assertThat(result.fragments()[i].string(), equalTo(expectedPassages[i]));
303+
}
270304
}
271305
}
272306
} finally {

0 commit comments

Comments
 (0)