Skip to content

Commit 4c6bb2c

Browse files
authored
Fix NPE in semantic highlighter (#128989) (#129048)
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 14e0b05 commit 4c6bb2c

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

docs/changelog/128989.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 128989
2+
summary: Fix NPE in semantic highlighter
3+
area: Search
4+
type: bug
5+
issues:
6+
- 128975

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)