Skip to content

Commit 6209d07

Browse files
authored
Merge branch 'main' into esql_sequential_pct
2 parents 1c99056 + 23b7a31 commit 6209d07

File tree

30 files changed

+596
-271
lines changed

30 files changed

+596
-271
lines changed

BUILDING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ To wire this registered cluster into a `TestClusterAware` task (e.g. `RestIntegT
144144
Additional integration tests for a certain Elasticsearch modules that are specific to certain cluster configuration can be declared in a separate so called `qa` subproject of your module.
145145

146146
The benefit of a dedicated project for these tests are:
147-
- `qa` projects are dedicated two specific use-cases and easier to maintain
147+
- `qa` projects are dedicated to specific use-cases and easier to maintain
148148
- It keeps the specific test logic separated from the common test logic.
149149
- You can run those tests in parallel to other projects of the build.
150150

docs/changelog/125922.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 125922
2+
summary: Fix text structure NPE when fields in list have null value
3+
area: Machine Learning
4+
type: bug
5+
issues: []

docs/changelog/127229.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 127229
2+
summary: Return BAD_REQUEST when a field scorer references a missing field
3+
area: Ranking
4+
type: bug
5+
issues:
6+
- 127162

docs/changelog/127414.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 127414
2+
summary: Fix npe when using source confirmed text query against missing field
3+
area: Search
4+
type: bug
5+
issues: []

modules/data-streams/src/test/java/org/elasticsearch/datastreams/action/TransportGetDataStreamsActionTests.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.elasticsearch.action.datastreams.GetDataStreamAction;
1212
import org.elasticsearch.cluster.ClusterName;
1313
import org.elasticsearch.cluster.ClusterState;
14+
import org.elasticsearch.cluster.metadata.ComponentTemplate;
1415
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
1516
import org.elasticsearch.cluster.metadata.DataStream;
1617
import org.elasticsearch.cluster.metadata.DataStreamFailureStoreSettings;
@@ -40,6 +41,7 @@
4041
import java.time.temporal.ChronoUnit;
4142
import java.util.ArrayList;
4243
import java.util.List;
44+
import java.util.Map;
4345
import java.util.Set;
4446
import java.util.stream.Collectors;
4547

@@ -543,11 +545,44 @@ public void testGetEffectiveSettingsTemplateOnlySettings() {
543545
GetDataStreamAction.Request req = new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] {});
544546
final String templatePolicy = "templatePolicy";
545547
final String templateIndexMode = IndexMode.LOOKUP.getName();
546-
final String dataStreamPolicy = "dataStreamPolicy";
547-
final String dataStreamIndexMode = IndexMode.LOGSDB.getName();
548548

549549
ClusterState state = getClusterStateWithDataStreamWithSettings(
550550
projectId,
551+
Settings.builder()
552+
.put(IndexMetadata.LIFECYCLE_NAME, templatePolicy)
553+
.put(IndexSettings.MODE.getKey(), templateIndexMode)
554+
.build(),
555+
Settings.EMPTY,
556+
Settings.EMPTY
557+
);
558+
559+
GetDataStreamAction.Response response = TransportGetDataStreamsAction.innerOperation(
560+
state.projectState(projectId),
561+
req,
562+
resolver,
563+
systemIndices,
564+
ClusterSettings.createBuiltInClusterSettings(),
565+
dataStreamGlobalRetentionSettings,
566+
emptyDataStreamFailureStoreSettings,
567+
new IndexSettingProviders(Set.of()),
568+
null
569+
);
570+
assertNotNull(response.getDataStreams());
571+
assertThat(response.getDataStreams().size(), equalTo(1));
572+
assertThat(response.getDataStreams().get(0).getIlmPolicy(), equalTo(templatePolicy));
573+
assertThat(response.getDataStreams().get(0).getIndexModeName(), equalTo(templateIndexMode));
574+
}
575+
576+
public void testGetEffectiveSettingsComponentTemplateOnlySettings() {
577+
// Set a lifecycle only in the template, and make sure that is in the response:
578+
ProjectId projectId = randomProjectIdOrDefault();
579+
GetDataStreamAction.Request req = new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] {});
580+
final String templatePolicy = "templatePolicy";
581+
final String templateIndexMode = IndexMode.LOOKUP.getName();
582+
583+
ClusterState state = getClusterStateWithDataStreamWithSettings(
584+
projectId,
585+
Settings.EMPTY,
551586
Settings.builder()
552587
.put(IndexMetadata.LIFECYCLE_NAME, templatePolicy)
553588
.put(IndexSettings.MODE.getKey(), templateIndexMode)
@@ -582,6 +617,10 @@ public void testGetEffectiveSettings() {
582617
// Now set a lifecycle in both the template and the data stream, and make sure the response has the data stream one:
583618
ClusterState state = getClusterStateWithDataStreamWithSettings(
584619
projectId,
620+
Settings.builder()
621+
.put(IndexMetadata.LIFECYCLE_NAME, templatePolicy)
622+
.put(IndexSettings.MODE.getKey(), templateIndexMode)
623+
.build(),
585624
Settings.builder()
586625
.put(IndexMetadata.LIFECYCLE_NAME, templatePolicy)
587626
.put(IndexSettings.MODE.getKey(), templateIndexMode)
@@ -611,6 +650,7 @@ public void testGetEffectiveSettings() {
611650
private static ClusterState getClusterStateWithDataStreamWithSettings(
612651
ProjectId projectId,
613652
Settings templateSettings,
653+
Settings componentTemplateSettings,
614654
Settings dataStreamSettings
615655
) {
616656
String dataStreamName = "data-stream-1";
@@ -625,8 +665,16 @@ private static ClusterState getClusterStateWithDataStreamWithSettings(
625665
.indexPatterns(List.of("*"))
626666
.template(Template.builder().settings(templateSettings))
627667
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
668+
.componentTemplates(List.of("component_template_1"))
628669
.build()
629670
);
671+
ComponentTemplate componentTemplate = new ComponentTemplate(
672+
Template.builder().settings(componentTemplateSettings).build(),
673+
null,
674+
null,
675+
null
676+
);
677+
builder.componentTemplates(Map.of("component_template_1", componentTemplate));
630678

631679
List<IndexMetadata> backingIndices = new ArrayList<>();
632680
for (int backingIndexNumber = 1; backingIndexNumber <= numberOfBackingIndices; backingIndexNumber++) {

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/SourceConfirmedTextQuery.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,11 @@ public boolean isCacheable(LeafReaderContext ctx) {
267267
@Override
268268
public Explanation explain(LeafReaderContext context, int doc) throws IOException {
269269
NumericDocValues norms = context.reader().getNormValues(field);
270-
RuntimePhraseScorer scorer = (RuntimePhraseScorer) scorerSupplier(context).get(0);
270+
ScorerSupplier scorerSupplier = scorerSupplier(context);
271+
if (scorerSupplier == null) {
272+
return Explanation.noMatch("No matching phrase");
273+
}
274+
RuntimePhraseScorer scorer = (RuntimePhraseScorer) scorerSupplier.get(0);
271275
if (scorer == null) {
272276
return Explanation.noMatch("No matching phrase");
273277
}
@@ -277,6 +281,7 @@ public Explanation explain(LeafReaderContext context, int doc) throws IOExceptio
277281
}
278282
float phraseFreq = scorer.freq();
279283
Explanation freqExplanation = Explanation.match(phraseFreq, "phraseFreq=" + phraseFreq);
284+
assert simScorer != null;
280285
Explanation scoreExplanation = simScorer.explain(freqExplanation, getNormValue(norms, doc));
281286
return Explanation.match(
282287
scoreExplanation.getValue(),
@@ -321,7 +326,11 @@ public Matches matches(LeafReaderContext context, int doc) throws IOException {
321326
Weight innerWeight = in.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1);
322327
return innerWeight.matches(context, doc);
323328
}
324-
RuntimePhraseScorer scorer = (RuntimePhraseScorer) scorerSupplier(context).get(0L);
329+
ScorerSupplier scorerSupplier = scorerSupplier(context);
330+
if (scorerSupplier == null) {
331+
return null;
332+
}
333+
RuntimePhraseScorer scorer = (RuntimePhraseScorer) scorerSupplier.get(0L);
325334
if (scorer == null) {
326335
return null;
327336
}

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/SourceConfirmedTextQueryTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.lucene.queries.spans.SpanTermQuery;
2525
import org.apache.lucene.search.BooleanClause.Occur;
2626
import org.apache.lucene.search.BooleanQuery;
27+
import org.apache.lucene.search.Explanation;
2728
import org.apache.lucene.search.IndexSearcher;
2829
import org.apache.lucene.search.MatchNoDocsQuery;
2930
import org.apache.lucene.search.Matches;
@@ -101,6 +102,26 @@ public void testTerm() throws Exception {
101102
}
102103
}
103104

105+
public void testMissingPhrase() throws Exception {
106+
try (Directory dir = newDirectory(); IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(Lucene.STANDARD_ANALYZER))) {
107+
108+
Document doc = new Document();
109+
doc.add(new TextField("body", "a b c b a b c", Store.YES));
110+
w.addDocument(doc);
111+
112+
try (IndexReader reader = DirectoryReader.open(w)) {
113+
IndexSearcher searcher = newSearcher(reader);
114+
PhraseQuery query = new PhraseQuery("missing_field", "b", "c");
115+
Query sourceConfirmedPhraseQuery = new SourceConfirmedTextQuery(query, SOURCE_FETCHER_PROVIDER, Lucene.STANDARD_ANALYZER);
116+
Explanation explanation = searcher.explain(sourceConfirmedPhraseQuery, 0);
117+
assertFalse(explanation.isMatch());
118+
119+
Weight weight = searcher.createWeight(query, ScoreMode.COMPLETE, 1);
120+
assertNull(weight.matches(getOnlyLeafReader(reader).getContext(), 0));
121+
}
122+
}
123+
}
124+
104125
public void testPhrase() throws Exception {
105126
try (Directory dir = newDirectory(); IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(Lucene.STANDARD_ANALYZER))) {
106127

plugins/examples/rescore/src/yamlRestTest/resources/rest-api-spec/test/example-rescore/30_factor_field.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ setup:
4848
- match: { hits.hits.1._score: 20 }
4949
- match: { hits.hits.2._score: 10 }
5050

51+
---
52+
"referencing a missing field returns bad request":
53+
- requires:
54+
cluster_features: [ "search.rescorer.missing.field.bad.request" ]
55+
reason: "Testing the behaviour change with this feature"
56+
- do:
57+
catch: bad_request
58+
search:
59+
index: test
60+
body:
61+
rescore:
62+
example:
63+
factor: 1
64+
factor_field: missing
65+
- match: { status: 400 }
66+
- match: { error.root_cause.0.type: "illegal_argument_exception" }
67+
- match: { error.root_cause.0.reason: "Missing value for field [missing]" }
68+
5169
---
5270
"sorted based on a numeric field and rescored based on a factor field using a window size":
5371
- do:

qa/smoke-test-http/src/internalClusterTest/java/org/elasticsearch/http/SearchErrorTraceIT.java

Lines changed: 17 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -127,33 +127,7 @@ public void testSearchFailingQueryErrorTraceFalse() throws IOException {
127127
assertFalse(hasStackTrace.getAsBoolean());
128128
}
129129

130-
public void testDataNodeDoesNotLogStackTraceWhenErrorTraceTrue() throws IOException {
131-
setupIndexWithDocs();
132-
133-
Request searchRequest = new Request("POST", "/_search");
134-
searchRequest.setJsonEntity("""
135-
{
136-
"query": {
137-
"simple_query_string" : {
138-
"query": "foo",
139-
"fields": ["field"]
140-
}
141-
}
142-
}
143-
""");
144-
145-
String errorTriggeringIndex = "test2";
146-
int numShards = getNumShards(errorTriggeringIndex).numPrimaries;
147-
try (var mockLog = MockLog.capture(SearchService.class)) {
148-
ErrorTraceHelper.addUnseenLoggingExpectations(numShards, mockLog, errorTriggeringIndex);
149-
150-
searchRequest.addParameter("error_trace", "true");
151-
getRestClient().performRequest(searchRequest);
152-
mockLog.assertAllExpectationsMatched();
153-
}
154-
}
155-
156-
public void testDataNodeLogsStackTraceWhenErrorTraceFalseOrEmpty() throws IOException {
130+
public void testDataNodeLogsStackTrace() throws IOException {
157131
setupIndexWithDocs();
158132

159133
Request searchRequest = new Request("POST", "/_search");
@@ -173,10 +147,14 @@ public void testDataNodeLogsStackTraceWhenErrorTraceFalseOrEmpty() throws IOExce
173147
try (var mockLog = MockLog.capture(SearchService.class)) {
174148
ErrorTraceHelper.addSeenLoggingExpectations(numShards, mockLog, errorTriggeringIndex);
175149

176-
// error_trace defaults to false so we can test both cases with some randomization
177-
if (randomBoolean()) {
150+
// No matter the value of error_trace (empty, true, or false) we should see stack traces logged
151+
int errorTraceValue = randomIntBetween(0, 2);
152+
if (errorTraceValue == 0) {
153+
searchRequest.addParameter("error_trace", "true");
154+
} else if (errorTraceValue == 1) {
178155
searchRequest.addParameter("error_trace", "false");
179-
}
156+
} // else empty
157+
180158
getRestClient().performRequest(searchRequest);
181159
mockLog.assertAllExpectationsMatched();
182160
}
@@ -233,32 +211,7 @@ public void testMultiSearchFailingQueryErrorTraceFalse() throws IOException {
233211
assertFalse(hasStackTrace.getAsBoolean());
234212
}
235213

236-
public void testDataNodeDoesNotLogStackTraceWhenErrorTraceTrueMultiSearch() throws IOException {
237-
setupIndexWithDocs();
238-
239-
XContentType contentType = XContentType.JSON;
240-
MultiSearchRequest multiSearchRequest = new MultiSearchRequest().add(
241-
new SearchRequest("test*").source(new SearchSourceBuilder().query(simpleQueryStringQuery("foo").field("field")))
242-
);
243-
Request searchRequest = new Request("POST", "/_msearch");
244-
byte[] requestBody = MultiSearchRequest.writeMultiLineFormat(multiSearchRequest, contentType.xContent());
245-
searchRequest.setEntity(
246-
new NByteArrayEntity(requestBody, ContentType.create(contentType.mediaTypeWithoutParameters(), (Charset) null))
247-
);
248-
249-
searchRequest.addParameter("error_trace", "true");
250-
251-
String errorTriggeringIndex = "test2";
252-
int numShards = getNumShards(errorTriggeringIndex).numPrimaries;
253-
try (var mockLog = MockLog.capture(SearchService.class)) {
254-
ErrorTraceHelper.addUnseenLoggingExpectations(numShards, mockLog, errorTriggeringIndex);
255-
256-
getRestClient().performRequest(searchRequest);
257-
mockLog.assertAllExpectationsMatched();
258-
}
259-
}
260-
261-
public void testDataNodeLogsStackTraceWhenErrorTraceFalseOrEmptyMultiSearch() throws IOException {
214+
public void testDataNodeLogsStackTraceMultiSearch() throws IOException {
262215
setupIndexWithDocs();
263216

264217
XContentType contentType = XContentType.JSON;
@@ -271,16 +224,19 @@ public void testDataNodeLogsStackTraceWhenErrorTraceFalseOrEmptyMultiSearch() th
271224
new NByteArrayEntity(requestBody, ContentType.create(contentType.mediaTypeWithoutParameters(), (Charset) null))
272225
);
273226

274-
// error_trace defaults to false so we can test both cases with some randomization
275-
if (randomBoolean()) {
276-
searchRequest.addParameter("error_trace", "false");
277-
}
278-
279227
String errorTriggeringIndex = "test2";
280228
int numShards = getNumShards(errorTriggeringIndex).numPrimaries;
281229
try (var mockLog = MockLog.capture(SearchService.class)) {
282230
ErrorTraceHelper.addSeenLoggingExpectations(numShards, mockLog, errorTriggeringIndex);
283231

232+
// No matter the value of error_trace (empty, true, or false) we should see stack traces logged
233+
int errorTraceValue = randomIntBetween(0, 2);
234+
if (errorTraceValue == 0) {
235+
searchRequest.addParameter("error_trace", "true");
236+
} else if (errorTraceValue == 1) {
237+
searchRequest.addParameter("error_trace", "false");
238+
} // else empty
239+
284240
getRestClient().performRequest(searchRequest);
285241
mockLog.assertAllExpectationsMatched();
286242
}

server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,7 @@ public ComposableIndexTemplate getEffectiveIndexTemplate(ProjectMetadata project
381381

382382
public Settings getEffectiveSettings(ProjectMetadata projectMetadata) {
383383
ComposableIndexTemplate template = getMatchingIndexTemplate(projectMetadata);
384-
final Settings templateSettings;
385-
if (template.template() == null || template.template().settings() == null) {
386-
templateSettings = Settings.EMPTY;
387-
} else {
388-
templateSettings = template.template().settings();
389-
}
384+
Settings templateSettings = MetadataIndexTemplateService.resolveSettings(template, projectMetadata.componentTemplates());
390385
return templateSettings.merge(settings);
391386
}
392387

0 commit comments

Comments
 (0)