|
@@ -43,6 +43,7 @@ import static org.hamcrest.Matchers.equalTo;
|
|
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|
|
import static org.hamcrest.Matchers.hasSize;
|
|
|
import static org.hamcrest.Matchers.is;
|
|
|
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
|
|
|
|
|
public class CrossClustersQueryIT extends AbstractMultiClustersTestCase {
|
|
|
private static final String REMOTE_CLUSTER = "cluster-a";
|
|
@@ -339,6 +340,108 @@ public class CrossClustersQueryIT extends AbstractMultiClustersTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Searches with LIMIT 0 are used by Kibana to get a list of columns. After the initial planning
|
|
|
+ * (which involves cross-cluster field-caps calls), it is a coordinator only operation at query time
|
|
|
+ * which uses a different pathway compared to queries that require data node (and remote data node) operations
|
|
|
+ * at query time.
|
|
|
+ */
|
|
|
+ public void testCCSExecutionOnSearchesWithLimit0() {
|
|
|
+ setupTwoClusters();
|
|
|
+
|
|
|
+ // Ensure non-cross cluster queries have overall took time
|
|
|
+ try (EsqlQueryResponse resp = runQuery("FROM logs* | LIMIT 0")) {
|
|
|
+ EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
|
|
|
+ assertNotNull(executionInfo);
|
|
|
+ assertThat(executionInfo.isCrossClusterSearch(), is(false));
|
|
|
+ assertThat(executionInfo.overallTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ensure cross-cluster searches have overall took time and correct per-cluster details in EsqlExecutionInfo
|
|
|
+ try (EsqlQueryResponse resp = runQuery("FROM logs*,cluster-a:* | LIMIT 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, LOCAL_CLUSTER)));
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER);
|
|
|
+ assertThat(remoteCluster.getIndexExpression(), equalTo("*"));
|
|
|
+ assertThat(remoteCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
|
|
|
+ assertThat(remoteCluster.getTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ assertThat(remoteCluster.getTook().millis(), lessThanOrEqualTo(overallTookMillis));
|
|
|
+ assertNull(remoteCluster.getTotalShards());
|
|
|
+ assertNull(remoteCluster.getSuccessfulShards());
|
|
|
+ assertNull(remoteCluster.getSkippedShards());
|
|
|
+ assertNull(remoteCluster.getFailedShards());
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
|
|
|
+ assertThat(localCluster.getIndexExpression(), equalTo("logs*"));
|
|
|
+ assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
|
|
|
+ assertThat(localCluster.getTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ assertThat(localCluster.getTook().millis(), lessThanOrEqualTo(overallTookMillis));
|
|
|
+ assertNull(localCluster.getTotalShards());
|
|
|
+ assertNull(localCluster.getSuccessfulShards());
|
|
|
+ assertNull(localCluster.getSkippedShards());
|
|
|
+ assertNull(localCluster.getFailedShards());
|
|
|
+ }
|
|
|
+
|
|
|
+ try (EsqlQueryResponse resp = runQuery("FROM logs*,cluster-a:nomatch* | LIMIT 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, LOCAL_CLUSTER)));
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER);
|
|
|
+ assertThat(remoteCluster.getIndexExpression(), equalTo("nomatch*"));
|
|
|
+ assertThat(remoteCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
|
|
|
+ assertThat(remoteCluster.getTook().millis(), equalTo(0L));
|
|
|
+ assertThat(remoteCluster.getTotalShards(), equalTo(0));
|
|
|
+ assertThat(remoteCluster.getSuccessfulShards(), equalTo(0));
|
|
|
+ assertThat(remoteCluster.getSkippedShards(), equalTo(0));
|
|
|
+ assertThat(remoteCluster.getFailedShards(), equalTo(0));
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
|
|
|
+ assertThat(localCluster.getIndexExpression(), equalTo("logs*"));
|
|
|
+ assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
|
|
|
+ assertThat(localCluster.getTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ assertThat(localCluster.getTook().millis(), lessThanOrEqualTo(overallTookMillis));
|
|
|
+ assertNull(localCluster.getTotalShards());
|
|
|
+ assertNull(localCluster.getSuccessfulShards());
|
|
|
+ assertNull(localCluster.getSkippedShards());
|
|
|
+ assertNull(localCluster.getFailedShards());
|
|
|
+ }
|
|
|
+
|
|
|
+ try (EsqlQueryResponse resp = runQuery("FROM nomatch*,cluster-a:* | LIMIT 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, LOCAL_CLUSTER)));
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER);
|
|
|
+ assertThat(remoteCluster.getIndexExpression(), equalTo("*"));
|
|
|
+ assertThat(remoteCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
|
|
|
+ assertThat(remoteCluster.getTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ assertThat(remoteCluster.getTook().millis(), lessThanOrEqualTo(overallTookMillis));
|
|
|
+ assertNull(remoteCluster.getTotalShards());
|
|
|
+ assertNull(remoteCluster.getSuccessfulShards());
|
|
|
+ assertNull(remoteCluster.getSkippedShards());
|
|
|
+ assertNull(remoteCluster.getFailedShards());
|
|
|
+
|
|
|
+ EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
|
|
|
+ assertThat(localCluster.getIndexExpression(), equalTo("nomatch*"));
|
|
|
+ // TODO: in https://github.com/elastic/elasticsearch/issues/112886, this will be changed to be SKIPPED
|
|
|
+ assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
|
|
|
+ assertThat(localCluster.getTook().millis(), greaterThanOrEqualTo(0L));
|
|
|
+ assertThat(localCluster.getTook().millis(), lessThanOrEqualTo(overallTookMillis));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public void testMetadataIndex() {
|
|
|
Map<String, Object> testClusterInfo = setupTwoClusters();
|
|
|
int localNumShards = (Integer) testClusterInfo.get("local.num_shards");
|