|
82 | 82 | import java.util.List; |
83 | 83 | import java.util.Map; |
84 | 84 | import java.util.Set; |
85 | | -import java.util.stream.Collectors; |
86 | 85 | import java.util.stream.Stream; |
87 | 86 |
|
88 | 87 | import static java.util.stream.Collectors.toSet; |
89 | 88 | import static org.elasticsearch.index.query.QueryBuilders.boolQuery; |
90 | 89 | import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; |
91 | 90 | import static org.elasticsearch.xpack.esql.plan.logical.join.InlineJoin.firstSubPlan; |
| 91 | +import static org.elasticsearch.xpack.esql.session.EsqlCCSUtils.getRemotesOf; |
| 92 | +import static org.elasticsearch.xpack.esql.session.EsqlCCSUtils.qualifyWithRunningRemotes; |
92 | 93 |
|
93 | 94 | public class EsqlSession { |
94 | 95 |
|
@@ -407,36 +408,20 @@ private void preAnalyzeLookupIndex( |
407 | 408 | EsqlExecutionInfo executionInfo, |
408 | 409 | ActionListener<PreAnalysisResult> listener |
409 | 410 | ) { |
410 | | - String localPattern = lookupIndexPattern.indexPattern(); |
411 | | - assert RemoteClusterAware.isRemoteIndexName(localPattern) == false |
412 | | - : "Lookup index name should not include remote, but got: " + localPattern; |
| 411 | + String lookupJoinPattern = lookupIndexPattern.indexPattern(); |
| 412 | + assert RemoteClusterAware.isRemoteIndexName(lookupJoinPattern) == false |
| 413 | + : "Lookup index name should not include remote, but got: " + lookupJoinPattern; |
413 | 414 | assert ThreadPool.assertCurrentThreadPool( |
414 | 415 | ThreadPool.Names.SEARCH, |
415 | 416 | ThreadPool.Names.SEARCH_COORDINATION, |
416 | 417 | ThreadPool.Names.SYSTEM_READ |
417 | 418 | ); |
418 | | - Set<String> fieldNames = result.wildcardJoinIndices().contains(localPattern) ? IndexResolver.ALL_FIELDS : result.fieldNames; |
419 | | - |
420 | | - String patternWithRemotes; |
421 | | - |
422 | | - if (executionInfo.getClusters().isEmpty()) { |
423 | | - patternWithRemotes = localPattern; |
424 | | - } else { |
425 | | - // convert index -> cluster1:index,cluster2:index, etc.for each running cluster |
426 | | - patternWithRemotes = executionInfo.getClusterStates(EsqlExecutionInfo.Cluster.Status.RUNNING) |
427 | | - .map(c -> RemoteClusterAware.buildRemoteIndexName(c.getClusterAlias(), localPattern)) |
428 | | - .collect(Collectors.joining(",")); |
429 | | - } |
430 | | - if (patternWithRemotes.isEmpty()) { |
431 | | - return; |
432 | | - } |
433 | | - // call the EsqlResolveFieldsAction (field-caps) to resolve indices and get field types |
434 | 419 | indexResolver.resolveAsMergedMapping( |
435 | | - patternWithRemotes, |
436 | | - fieldNames, |
| 420 | + qualifyWithRunningRemotes(lookupJoinPattern, getRemotesOf(result.indices.resolvedIndices()), executionInfo), |
| 421 | + result.wildcardJoinIndices().contains(lookupJoinPattern) ? IndexResolver.ALL_FIELDS : result.fieldNames, |
437 | 422 | null, |
438 | 423 | false, |
439 | | - listener.map(indexResolution -> receiveLookupIndexResolution(result, localPattern, executionInfo, indexResolution)) |
| 424 | + listener.map(indexResolution -> receiveLookupIndexResolution(result, lookupJoinPattern, executionInfo, indexResolution)) |
440 | 425 | ); |
441 | 426 | } |
442 | 427 |
|
@@ -634,51 +619,29 @@ private void preAnalyzeMainIndices( |
634 | 619 | ThreadPool.Names.SYSTEM_READ |
635 | 620 | ); |
636 | 621 | // TODO we plan to support joins in the future when possible, but for now we'll just fail early if we see one |
637 | | - List<IndexPattern> indices = preAnalysis.indices; |
638 | | - if (indices.size() > 1) { |
639 | | - // Note: JOINs are not supported but we detect them when |
640 | | - listener.onFailure(new MappingException("Queries with multiple indices are not supported")); |
641 | | - } else if (indices.size() == 1) { |
642 | | - IndexPattern table = indices.getFirst(); |
643 | | - |
644 | | - // if the preceding call to the enrich policy API found unavailable clusters, recreate the index expression to search |
645 | | - // based only on available clusters (which could now be an empty list) |
646 | | - String indexExpressionToResolve = EsqlCCSUtils.createIndexExpressionFromAvailableClusters(executionInfo); |
647 | | - if (indexExpressionToResolve.isEmpty()) { |
648 | | - // if this was a pure remote CCS request (no local indices) and all remotes are offline, return an empty IndexResolution |
649 | | - listener.onResponse( |
650 | | - result.withIndexResolution(IndexResolution.valid(new EsIndex(table.indexPattern(), Map.of(), Map.of()))) |
651 | | - ); |
652 | | - } else { |
653 | | - boolean includeAllDimensions = false; |
654 | | - // call the EsqlResolveFieldsAction (field-caps) to resolve indices and get field types |
655 | | - if (preAnalysis.indexMode == IndexMode.TIME_SERIES) { |
656 | | - includeAllDimensions = true; |
657 | | - // TODO: Maybe if no indices are returned, retry without index mode and provide a clearer error message. |
658 | | - var indexModeFilter = new TermQueryBuilder(IndexModeFieldMapper.NAME, IndexMode.TIME_SERIES.getName()); |
659 | | - if (requestFilter != null) { |
660 | | - requestFilter = new BoolQueryBuilder().filter(requestFilter).filter(indexModeFilter); |
661 | | - } else { |
662 | | - requestFilter = indexModeFilter; |
663 | | - } |
664 | | - } |
665 | | - indexResolver.resolveAsMergedMapping( |
666 | | - indexExpressionToResolve, |
667 | | - result.fieldNames, |
| 622 | + switch (preAnalysis.indices.size()) { |
| 623 | + case 0 -> listener.onResponse(result.withIndexResolution(IndexResolution.invalid("[none specified]"))); |
| 624 | + case 1 -> indexResolver.resolveAsMergedMapping( |
| 625 | + preAnalysis.indices.getFirst().indexPattern(), |
| 626 | + result.fieldNames, |
| 627 | + merge( |
668 | 628 | requestFilter, |
669 | | - includeAllDimensions, |
670 | | - listener.delegateFailure((l, indexResolution) -> { |
671 | | - l.onResponse(result.withIndexResolution(indexResolution)); |
672 | | - }) |
673 | | - ); |
674 | | - } |
| 629 | + preAnalysis.indexMode == IndexMode.TIME_SERIES |
| 630 | + ? new TermQueryBuilder(IndexModeFieldMapper.NAME, IndexMode.TIME_SERIES.getName()) |
| 631 | + : null |
| 632 | + ), |
| 633 | + preAnalysis.indexMode == IndexMode.TIME_SERIES, |
| 634 | + listener.delegateFailure((l, indexResolution) -> l.onResponse(result.withIndexResolution(indexResolution))) |
| 635 | + ); |
| 636 | + default -> listener.onFailure(new MappingException("Queries with multiple indices are not supported")); |
| 637 | + } |
| 638 | + } |
| 639 | + |
| 640 | + private static QueryBuilder merge(QueryBuilder q1, QueryBuilder q2) { |
| 641 | + if (q1 != null && q2 != null) { |
| 642 | + return new BoolQueryBuilder().filter(q1).filter(q2); |
675 | 643 | } else { |
676 | | - try { |
677 | | - // occurs when dealing with local relations (row a = 1) |
678 | | - listener.onResponse(result.withIndexResolution(IndexResolution.invalid("[none specified]"))); |
679 | | - } catch (Exception ex) { |
680 | | - listener.onFailure(ex); |
681 | | - } |
| 644 | + return q1 != null ? q1 : q2; |
682 | 645 | } |
683 | 646 | } |
684 | 647 |
|
|
0 commit comments