Skip to content

Commit 3d6619a

Browse files
authored
Merge branch 'main' into make-layout-failure-test-more-specific
2 parents 3748346 + bd5f43f commit 3d6619a

File tree

9 files changed

+219
-27
lines changed

9 files changed

+219
-27
lines changed

docs/release-notes/breaking-changes.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,15 @@ If you are migrating from a version prior to version 9.0, you must first upgrade
1212

1313
% ## Next version [elasticsearch-nextversion-breaking-changes]
1414

15-
```{applies_to}
16-
stack: coming 9.0.3
17-
```
1815
## 9.0.3 [elasticsearch-9.0.3-breaking-changes]
1916

2017
No breaking changes in this version.
2118

22-
```{applies_to}
23-
stack: coming 9.0.2
24-
```
2519
## 9.0.2 [elasticsearch-9.0.2-breaking-changes]
2620

2721
Snapshot/Restore:
2822
* Make S3 custom query parameter optional [#128043](https://github.com/elastic/elasticsearch/pull/128043)
2923

30-
31-
3224
## 9.0.1 [elasticsearch-9.0.1-breaking-changes]
3325

3426
No breaking changes in this version.

docs/release-notes/changelog-bundles/9.0.3.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
version: 9.0.3
2-
released: false
3-
generated: 2025-06-21T00:06:16.346021604Z
2+
released: true
3+
generated: 2025-06-24T15:19:29.859630035Z
44
changelogs:
55
- pr: 120869
66
summary: Threadpool merge scheduler

docs/release-notes/deprecations.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,11 @@ To give you insight into what deprecated features you’re using, {{es}}:
1616

1717
% ## Next version [elasticsearch-nextversion-deprecations]
1818

19-
```{applies_to}
20-
stack: coming 9.0.3
21-
```
2219
## 9.0.3 [elasticsearch-9.0.3-deprecations]
2320

2421
Engine:
2522
* Deprecate `indices.merge.scheduler.use_thread_pool` setting [#129464](https://github.com/elastic/elasticsearch/pull/129464)
2623

27-
28-
29-
```{applies_to}
30-
stack: coming 9.0.2
31-
```
3224
## 9.0.2 [elasticsearch-9.0.2-deprecations]
3325

3426
No deprecations in this version.

docs/release-notes/index.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ To check for security updates, go to [Security announcements for the Elastic sta
2121
% *
2222

2323
## 9.0.3 [elasticsearch-9.0.3-release-notes]
24-
```{applies_to}
25-
stack: coming 9.0.3
26-
```
2724

2825
### Features and enhancements [elasticsearch-9.0.3-features-enhancements]
2926

@@ -92,7 +89,6 @@ Searchable Snapshots:
9289
Security:
9390
* Fix error message when changing the password for a user in the file realm [#127621](https://github.com/elastic/elasticsearch/pull/127621)
9491

95-
9692
## 9.0.2 [elasticsearch-9.0.2-release-notes]
9793

9894
### Features and enhancements [elasticsearch-9.0.2-features-enhancements]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.core;
11+
12+
import java.lang.annotation.ElementType;
13+
import java.lang.annotation.Retention;
14+
import java.lang.annotation.RetentionPolicy;
15+
import java.lang.annotation.Target;
16+
17+
/**
18+
* Annotation to identify a block of code (a whole class, a method, a field, or a local variable) that is intentionally not fully
19+
* project-aware because it's not intended to be used in a serverless environment. Some features are unavailable in serverless and are
20+
* thus not worth the investment to make fully project-aware. This annotation makes it easier to identify blocks of code that require
21+
* attention in case those features are revisited from a multi-project POV.
22+
*/
23+
@Retention(RetentionPolicy.SOURCE)
24+
@Target(
25+
{ ElementType.LOCAL_VARIABLE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.MODULE }
26+
)
27+
public @interface NotMultiProjectCapable {
28+
29+
/**
30+
* Some explanation on why the block of code would not work in a multi-project context and/or what would need to be done to make it
31+
* properly project-aware.
32+
*/
33+
String description() default "";
34+
}

muted-tests.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,12 @@ tests:
564564
method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
565565
extractedAssemble, #2]"
566566
issue: https://github.com/elastic/elasticsearch/issues/119871
567-
567+
- class: org.elasticsearch.xpack.inference.qa.mixed.CohereServiceMixedIT
568+
method: testRerank
569+
issue: https://github.com/elastic/elasticsearch/issues/130009
570+
- class: org.elasticsearch.xpack.inference.qa.mixed.CohereServiceMixedIT
571+
method: testCohereEmbeddings
572+
issue: https://github.com/elastic/elasticsearch/issues/130010
568573

569574
# Examples:
570575
#

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77

88
package org.elasticsearch.xpack.esql.planner;
99

10+
import org.apache.lucene.document.FieldType;
11+
import org.apache.lucene.index.DocValuesType;
12+
import org.apache.lucene.index.IndexOptions;
1013
import org.apache.lucene.index.LeafReaderContext;
1114
import org.apache.lucene.index.SortedSetDocValues;
1215
import org.apache.lucene.search.BooleanClause;
1316
import org.apache.lucene.search.BooleanQuery;
1417
import org.apache.lucene.search.IndexSearcher;
1518
import org.apache.lucene.search.Query;
1619
import org.elasticsearch.common.logging.HeaderWarning;
20+
import org.elasticsearch.common.lucene.Lucene;
1721
import org.elasticsearch.compute.aggregation.AggregatorMode;
1822
import org.elasticsearch.compute.aggregation.GroupingAggregator;
1923
import org.elasticsearch.compute.aggregation.blockhash.BlockHash;
@@ -76,7 +80,6 @@
7680
import java.io.IOException;
7781
import java.util.ArrayList;
7882
import java.util.List;
79-
import java.util.Map;
8083
import java.util.Optional;
8184
import java.util.Set;
8285
import java.util.function.Function;
@@ -177,6 +180,13 @@ private BlockLoader getBlockLoaderFor(int shardId, Attribute attr, MappedFieldTy
177180

178181
/** A hack to pretend an unmapped field still exists. */
179182
private static class DefaultShardContextForUnmappedField extends DefaultShardContext {
183+
private static final FieldType UNMAPPED_FIELD_TYPE = new FieldType(KeywordFieldMapper.Defaults.FIELD_TYPE);
184+
static {
185+
UNMAPPED_FIELD_TYPE.setDocValuesType(DocValuesType.NONE);
186+
UNMAPPED_FIELD_TYPE.setIndexOptions(IndexOptions.NONE);
187+
UNMAPPED_FIELD_TYPE.setStored(false);
188+
UNMAPPED_FIELD_TYPE.freeze();
189+
}
180190
private final KeywordEsField unmappedEsField;
181191

182192
DefaultShardContextForUnmappedField(DefaultShardContext ctx, PotentiallyUnmappedKeywordEsField unmappedEsField) {
@@ -187,9 +197,22 @@ private static class DefaultShardContextForUnmappedField extends DefaultShardCon
187197
@Override
188198
public @Nullable MappedFieldType fieldType(String name) {
189199
var superResult = super.fieldType(name);
190-
return superResult == null && name.equals(unmappedEsField.getName())
191-
? new KeywordFieldMapper.KeywordFieldType(name, false /* isIndexed */, false /* hasDocValues */, Map.of() /* meta */)
192-
: superResult;
200+
return superResult == null && name.equals(unmappedEsField.getName()) ? createUnmappedFieldType(name, this) : superResult;
201+
}
202+
203+
static MappedFieldType createUnmappedFieldType(String name, DefaultShardContext context) {
204+
var builder = new KeywordFieldMapper.Builder(name, context.ctx.indexVersionCreated());
205+
builder.docValues(false);
206+
builder.indexed(false);
207+
return new KeywordFieldMapper.KeywordFieldType(
208+
name,
209+
UNMAPPED_FIELD_TYPE,
210+
Lucene.KEYWORD_ANALYZER,
211+
Lucene.KEYWORD_ANALYZER,
212+
Lucene.KEYWORD_ANALYZER,
213+
builder,
214+
context.ctx.isSourceSynthetic()
215+
);
193216
}
194217
}
195218

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,18 @@
2323
import org.elasticsearch.compute.lucene.DataPartitioning;
2424
import org.elasticsearch.compute.lucene.LuceneSourceOperator;
2525
import org.elasticsearch.compute.lucene.LuceneTopNSourceOperator;
26+
import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
2627
import org.elasticsearch.compute.operator.SourceOperator;
2728
import org.elasticsearch.compute.test.TestBlockFactory;
2829
import org.elasticsearch.core.IOUtils;
2930
import org.elasticsearch.core.Releasable;
3031
import org.elasticsearch.core.Releasables;
3132
import org.elasticsearch.index.IndexMode;
3233
import org.elasticsearch.index.cache.query.TrivialQueryCachingPolicy;
34+
import org.elasticsearch.index.mapper.BlockLoader;
35+
import org.elasticsearch.index.mapper.BlockSourceReader;
36+
import org.elasticsearch.index.mapper.FallbackSyntheticSourceBlockLoader;
37+
import org.elasticsearch.index.mapper.MappedFieldType;
3338
import org.elasticsearch.index.mapper.MapperServiceTestCase;
3439
import org.elasticsearch.node.Node;
3540
import org.elasticsearch.plugins.ExtensiblePlugin;
@@ -42,10 +47,12 @@
4247
import org.elasticsearch.xpack.esql.core.tree.Source;
4348
import org.elasticsearch.xpack.esql.core.type.DataType;
4449
import org.elasticsearch.xpack.esql.core.type.EsField;
50+
import org.elasticsearch.xpack.esql.core.type.PotentiallyUnmappedKeywordEsField;
4551
import org.elasticsearch.xpack.esql.core.util.StringUtils;
4652
import org.elasticsearch.xpack.esql.expression.Order;
4753
import org.elasticsearch.xpack.esql.index.EsIndex;
4854
import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec;
55+
import org.elasticsearch.xpack.esql.plan.physical.FieldExtractExec;
4956
import org.elasticsearch.xpack.esql.plan.physical.LimitExec;
5057
import org.elasticsearch.xpack.esql.plan.physical.ParallelExec;
5158
import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
@@ -64,6 +71,7 @@
6471

6572
import static org.hamcrest.Matchers.equalTo;
6673
import static org.hamcrest.Matchers.hasSize;
74+
import static org.hamcrest.Matchers.instanceOf;
6775
import static org.hamcrest.Matchers.lessThanOrEqualTo;
6876

6977
public class LocalExecutionPlannerTests extends MapperServiceTestCase {
@@ -84,10 +92,17 @@ public static Iterable<Object[]> parameters() throws Exception {
8492

8593
private final ArrayList<Releasable> releasables = new ArrayList<>();
8694

95+
private Settings settings = SETTINGS;
96+
8797
public LocalExecutionPlannerTests(@Name("estimatedRowSizeIsHuge") boolean estimatedRowSizeIsHuge) {
8898
this.estimatedRowSizeIsHuge = estimatedRowSizeIsHuge;
8999
}
90100

101+
@Override
102+
protected Settings getIndexSettings() {
103+
return settings;
104+
}
105+
91106
@Override
92107
protected Collection<Plugin> getPlugins() {
93108
var plugin = new SpatialPlugin();
@@ -229,6 +244,47 @@ public void testParallel() throws Exception {
229244
assertThat(plan.driverFactories, hasSize(2));
230245
}
231246

247+
public void testPlanUnmappedFieldExtractStoredSource() throws Exception {
248+
var blockLoader = constructBlockLoader();
249+
// In case of stored source we expect bytes based block source loader (this loads source from _source)
250+
assertThat(blockLoader, instanceOf(BlockSourceReader.BytesRefsBlockLoader.class));
251+
}
252+
253+
public void testPlanUnmappedFieldExtractSyntheticSource() throws Exception {
254+
// Enables synthetic source, so that fallback synthetic source blocker loader is used:
255+
settings = Settings.builder().put(settings).put("index.mapping.source.mode", "synthetic").build();
256+
257+
var blockLoader = constructBlockLoader();
258+
// In case of synthetic source we expect bytes based block source loader (this loads source from _ignored_source)
259+
assertThat(blockLoader, instanceOf(FallbackSyntheticSourceBlockLoader.class));
260+
}
261+
262+
private BlockLoader constructBlockLoader() throws IOException {
263+
EsQueryExec queryExec = new EsQueryExec(
264+
Source.EMPTY,
265+
index().name(),
266+
IndexMode.STANDARD,
267+
index().indexNameWithModes(),
268+
List.of(new FieldAttribute(Source.EMPTY, EsQueryExec.DOC_ID_FIELD.getName(), EsQueryExec.DOC_ID_FIELD)),
269+
null,
270+
null,
271+
null,
272+
between(1, 1000)
273+
);
274+
FieldExtractExec fieldExtractExec = new FieldExtractExec(
275+
Source.EMPTY,
276+
queryExec,
277+
List.of(
278+
new FieldAttribute(Source.EMPTY, "potentially_unmapped", new PotentiallyUnmappedKeywordEsField("potentially_unmapped"))
279+
),
280+
MappedFieldType.FieldExtractPreference.NONE
281+
);
282+
LocalExecutionPlanner.LocalExecutionPlan plan = planner().plan("test", FoldContext.small(), fieldExtractExec);
283+
var p = plan.driverFactories.get(0).driverSupplier().physicalOperation();
284+
var fieldInfo = ((ValuesSourceReaderOperator.Factory) p.intermediateOperatorFactories.get(0)).fields().get(0);
285+
return fieldInfo.blockLoader().apply(0);
286+
}
287+
232288
private int randomEstimatedRowSize(boolean huge) {
233289
int hugeBoundary = SourceOperator.MIN_TARGET_PAGE_SIZE * 10;
234290
return huge ? between(hugeBoundary, Integer.MAX_VALUE) : between(1, hugeBoundary);
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
setup:
3+
- do:
4+
indices.create:
5+
index: my-index
6+
body:
7+
settings:
8+
index:
9+
mode: logsdb
10+
mappings:
11+
dynamic: false
12+
properties:
13+
"@timestamp":
14+
type: date
15+
message:
16+
type: text
17+
18+
- do:
19+
bulk:
20+
index: my-index
21+
refresh: true
22+
body:
23+
- { "index": { } }
24+
- { "@timestamp": "2024-02-12T10:30:00Z", "host.name": "foo", "agent_id": "darth-vader", "process_id": 101, "http_method": "GET", "is_https": false, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "No, I am your father." }
25+
- { "index": { } }
26+
- { "@timestamp": "2024-02-12T10:31:00Z", "host.name": "bar", "agent_id": "yoda", "process_id": 102, "http_method": "PUT", "is_https": false, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "Do. Or do not. There is no try." }
27+
- { "index": { } }
28+
- { "@timestamp": "2024-02-12T10:32:00Z", "host.name": "foo", "agent_id": "obi-wan", "process_id": 103, "http_method": "GET", "is_https": false, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "May the force be with you." }
29+
- { "index": { } }
30+
- { "@timestamp": "2024-02-12T10:33:00Z", "host.name": "baz", "agent_id": "darth-vader", "process_id": 102, "http_method": "POST", "is_https": true, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "I find your lack of faith disturbing." }
31+
- { "index": { } }
32+
- { "@timestamp": "2024-02-12T10:34:00Z", "host.name": "baz", "agent_id": "yoda", "process_id": 104, "http_method": "POST", "is_https": false, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "Wars not make one great." }
33+
- { "index": { } }
34+
- { "@timestamp": "2024-02-12T10:35:00Z", "host.name": "foo", "agent_id": "obi-wan", "process_id": 105, "http_method": "GET", "is_https": false, "location": {"lat" : 40.7128, "lon" : -74.0060}, "message": "That's no moon. It's a space station." }
35+
36+
---
37+
teardown:
38+
- do:
39+
indices.delete:
40+
index: my-index
41+
42+
---
43+
"Simple from":
44+
- do:
45+
esql.query:
46+
body:
47+
query: 'FROM my-index | SORT @timestamp | LIMIT 1'
48+
49+
- match: {columns.0.name: "@timestamp"}
50+
- match: {columns.0.type: "date"}
51+
- match: {columns.1.name: "message"}
52+
- match: {columns.1.type: "text"}
53+
54+
- match: {values.0.0: "2024-02-12T10:30:00.000Z"}
55+
- match: {values.0.1: "No, I am your father."}
56+
57+
---
58+
"FROM with INSIST_🐔and LIMIT 1":
59+
- do:
60+
esql.query:
61+
body:
62+
query: 'FROM my-index | INSIST_🐔 host.name, agent_id, http_method | SORT @timestamp | KEEP host.name, agent_id, http_method | LIMIT 1'
63+
64+
- match: {columns.0.name: "host.name"}
65+
- match: {columns.0.type: "keyword"}
66+
- match: {columns.1.name: "agent_id"}
67+
- match: {columns.1.type: "keyword"}
68+
- match: {columns.2.name: "http_method"}
69+
- match: {columns.2.type: "keyword"}
70+
71+
- match: {values.0.0: "foo"}
72+
- match: {values.0.1: "darth-vader"}
73+
- match: {values.0.2: "GET"}
74+
75+
---
76+
"FROM with INSIST_🐔":
77+
- requires:
78+
test_runner_features: allowed_warnings_regex
79+
- do:
80+
allowed_warnings_regex:
81+
- "No limit defined, adding default limit of \\[.*\\]"
82+
esql.query:
83+
body:
84+
query: 'FROM my-index | INSIST_🐔 agent_id | SORT @timestamp | KEEP agent_id'
85+
86+
- match: {columns.0.name: "agent_id"}
87+
- match: {columns.0.type: "keyword"}
88+
89+
- match: {values.0.0: "darth-vader"}
90+
- match: {values.1.0: "yoda"}
91+
- match: {values.2.0: "obi-wan"}
92+
- match: {values.3.0: "darth-vader"}
93+
- match: {values.4.0: "yoda"}
94+
- match: {values.5.0: "obi-wan"}

0 commit comments

Comments
 (0)