From 1c8b42489d38f7ff12ca26376178444e105cb343 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Fri, 6 Jun 2025 13:06:22 +0100 Subject: [PATCH] Fix NPE in semantic highlighter (#128989) 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 --- docs/changelog/128989.yaml | 6 +++ .../highlight/SemanticTextHighlighter.java | 3 ++ .../SemanticTextHighlighterTests.java | 40 +++++++++++++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 docs/changelog/128989.yaml diff --git a/docs/changelog/128989.yaml b/docs/changelog/128989.yaml new file mode 100644 index 0000000000000..94ee4c6923d7b --- /dev/null +++ b/docs/changelog/128989.yaml @@ -0,0 +1,6 @@ +pr: 128989 +summary: Fix NPE in semantic highlighter +area: Search +type: bug +issues: + - 128975 diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java index 1ad205cd6aad6..844267244263e 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java @@ -209,6 +209,9 @@ private List extractOffsetAndScores( leafQueries.stream().forEach(q -> bq.add(q, BooleanClause.Occur.SHOULD)); Weight weight = new IndexSearcher(reader).createWeight(bq.build(), ScoreMode.COMPLETE, 1); Scorer scorer = weight.scorer(reader.getContext()); + if (scorer == null) { + return List.of(); + } if (previousParent != -1) { if (scorer.iterator().advance(previousParent) == DocIdSetIterator.NO_MORE_DOCS) { return List.of(); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighterTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighterTests.java index 4b459c25556e2..9612719e0da65 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighterTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighterTests.java @@ -32,6 +32,8 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperServiceTestCase; import org.elasticsearch.index.mapper.SourceToParse; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.NestedQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.shard.ShardId; @@ -170,6 +172,34 @@ public void testSparseVector() throws Exception { ); } + @SuppressWarnings("unchecked") + public void testNoSemanticField() throws Exception { + var mapperService = createDefaultMapperService(useLegacyFormat); + Map queryMap = (Map) queries.get("sparse_vector_1"); + List tokens = readSparseVector(queryMap.get("embeddings")); + var fieldType = (SemanticTextFieldMapper.SemanticTextFieldType) mapperService.mappingLookup().getFieldType(SEMANTIC_FIELD_ELSER); + SparseVectorQueryBuilder sparseQuery = new SparseVectorQueryBuilder( + fieldType.getEmbeddingsField().fullPath(), + tokens, + null, + null, + null, + null + ); + var query = new BoolQueryBuilder().should(sparseQuery).should(new MatchAllQueryBuilder()); + var shardRequest = createShardSearchRequest(query); + var sourceToParse = new SourceToParse("0", new BytesArray("{}"), XContentType.JSON); + assertHighlightOneDoc( + mapperService, + shardRequest, + sourceToParse, + SEMANTIC_FIELD_ELSER, + 10, + HighlightBuilder.Order.SCORE, + new String[0] + ); + } + private MapperService createDefaultMapperService(boolean useLegacyFormat) throws IOException { var mappings = Streams.readFully(SemanticTextHighlighterTests.class.getResourceAsStream("mappings.json")); var settings = Settings.builder() @@ -264,9 +294,13 @@ private void assertHighlightOneDoc( new HashMap<>() ); var result = highlighter.highlight(context); - assertThat(result.fragments().length, equalTo(expectedPassages.length)); - for (int i = 0; i < result.fragments().length; i++) { - assertThat(result.fragments()[i].string(), equalTo(expectedPassages[i])); + if (result == null) { + assertThat(expectedPassages.length, equalTo(0)); + } else { + assertThat(result.fragments().length, equalTo(expectedPassages.length)); + for (int i = 0; i < result.fragments().length; i++) { + assertThat(result.fragments()[i].string(), equalTo(expectedPassages[i])); + } } } } finally {