Skip to content

Fix missing index exception handling #126738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Apr 24, 2025
Merged
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
436a831
Fix missing index handling for partial-enabled queries
smalyshev Apr 9, 2025
0bacef5
Merge branch 'main' into fix-missing-index-handling
smalyshev Apr 9, 2025
39141cc
Oops shouldn't delete that
smalyshev Apr 9, 2025
5ffdc46
Merge branch 'main' into fix-missing-index-handling
smalyshev Apr 10, 2025
d3421a1
Set ignore_unavaliable to false
smalyshev Apr 11, 2025
374df05
Merge branch 'main' into fix-missing-index-handling
smalyshev Apr 11, 2025
06ee627
Revert
smalyshev Apr 12, 2025
bb890ec
Update docs/changelog/126738.yaml
smalyshev Apr 12, 2025
88602d4
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 12, 2025
954f753
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 13, 2025
be41b3e
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 14, 2025
c2159d2
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 14, 2025
9f05ded
Test for CCS with filters
smalyshev Apr 14, 2025
6f348b9
[CI] Auto commit changes from spotless
elasticsearchmachine Apr 15, 2025
7313daf
Partial fix for CCS/filters problems
smalyshev Apr 17, 2025
fb7fb6a
fix tests
smalyshev Apr 18, 2025
8610845
Merge branch 'main' into fix-filter-ccs
smalyshev Apr 18, 2025
a51bf2a
More tests
smalyshev Apr 18, 2025
d58d6e6
We can not eliminate some filtered runtime calls since there could be…
smalyshev Apr 18, 2025
9f432eb
Merge branch 'main' into fix-filter-ccs
smalyshev Apr 18, 2025
c730f21
Merge branch 'main' into fix-filter-ccs
smalyshev Apr 21, 2025
d2df0e1
Improve comments
smalyshev Apr 21, 2025
492daae
Add column tests
smalyshev Apr 21, 2025
9cc3fad
More tests for unavailable
smalyshev Apr 21, 2025
14e70bb
Merge branch 'main' into fix-filter-ccs
smalyshev Apr 21, 2025
f9d78f2
Merge branch 'main' into fix-filter-ccs
smalyshev Apr 22, 2025
216bd11
Declutter asserts
smalyshev Apr 22, 2025
6cbfe19
Remove this change, may not be needed
smalyshev Apr 22, 2025
9098695
add async
smalyshev Apr 22, 2025
8ca2529
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 22, 2025
cd2e7a6
Merge branch 'fix-filter-ccs' into fix-missing-index-exception
smalyshev Apr 22, 2025
c428a43
Update tests
smalyshev Apr 22, 2025
1dad0fb
Remove the test, no longer needed
smalyshev Apr 22, 2025
2a4a1fd
Merge branch 'main' into fix-missing-index-exception
smalyshev Apr 23, 2025
75913eb
Delete docs/changelog/126738.yaml
smalyshev Apr 23, 2025
a8e3efb
Fix merge
smalyshev Apr 23, 2025
44e559a
oops merge dropped this change, restore
smalyshev Apr 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More tests
  • Loading branch information
smalyshev committed Apr 18, 2025
commit a51bf2a6e3c41a1e2e30cee5875843fa05da8d1f
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package org.elasticsearch.xpack.esql.action;

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
Expand All @@ -15,6 +16,7 @@
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.xpack.esql.VerificationException;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -37,6 +39,11 @@ protected Map<String, Boolean> skipUnavailableForRemoteClusters() {
return Map.of(REMOTE_CLUSTER_1, false, REMOTE_CLUSTER_2, false);
}

@Override
protected boolean reuseClusters() {
return false;
}

