Skip to content

Commit 17c3f33

Browse files
authored
[8.19] Allow partial results by default in ES|QL - Take 2 (#127351) (#127474)
* Allow partial results by default in ES|QL - Take 2 (#127351) * Revert "ESQL: Revert "Allow partial results by default in ES|QL (#125060)" (#126286)" This reverts commit 8f38b13. Restore changes from #125060 now that the breakage should be fixed. (cherry picked from commit eb479e5) # Conflicts: # docs/release-notes/breaking-changes.md # x-pack/plugin/build.gradle # x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java * skip test * fix test * fix test
1 parent 7e9a7c3 commit 17c3f33

File tree

16 files changed

+92
-63
lines changed

16 files changed

+92
-63
lines changed

docs/changelog/127351.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pr: 127351
2+
summary: Allow partial results by default in ES|QL
3+
area: ES|QL
4+
type: breaking
5+
issues: [122802]
6+
7+
breaking:
8+
title: Allow partial results by default in ES|QL
9+
area: ES|QL
10+
details: >-
11+
In earlier versions of {es}, ES|QL would fail the entire query if it encountered any error. ES|QL now returns partial results instead of failing when encountering errors.
12+
13+
impact: >-
14+
Callers should check the `is_partial` flag returned in the response to determine if the result is partial or complete. If returning partial results is not desired, this option can be overridden per request via an `allow_partial_results` parameter in the query URL or globally via the cluster setting `esql.query.allow_partial_results`.
15+
16+
notable: true

test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/Clusters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static ElasticsearchCluster buildCluster() {
2121
.module("test-esql-heap-attack")
2222
.setting("xpack.security.enabled", "false")
2323
.setting("xpack.license.self_generated.type", "trial")
24+
.setting("esql.query.allow_partial_results", "false")
2425
.jvmArg("-Xmx512m");
2526
String javaVersion = JvmInfo.jvmInfo().version();
2627
if (javaVersion.equals("20") || javaVersion.equals("21")) {

x-pack/plugin/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,10 @@ tasks.named("yamlRestTestV7CompatTransform").configure({ task ->
223223
task.skipTest("esql/40_tsdb/from index pattern unsupported counter", "TODO: support for subset of metric fields")
224224
task.skipTest("esql/40_unsupported_types/unsupported", "TODO: support for subset of metric fields")
225225
task.skipTest("esql/40_unsupported_types/unsupported with sort", "TODO: support for subset of metric fields")
226+
task.skipTest("esql/63_enrich_int_range/Invalid age as double", "TODO: require disable allow_partial_results")
226227
})
227228

229+
228230
tasks.named('yamlRestTestV7CompatTest').configure {
229231
systemProperty 'es.queryable_built_in_roles_enabled', 'false'
230232
}

x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/EsqlRestValidationIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@ private RestClient remoteClusterClient() throws IOException {
8383

8484
@Before
8585
public void skipTestOnOldVersions() {
86-
assumeTrue("skip on old versions", Clusters.localClusterVersion().equals(Version.V_8_16_0));
86+
assumeTrue("skip on old versions", Clusters.localClusterVersion().equals(Version.V_8_19_0));
8787
}
8888
}

x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.junit.rules.TestRule;
3131

3232
import java.io.IOException;
33+
import java.util.List;
3334
import java.util.Map;
3435

3536
import static org.elasticsearch.test.MapMatcher.assertMap;
@@ -94,6 +95,12 @@ protected String from(String... indexName) {
9495

9596
@Override
9697
public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject) throws IOException {
98+
if (requestObject.allowPartialResults() != null) {
99+
assumeTrue(
100+
"require allow_partial_results on local cluster",
101+
clusterHasCapability("POST", "/_query", List.of(), List.of("support_partial_results")).orElse(false)
102+
);
103+
}
97104
requestObject.includeCCSMetadata(true);
98105
return super.runEsql(requestObject);
99106
}

x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void testInvalidPragma() throws IOException {
110110
request.setJsonEntity("{\"f\":" + i + "}");
111111
assertOK(client().performRequest(request));
112112
}
113-
RequestObjectBuilder builder = requestObjectBuilder().query("from test-index | limit 1 | keep f");
113+
RequestObjectBuilder builder = requestObjectBuilder().query("from test-index | limit 1 | keep f").allowPartialResults(false);
114114
builder.pragmas(Settings.builder().put("data_partitioning", "invalid-option").build());
115115
ResponseException re = expectThrows(ResponseException.class, () -> runEsqlSync(builder));
116116
assertThat(EntityUtils.toString(re.getResponse().getEntity()), containsString("No enum constant"));

x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public static class RequestObjectBuilder {
132132
private Boolean includeCCSMetadata = null;
133133

134134
private CheckedConsumer<XContentBuilder, IOException> filter;
135-
private Boolean allPartialResults = null;
135+
private Boolean allowPartialResults = null;
136136

137137
public RequestObjectBuilder() throws IOException {
138138
this(randomFrom(XContentType.values()));
@@ -210,11 +210,15 @@ public RequestObjectBuilder filter(CheckedConsumer<XContentBuilder, IOException>
210210
return this;
211211
}
212212

213-
public RequestObjectBuilder allPartialResults(boolean allPartialResults) {
214-
this.allPartialResults = allPartialResults;
213+
public RequestObjectBuilder allowPartialResults(boolean allowPartialResults) {
214+
this.allowPartialResults = allowPartialResults;
215215
return this;
216216
}
217217

218+
public Boolean allowPartialResults() {
219+
return allowPartialResults;
220+
}
221+
218222
public RequestObjectBuilder build() throws IOException {
219223
if (isBuilt == false) {
220224
if (tables != null) {
@@ -1369,8 +1373,8 @@ protected static Request prepareRequestWithOptions(RequestObjectBuilder requestO
13691373
requestObject.build();
13701374
Request request = prepareRequest(mode);
13711375
String mediaType = attachBody(requestObject, request);
1372-
if (requestObject.allPartialResults != null) {
1373-
request.addParameter("allow_partial_results", String.valueOf(requestObject.allPartialResults));
1376+
if (requestObject.allowPartialResults != null) {
1377+
request.addParameter("allow_partial_results", String.valueOf(requestObject.allowPartialResults));
13741378
}
13751379

13761380
RequestOptions.Builder options = request.getOptions().toBuilder();

x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterTestCase.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.transport.RemoteClusterAware;
2626
import org.elasticsearch.xcontent.XContentBuilder;
2727
import org.elasticsearch.xcontent.json.JsonXContent;
28+
import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
2829
import org.junit.After;
2930
import org.junit.Before;
3031

@@ -76,6 +77,11 @@ protected Collection<Class<? extends Plugin>> nodePlugins(String clusterAlias) {
7677
return plugins;
7778
}
7879

80+
@Override
81+
protected Settings nodeSettings() {
82+
return Settings.builder().put(super.nodeSettings()).put(EsqlPlugin.QUERY_ALLOW_PARTIAL_RESULTS.getKey(), false).build();
83+
}
84+
7985
public static class InternalExchangePlugin extends Plugin {
8086
@Override
8187
public List<Setting<?>> getSettings() {

x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractEsqlIntegTestCase.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ protected Collection<Class<? extends Plugin>> nodePlugins() {
139139
return CollectionUtils.appendToCopy(super.nodePlugins(), EsqlPlugin.class);
140140
}
141141

142+
@Override
143+
protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
144+
return Settings.builder()
145+
.put(super.nodeSettings(nodeOrdinal, otherSettings))
146+
.put(EsqlPlugin.QUERY_ALLOW_PARTIAL_RESULTS.getKey(), false)
147+
.build();
148+
}
149+
142150
protected void setRequestCircuitBreakerLimit(ByteSizeValue limit) {
143151
if (limit != null) {
144152
assertAcked(

x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterCancellationIT.java

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,20 @@
1414
import org.elasticsearch.action.index.IndexRequest;
1515
import org.elasticsearch.action.support.PlainActionFuture;
1616
import org.elasticsearch.action.support.WriteRequest;
17-
import org.elasticsearch.common.settings.Setting;
17+
import org.elasticsearch.common.settings.Settings;
1818
import org.elasticsearch.common.transport.TransportAddress;
1919
import org.elasticsearch.compute.operator.DriverTaskRunner;
2020
import org.elasticsearch.compute.operator.exchange.ExchangeService;
2121
import org.elasticsearch.core.TimeValue;
22-
import org.elasticsearch.plugins.Plugin;
2322
import org.elasticsearch.tasks.TaskCancelledException;
2423
import org.elasticsearch.tasks.TaskInfo;
25-
import org.elasticsearch.test.AbstractMultiClustersTestCase;
2624
import org.elasticsearch.transport.TransportService;
2725
import org.elasticsearch.xcontent.XContentBuilder;
2826
import org.elasticsearch.xcontent.json.JsonXContent;
2927
import org.elasticsearch.xpack.esql.EsqlTestUtils;
3028
import org.elasticsearch.xpack.esql.plugin.ComputeService;
31-
import org.junit.After;
32-
import org.junit.Before;
3329

3430
import java.util.ArrayList;
35-
import java.util.Collection;
3631
import java.util.List;
3732
import java.util.concurrent.TimeUnit;
3833

@@ -44,44 +39,20 @@
4439
import static org.hamcrest.Matchers.hasSize;
4540
import static org.hamcrest.Matchers.instanceOf;
4641

47-
public class CrossClusterCancellationIT extends AbstractMultiClustersTestCase {
42+
public class CrossClusterCancellationIT extends AbstractCrossClusterTestCase {
4843
private static final String REMOTE_CLUSTER = "cluster-a";
4944

5045
@Override
51-
protected Collection<String> remoteClusterAlias() {
46+
protected List<String> remoteClusterAlias() {
5247
return List.of(REMOTE_CLUSTER);
5348
}
5449

5550
@Override
56-
protected Collection<Class<? extends Plugin>> nodePlugins(String clusterAlias) {
57-
List<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins(clusterAlias));
58-
plugins.add(EsqlPluginWithEnterpriseOrTrialLicense.class);
59-
plugins.add(InternalExchangePlugin.class);
60-
plugins.add(SimplePauseFieldPlugin.class);
61-
return plugins;
62-
}
63-
64-
public static class InternalExchangePlugin extends Plugin {
65-
@Override
66-
public List<Setting<?>> getSettings() {
67-
return List.of(
68-
Setting.timeSetting(
69-
ExchangeService.INACTIVE_SINKS_INTERVAL_SETTING,
70-
TimeValue.timeValueMillis(between(3000, 4000)),
71-
Setting.Property.NodeScope
72-
)
73-
);
74-
}
75-
}
76-
77-
@Before
78-
public void resetPlugin() {
79-
SimplePauseFieldPlugin.resetPlugin();
80-
}
81-
82-
@After
83-
public void releasePlugin() {
84-
SimplePauseFieldPlugin.release();
51+
protected Settings nodeSettings() {
52+
return Settings.builder()
53+
.put(super.nodeSettings())
54+
.put(ExchangeService.INACTIVE_SINKS_INTERVAL_SETTING, TimeValue.timeValueMillis(between(3000, 4000)))
55+
.build();
8556
}
8657

8758
@Override

0 commit comments

Comments
 (0)