Skip to content

Commit e73e6b0

Browse files
authored
No special handling rules for skip_unavailable=true clusters at plan time other than disconnected exceptions (#120236) (#120628)
For ES|QL, we are moving to limit the scope of the skip_unavailable setting for remote clusters. Going forward, skip_unavailable will be considered for two scenarios: 1) inability to connect to a remote cluster ("unavailable") 2) whether to fail on execution time errors or not (inline with the upcoming allow_partial_search_results work for ES|QL). This PR reverses the special plan-time handling for skip_unavailable=true clusters that was added in #116348. Remote clusters, regardless of their skip_unavailable setting, will now use the same logic as the local cluster for index expression analysis at plan time, namely: 1) If any concrete index specified is missing from the cluster, a VerificationException will be thrown 2) If no matching index/alias/datastream was found on any cluster (even if all were specified with a wildcard), a VerificationException will be thrown Thus, we no longer require at least one matching index expression for skip_unavailable=false clusters either, as was done in the previous PR referenced above.
1 parent 54a08ad commit e73e6b0

File tree

7 files changed

+266
-1112
lines changed

7 files changed

+266
-1112
lines changed

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

Lines changed: 141 additions & 522 deletions
Large diffs are not rendered by default.

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,35 +91,32 @@ public void testFailed() throws Exception {
9191
assertThat(telemetry.getSuccessCount(), equalTo(0L));
9292
assertThat(telemetry.getByRemoteCluster().size(), equalTo(0));
9393

94-
// One remote is skipped, one is not
94+
// Errors from both remotes
9595
telemetry = getTelemetryFromFailedQuery("from logs-*,c*:no_such_index | stats sum (v)");
9696

9797
assertThat(telemetry.getTotalCount(), equalTo(1L));
9898
assertThat(telemetry.getSuccessCount(), equalTo(0L));
99-
assertThat(telemetry.getByRemoteCluster().size(), equalTo(1));
99+
assertThat(telemetry.getByRemoteCluster().size(), equalTo(0));
100100
assertThat(telemetry.getRemotesPerSearchAvg(), equalTo(2.0));
101101
assertThat(telemetry.getRemotesPerSearchMax(), equalTo(2L));
102-
assertThat(telemetry.getSearchCountWithSkippedRemotes(), equalTo(1L));
102+
assertThat(telemetry.getSearchCountWithSkippedRemotes(), equalTo(0L));
103103
Map<String, Long> expectedFailure = Map.of(CCSUsageTelemetry.Result.NOT_FOUND.getName(), 1L);
104104
assertThat(telemetry.getFailureReasons(), equalTo(expectedFailure));
105-
// cluster-b should be skipped
106-
assertThat(telemetry.getByRemoteCluster().get(REMOTE2).getCount(), equalTo(0L));
107-
assertThat(telemetry.getByRemoteCluster().get(REMOTE2).getSkippedCount(), equalTo(1L));
108105

109106
// this is only for cluster-a so no skipped remotes
110107
telemetry = getTelemetryFromFailedQuery("from logs-*,cluster-a:no_such_index | stats sum (v)");
111108
assertThat(telemetry.getTotalCount(), equalTo(2L));
112109
assertThat(telemetry.getSuccessCount(), equalTo(0L));
113-
assertThat(telemetry.getByRemoteCluster().size(), equalTo(1));
110+
assertThat(telemetry.getByRemoteCluster().size(), equalTo(0));
114111
assertThat(telemetry.getRemotesPerSearchAvg(), equalTo(2.0));
115112
assertThat(telemetry.getRemotesPerSearchMax(), equalTo(2L));
116-
assertThat(telemetry.getSearchCountWithSkippedRemotes(), equalTo(1L));
113+
assertThat(telemetry.getSearchCountWithSkippedRemotes(), equalTo(0L));
117114
expectedFailure = Map.of(CCSUsageTelemetry.Result.NOT_FOUND.getName(), 2L);
118115
assertThat(telemetry.getFailureReasons(), equalTo(expectedFailure));
119-
assertThat(telemetry.getByRemoteCluster().size(), equalTo(1));
116+
assertThat(telemetry.getByRemoteCluster().size(), equalTo(0));
120117
}
121118

