|
11 | 11 | import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; |
12 | 12 | import org.elasticsearch.client.internal.Client; |
13 | 13 | import org.elasticsearch.common.settings.Settings; |
| 14 | +import org.elasticsearch.index.IndexMode; |
| 15 | +import org.elasticsearch.index.IndexSettings; |
| 16 | +import org.elasticsearch.index.query.TermQueryBuilder; |
14 | 17 | import org.elasticsearch.xpack.core.enrich.EnrichPolicy; |
15 | 18 | import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction; |
16 | 19 | import org.elasticsearch.xpack.core.enrich.action.PutEnrichPolicyAction; |
|
28 | 31 |
|
29 | 32 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; |
30 | 33 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.getValuesList; |
| 34 | +import static org.elasticsearch.xpack.esql.action.EsqlQueryRequest.syncEsqlQueryRequest; |
31 | 35 | import static org.hamcrest.Matchers.containsString; |
32 | 36 | import static org.hamcrest.Matchers.empty; |
33 | 37 | import static org.hamcrest.Matchers.equalTo; |
@@ -557,6 +561,42 @@ public void testLookupJoinFieldTypes() throws IOException { |
557 | 561 | } |
558 | 562 | } |
559 | 563 |
|
| 564 | + public void testLookupJoinRetryAnalysis() throws IOException { |
| 565 | + setupClusters(3); |
| 566 | + setSkipUnavailable(REMOTE_CLUSTER_1, false); |
| 567 | + setSkipUnavailable(REMOTE_CLUSTER_2, false); |
| 568 | + |
| 569 | + var defaultSettings = Settings.builder(); |
| 570 | + createIndexWithDocument(LOCAL_CLUSTER, "data", defaultSettings, Map.of("key", 1, "f1", 1)); |
| 571 | + createIndexWithDocument(REMOTE_CLUSTER_1, "data", defaultSettings, Map.of("key", 2, "f2", 2)); |
| 572 | + createIndexWithDocument(REMOTE_CLUSTER_2, "data", defaultSettings, Map.of("key", 3, "f3", 3)); |
| 573 | + |
| 574 | + var lookupSettings = Settings.builder().put(IndexSettings.MODE.getKey(), IndexMode.LOOKUP); |
| 575 | + createIndexWithDocument(LOCAL_CLUSTER, "lookup", lookupSettings, Map.of("key", 1, "location", "local")); |
| 576 | + createIndexWithDocument(REMOTE_CLUSTER_1, "lookup", lookupSettings, Map.of("key", 2, "location", "remote-1")); |
| 577 | + // lookup is intentionally absent on REMOTE_CLUSTER_2 |
| 578 | + |
| 579 | + // The following query uses filter f2=2 that narrows down execution only to REMOTE_CLUSTER_1 index however, |
| 580 | + // later it uses `WHERE f1 == 1` esql condition that to an attribute present only on the local cluster index. |
| 581 | + // This causes analysis to fail and retry the entire query without a filter. |
| 582 | + // The second analysis executes against all cluster indices and should discover that lookup is absent on REMOTE_CLUSTER_2. |
| 583 | + expectThrows( |
| 584 | + VerificationException.class, |
| 585 | + containsString("lookup index [lookup] is not available in remote cluster [remote-b]"), |
| 586 | + () -> runQuery( |
| 587 | + syncEsqlQueryRequest().query("FROM data,*:data | LOOKUP JOIN lookup ON key | WHERE f1 == 1") |
| 588 | + .filter(new TermQueryBuilder("f2", 2)) |
| 589 | + ) |
| 590 | + ); |
| 591 | + } |
| 592 | + |
| 593 | + private void createIndexWithDocument(String clusterAlias, String indexName, Settings.Builder settings, Map<String, Object> source) { |
| 594 | + var client = client(clusterAlias); |
| 595 | + client.admin().indices().prepareCreate(indexName).setSettings(settings).get(); |
| 596 | + client.prepareIndex(indexName).setSource(source).get(); |
| 597 | + client.admin().indices().prepareRefresh(indexName).get(); |
| 598 | + } |
| 599 | + |
560 | 600 | protected Map<String, Object> setupClustersAndLookups() throws IOException { |
561 | 601 | var setupData = setupClusters(2); |
562 | 602 | populateLookupIndex(LOCAL_CLUSTER, "values_lookup", 10); |
|
0 commit comments