protected void assertClusterMetadataSuccess(EsqlExecutionInfo.Cluster clusterMetatata, int shards, long took, String indexExpression) {
assertThat(clusterMetatata.getIndexExpression(), equalTo(indexExpression));
assertThat(clusterMetatata.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
Expand Down Expand Up @@ -75,6 +82,17 @@ protected void assertClusterMetadataSkippedShards(
assertThat(clusterMetatata.getFailedShards(), equalTo(0));
}

protected void assertClusterMetadataSkipped(EsqlExecutionInfo.Cluster clusterMetatata, long took, String indexExpression) {
assertThat(clusterMetatata.getIndexExpression(), equalTo(indexExpression));
assertThat(clusterMetatata.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
assertThat(clusterMetatata.getTook().millis(), greaterThanOrEqualTo(0L));
assertThat(clusterMetatata.getTook().millis(), lessThanOrEqualTo(took));
assertThat(clusterMetatata.getTotalShards(), equalTo(0));
assertThat(clusterMetatata.getSuccessfulShards(), equalTo(0));
assertThat(clusterMetatata.getSkippedShards(), equalTo(0));
assertThat(clusterMetatata.getFailedShards(), equalTo(0));
}

protected EsqlQueryResponse runQuery(String query, Boolean ccsMetadataInResponse, QueryBuilder filter) {
EsqlQueryRequest request = EsqlQueryRequest.syncEsqlQueryRequest();
request.query(query);
Expand Down Expand Up @@ -244,11 +262,12 @@ public void testFilterWithMissingIndex() {
populateDateIndex(LOCAL_CLUSTER, LOCAL_INDEX, localShards, docsTest1, "2024-11-26");
populateDateIndex(REMOTE_CLUSTER_1, REMOTE_INDEX, remoteShards, docsTest2, "2023-11-26");

int docSize = docsTest1;
int count = 0;
for (var filter : List.of(
new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
)) {
count++;
// Local index missing
VerificationException e = expectThrows(
VerificationException.class,
Expand All @@ -264,31 +283,162 @@ public void testFilterWithMissingIndex() {
// e = expectThrows(VerificationException.class, () -> runQuery("from missing,logs-1", randomBoolean(), filter).close());
// assertThat(e.getDetailedMessage(), containsString("Unknown index [missing]"));
// Local index missing + existing remote
e = expectThrows(VerificationException.class, () -> runQuery("from missing,c*:logs-2", randomBoolean(), filter).close());
e = expectThrows(VerificationException.class, () -> runQuery("from missing,cluster-a:logs-2", randomBoolean(), filter).close());
assertThat(e.getDetailedMessage(), containsString("Unknown index [missing]"));
// Wildcard index missing
e = expectThrows(VerificationException.class, () -> runQuery("from missing*", randomBoolean(), filter).close());
assertThat(e.getDetailedMessage(), containsString("Unknown index [missing*]"));
// Wildcard index missing + existing index
try (EsqlQueryResponse resp = runQuery("from missing*,logs-1", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(docSize));
// for the second round
docSize = 0;
assertThat(values, hasSize(count > 1 ? 0 : docsTest1));
}
}
}

public void testFilterWithMissingRemoteIndex() {
// TODO
int docsTest1 = 50;
int docsTest2 = 30;
int localShards = randomIntBetween(1, 5);
int remoteShards = randomIntBetween(1, 5);
populateDateIndex(LOCAL_CLUSTER, LOCAL_INDEX, localShards, docsTest1, "2024-11-26");
populateDateIndex(REMOTE_CLUSTER_1, REMOTE_INDEX, remoteShards, docsTest2, "2023-11-26");

int count = 0;
for (var filter : List.of(
new RangeQueryBuilder("@timestamp").from("2023-01-01").to("now"),
new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
)) {
count++;
// Local index missing
VerificationException e = expectThrows(
VerificationException.class,
() -> runQuery("from cluster-a:missing", randomBoolean(), filter).close()
);
assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
// Local index missing + wildcards
// FIXME: planner does not catch this now
// e = expectThrows(VerificationException.class, () -> runQuery("from cluster-a:missing,cluster-a:logs*", randomBoolean(),
// filter).close());
// assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
// Local index missing + existing index
// FIXME: planner does not catch this now
// e = expectThrows(VerificationException.class, () -> runQuery("from cluster-a:missing,cluster-a:logs-2", randomBoolean(),
// filter).close());
// assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
// Local index + missing remote
e = expectThrows(VerificationException.class, () -> runQuery("from logs-1,cluster-a:missing", randomBoolean(), filter).close());
assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
// Wildcard index missing
e = expectThrows(VerificationException.class, () -> runQuery("from cluster-a:missing*", randomBoolean(), filter).close());
assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing*]"));
// Wildcard index missing + existing remote index
try (EsqlQueryResponse resp = runQuery("from cluster-a:missing*,cluster-a:logs-2", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(count > 1 ? 0 : docsTest2));
}
// Wildcard index missing + existing local index
try (EsqlQueryResponse resp = runQuery("from cluster-a:missing*,logs-1", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(count > 2 ? 0 : docsTest1));
}
}
}

public void testFilterWithUnavailableRemote() {
// TODO
public void testFilterWithUnavailableRemote() throws IOException {
int docsTest1 = 50;
int localShards = randomIntBetween(1, 5);
populateDateIndex(LOCAL_CLUSTER, LOCAL_INDEX, localShards, docsTest1, "2024-11-26");
cluster(REMOTE_CLUSTER_1).close();

for (var filter : List.of(
new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
)) {
// One index
var e = expectThrows(ElasticsearchException.class, () -> runQuery("from cluster-a:log-2", randomBoolean(), filter).close());
// Two indices
e = expectThrows(ElasticsearchException.class, () -> runQuery("from logs-1,cluster-a:log-2", randomBoolean(), filter).close());
// Wildcard
e = expectThrows(ElasticsearchException.class, () -> runQuery("from logs-1,cluster-a:log*", randomBoolean(), filter).close());
}
}

public void testFilterWithUnavailableRemoteAndSkipUnavailable() {
// TODO
public void testFilterWithUnavailableRemoteAndSkipUnavailable() throws IOException {
setSkipUnavailable(REMOTE_CLUSTER_1, true);
int docsTest1 = 50;
int localShards = randomIntBetween(1, 5);
populateDateIndex(LOCAL_CLUSTER, LOCAL_INDEX, localShards, docsTest1, "2024-11-26");
cluster(REMOTE_CLUSTER_1).close();
int count = 0;

for (var filter : List.of(
new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
)) {
count++;
// One index
try (EsqlQueryResponse resp = runQuery("from cluster-a:logs-2", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(0));
EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
assertNotNull(executionInfo);
assertThat(executionInfo.isCrossClusterSearch(), is(true));
long overallTookMillis = executionInfo.overallTook().millis();
assertThat(overallTookMillis, greaterThanOrEqualTo(0L));

assertThat(executionInfo.clusterAliases(), equalTo(Set.of(REMOTE_CLUSTER_1)));

EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1);
assertClusterMetadataSkipped(remoteCluster, overallTookMillis, "logs-2");
}
// Two indices
try (EsqlQueryResponse resp = runQuery("from logs-1,cluster-a:logs-2", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(count > 1 ? 0 : docsTest1));
EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
assertNotNull(executionInfo);
assertThat(executionInfo.isCrossClusterSearch(), is(true));
long overallTookMillis = executionInfo.overallTook().millis();
assertThat(overallTookMillis, greaterThanOrEqualTo(0L));

assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1)));

EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1);
assertClusterMetadataSkipped(remoteCluster, overallTookMillis, "logs-2");

EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
if (count > 1) {
assertClusterMetadataNoShards(localCluster, localShards, overallTookMillis, "logs-1");
} else {
assertClusterMetadataSuccess(localCluster, localShards, overallTookMillis, "logs-1");
}
}
// Wildcard
try (EsqlQueryResponse resp = runQuery("from logs-1,cluster-a:logs*", randomBoolean(), filter)) {
List<List<Object>> values = getValuesList(resp);
assertThat(values, hasSize(count > 1 ? 0 : docsTest1));
EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
assertNotNull(executionInfo);
assertThat(executionInfo.isCrossClusterSearch(), is(true));
long overallTookMillis = executionInfo.overallTook().millis();
assertThat(overallTookMillis, greaterThanOrEqualTo(0L));

assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1)));

EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1);
assertClusterMetadataSkipped(remoteCluster, overallTookMillis, "logs*");

EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
if (count > 1) {
assertClusterMetadataNoShards(localCluster, localShards, overallTookMillis, "logs-1");
} else {
assertClusterMetadataSuccess(localCluster, localShards, overallTookMillis, "logs-1");
}
}
}

}

protected void populateDateIndex(String clusterAlias, String indexName, int numShards, int numDocs, String date) {
Expand Down