122-
// TODO: enable when skip-up patch is merged
119+
// TODO: enable when skip-un patch is merged
123120
// public void testSkipAllRemotes() throws Exception {
124121
// var telemetry = getTelemetryFromQuery("from logs-*,c*:no_such_index | stats sum (v)", "unknown");
125122
//

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSessionCCSUtils.java

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,13 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionIn
199199

200200
/**
201201
* Rules enforced at planning time around non-matching indices
202-
* P1. fail query if no matching indices on any cluster (VerificationException) - that is handled elsewhere (TODO: document where)
203-
* P2. fail query if a skip_unavailable:false cluster has no matching indices (the local cluster already has this rule
204-
* enforced at planning time)
205-
* P3. fail query if the local cluster has no matching indices and a concrete index was specified
202+
* 1. fail query if no matching indices on any cluster (VerificationException) - that is handled elsewhere
203+
* 2. fail query if a cluster has no matching indices *and* a concrete index was specified - handled here
206204
*/
207205
String fatalErrorMessage = null;
208206
/*
209207
* These are clusters in the original request that are not present in the field-caps response. They were
210-
* specified with an index expression matched no indices, so the search on that cluster is done.
208+
* specified with an index expression that matched no indices, so the search on that cluster is done.
211209
* Mark it as SKIPPED with 0 shards searched and took=0.
212210
*/
213211
for (String c : clustersWithNoMatchingIndices) {
@@ -216,7 +214,7 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionIn
216214
continue;
217215
}
218216
final String indexExpression = executionInfo.getCluster(c).getIndexExpression();
219-
if (missingIndicesIsFatal(c, executionInfo)) {
217+
if (concreteIndexRequested(executionInfo.getCluster(c).getIndexExpression())) {
220218
String error = Strings.format(
221219
"Unknown index [%s]",
222220
(c.equals(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY) ? indexExpression : c + ":" + indexExpression)
@@ -227,10 +225,11 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionIn
227225
fatalErrorMessage += "; " + error;
228226
}
229227
} else {
230-
// handles local cluster (when no concrete indices requested) and skip_unavailable=true clusters
228+
// no matching indices and no concrete index requested - just skip it, no error
231229
EsqlExecutionInfo.Cluster.Status status;
232230
ShardSearchFailure failure;
233231
if (c.equals(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY)) {
232+
// never mark local cluster as SKIPPED
234233
status = EsqlExecutionInfo.Cluster.Status.SUCCESSFUL;
235234
failure = null;
236235
} else {
@@ -257,15 +256,7 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionIn
257256
}
258257

259258
// visible for testing
260-
static boolean missingIndicesIsFatal(String clusterAlias, EsqlExecutionInfo executionInfo) {
261-
// missing indices on local cluster is fatal only if a concrete index requested
262-
if (clusterAlias.equals(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY)) {
263-
return concreteIndexRequested(executionInfo.getCluster(clusterAlias).getIndexExpression());
264-
}
265-
return executionInfo.getCluster(clusterAlias).isSkipUnavailable() == false;
266-
}
267-
268-
private static boolean concreteIndexRequested(String indexExpression) {
259+
static boolean concreteIndexRequested(String indexExpression) {
269260
if (Strings.isNullOrBlank(indexExpression)) {
270261
return false;
271262
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ public void resolveAsMergedMapping(
9494
public IndexResolution mergedMappings(String indexPattern, FieldCapabilitiesResponse fieldCapsResponse) {
9595
assert ThreadPool.assertCurrentThreadPool(ThreadPool.Names.SEARCH_COORDINATION); // too expensive to run this on a transport worker
9696
if (fieldCapsResponse.getIndexResponses().isEmpty()) {
97-
// TODO in follow-on PR, handle the case where remotes were specified with non-existent indices, according to skip_unavailable
9897
return IndexResolution.notFound(indexPattern);
9998
}
10099

0 commit comments

Comments
 (0)