99
1010import org .elasticsearch .action .ActionListener ;
1111import org .elasticsearch .action .OriginalIndices ;
12+ import org .elasticsearch .action .search .ShardSearchFailure ;
1213import org .elasticsearch .action .support .IndicesOptions ;
1314import org .elasticsearch .action .support .SubscribableListener ;
1415import org .elasticsearch .common .Strings ;
1819import org .elasticsearch .compute .data .Page ;
1920import org .elasticsearch .compute .operator .DriverProfile ;
2021import org .elasticsearch .core .Releasables ;
22+ import org .elasticsearch .core .TimeValue ;
2123import org .elasticsearch .index .IndexMode ;
2224import org .elasticsearch .index .mapper .IndexModeFieldMapper ;
2325import org .elasticsearch .index .query .BoolQueryBuilder ;
8486import org .elasticsearch .xpack .esql .telemetry .PlanTelemetry ;
8587
8688import java .util .ArrayList ;
89+ import java .util .Arrays ;
8790import java .util .HashMap ;
8891import java .util .Iterator ;
8992import java .util .List ;
@@ -363,10 +366,16 @@ public void analyzedPlan(
363366 final List <IndexPattern > indices = preAnalysis .indices ;
364367
365368 EsqlCCSUtils .checkForCcsLicense (executionInfo , indices , indicesExpressionGrouper , configuredClusters , verifier .licenseState ());
366- initializeClusterData (indices , executionInfo );
369+
370+ final Set <String > targetClusters = enrichPolicyResolver .groupIndicesPerCluster (
371+ configuredClusters ,
372+ indices .stream ()
373+ .flatMap (index -> Arrays .stream (Strings .commaDelimitedListToStringArray (index .indexPattern ())))
374+ .toArray (String []::new )
375+ ).keySet ();
367376
368377 var listener = SubscribableListener .<EnrichResolution >newForked (
369- l -> enrichPolicyResolver .resolvePolicies (unresolvedPolicies , executionInfo , l )
378+ l -> enrichPolicyResolver .resolvePolicies (targetClusters , unresolvedPolicies , l )
370379 )
371380 .<PreAnalysisResult >andThen ((l , enrichResolution ) -> resolveFieldNames (parsed , enrichResolution , l ))
372381 .<PreAnalysisResult >andThen ((l , preAnalysisResult ) -> resolveInferences (preAnalysis .inferencePlans , preAnalysisResult , l ));
@@ -392,6 +401,12 @@ public void analyzedPlan(
392401 }).<PreAnalysisResult >andThen ((l , result ) -> {
393402 assert requestFilter != null : "The second pre-analysis shouldn't take place when there is no index filter in the request" ;
394403
404+ // "reset" execution information for all ccs or non-ccs (local) clusters, since we are performing the indices
405+ // resolving one more time (the first attempt failed and the query had a filter)
406+ for (String clusterAlias : executionInfo .clusterAliases ()) {
407+ executionInfo .swapCluster (clusterAlias , (k , v ) -> null );
408+ }
409+
395410 // here the requestFilter is set to null, performing the pre-analysis after the first step failed
396411 preAnalyzeMainIndices (preAnalysis , executionInfo , result , null , l );
397412 }).<LogicalPlan >andThen ((l , result ) -> {
@@ -421,26 +436,6 @@ private void preAnalyzeLookupIndex(IndexPattern table, PreAnalysisResult result,
421436 // TODO: Verify that the resolved index actually has indexMode: "lookup"
422437 }
423438
424- private void initializeClusterData (List <IndexPattern > indices , EsqlExecutionInfo executionInfo ) {
425- if (indices .isEmpty ()) {
426- return ;
427- }
428- assert indices .size () == 1 : "Only single index pattern is supported" ;
429- Map <String , OriginalIndices > clusterIndices = indicesExpressionGrouper .groupIndices (
430- configuredClusters ,
431- IndicesOptions .DEFAULT ,
432- indices .getFirst ().indexPattern ()
433- );
434- for (Map .Entry <String , OriginalIndices > entry : clusterIndices .entrySet ()) {
435- final String clusterAlias = entry .getKey ();
436- String indexExpr = Strings .arrayToCommaDelimitedString (entry .getValue ().indices ());
437- executionInfo .swapCluster (clusterAlias , (k , v ) -> {
438- assert v == null : "No cluster for " + clusterAlias + " should have been added to ExecutionInfo yet" ;
439- return new EsqlExecutionInfo .Cluster (clusterAlias , indexExpr , executionInfo .isSkipUnavailable (clusterAlias ));
440- });
441- }
442- }
443-
444439 private void preAnalyzeMainIndices (
445440 PreAnalyzer .PreAnalysis preAnalysis ,
446441 EsqlExecutionInfo executionInfo ,
@@ -454,8 +449,38 @@ private void preAnalyzeMainIndices(
454449 // Note: JOINs are not supported but we detect them when
455450 listener .onFailure (new MappingException ("Queries with multiple indices are not supported" ));
456451 } else if (indices .size () == 1 ) {
452+ // known to be unavailable from the enrich policy API call
453+ Map <String , Exception > unavailableClusters = result .enrichResolution .getUnavailableClusters ();
457454 IndexPattern table = indices .getFirst ();
458455
456+ Map <String , OriginalIndices > clusterIndices = indicesExpressionGrouper .groupIndices (
457+ configuredClusters ,
458+ IndicesOptions .DEFAULT ,
459+ table .indexPattern ()
460+ );
461+ for (Map .Entry <String , OriginalIndices > entry : clusterIndices .entrySet ()) {
462+ final String clusterAlias = entry .getKey ();
463+ String indexExpr = Strings .arrayToCommaDelimitedString (entry .getValue ().indices ());
464+ executionInfo .swapCluster (clusterAlias , (k , v ) -> {
465+ assert v == null : "No cluster for " + clusterAlias + " should have been added to ExecutionInfo yet" ;
466+ if (unavailableClusters .containsKey (k )) {
467+ return new EsqlExecutionInfo .Cluster (
468+ clusterAlias ,
469+ indexExpr ,
470+ executionInfo .isSkipUnavailable (clusterAlias ),
471+ EsqlExecutionInfo .Cluster .Status .SKIPPED ,
472+ 0 ,
473+ 0 ,
474+ 0 ,
475+ 0 ,
476+ List .of (new ShardSearchFailure (unavailableClusters .get (k ))),
477+ new TimeValue (0 )
478+ );
479+ } else {
480+ return new EsqlExecutionInfo .Cluster (clusterAlias , indexExpr , executionInfo .isSkipUnavailable (clusterAlias ));
481+ }
482+ });
483+ }
459484 // if the preceding call to the enrich policy API found unavailable clusters, recreate the index expression to search
460485 // based only on available clusters (which could now be an empty list)
461486 String indexExpressionToResolve = EsqlCCSUtils .createIndexExpressionFromAvailableClusters (executionInfo );
0 commit comments