From fcc1dcfa03a1f62d517b3058ccbb93c4845c2222 Mon Sep 17 00:00:00 2001 From: piergm <134913285+piergm@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:45:41 +0100 Subject: [PATCH 1/6] allows fc to be cross project --- .../fieldcaps/FieldCapabilitiesRequest.java | 5 +++ .../fieldcaps/FieldCapabilitiesResponse.java | 5 +++ .../TransportFieldCapabilitiesAction.java | 38 ++++++++++++++++--- .../action/RestFieldCapabilitiesAction.java | 17 ++++++++- 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java index c17cae1779056..cacf1e9dedba2 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java @@ -259,6 +259,11 @@ public boolean allowsRemoteIndices() { return true; } + @Override + public boolean allowsCrossProject() { + return true; + } + @Override public boolean includeDataStreams() { return true; diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java index 8372ad5909de1..e42ee0d30f2e4 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java @@ -321,6 +321,11 @@ public Builder withResolvedRemotelyBuilder(Map resolvedRemotely) { + this.resolvedRemotely = resolvedRemotely; + return this; + } + public Builder withResolvedLocally(ResolvedIndexExpressions resolvedLocally) { this.resolvedLocally = resolvedLocally; return this; diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java index 87f74c0704c53..78f2d1bdb7f4b 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java @@ -55,6 +55,7 @@ import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.search.SearchService; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; @@ -88,6 +89,8 @@ import static org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest.RESOLVED_FIELDS_CAPS; import static org.elasticsearch.action.search.TransportSearchHelper.checkCCSVersionCompatibility; +import static org.elasticsearch.search.crossproject.CrossProjectIndexResolutionValidator.indicesOptionsForCrossProjectFanout; +import static org.elasticsearch.search.crossproject.CrossProjectIndexResolutionValidator.validate; public class TransportFieldCapabilitiesAction extends HandledTransportAction { public static final String EXCLUSION = "-"; @@ -110,6 +113,7 @@ public class TransportFieldCapabilitiesAction extends HandledTransportAction void doExecuteForked( long nowInMillis = request.nowInMillis() == null ? System.currentTimeMillis() : request.nowInMillis(); final ProjectState projectState = projectResolver.getProjectState(clusterService.state()); final var minTransportVersion = new AtomicReference<>(clusterService.state().getMinTransportVersion()); + final IndicesOptions originalIndicesOptions = request.indicesOptions(); + final boolean resolveCrossProject = crossProjectModeDecider.resolvesCrossProject(request); final Map remoteClusterIndices = transportService.getRemoteClusterService() - .groupIndices(request.indicesOptions(), request.indices(), request.returnLocalAll()); + .groupIndices( + resolveCrossProject ? indicesOptionsForCrossProjectFanout(originalIndicesOptions) : originalIndicesOptions, + request.indices() + ); final OriginalIndices localIndices = remoteClusterIndices.remove(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY); final String[] concreteLocalIndices; @@ -370,7 +380,13 @@ private void doExecuteForked( for (Map.Entry remoteIndices : remoteClusterIndices.entrySet()) { String clusterAlias = remoteIndices.getKey(); OriginalIndices originalIndices = remoteIndices.getValue(); - FieldCapabilitiesRequest remoteRequest = prepareRemoteRequest(clusterAlias, request, originalIndices, nowInMillis); + FieldCapabilitiesRequest remoteRequest = prepareRemoteRequest( + clusterAlias, + request, + originalIndices, + nowInMillis, + resolveCrossProject + ); ActionListener remoteListener = ActionListener.wrap(response -> { if (request.includeResolvedTo() && response.getResolvedLocally() != null) { @@ -607,12 +623,18 @@ private static FieldCapabilitiesRequest prepareRemoteRequest( String clusterAlias, FieldCapabilitiesRequest request, OriginalIndices originalIndices, - long nowInMillis + long nowInMillis, + boolean resolveCrossProject ) { + IndicesOptions indicesOptions = originalIndices.indicesOptions(); + if (indicesOptions.resolveCrossProjectIndexExpression()) { + // if is a CPS request reset CrossProjectModeOptions to Default and use lenient IndicesOptions. + indicesOptions = indicesOptionsForCrossProjectFanout(indicesOptions); + } FieldCapabilitiesRequest remoteRequest = new FieldCapabilitiesRequest(); remoteRequest.clusterAlias(clusterAlias); remoteRequest.setMergeResults(false); // we need to merge on this node - remoteRequest.indicesOptions(originalIndices.indicesOptions()); + remoteRequest.indicesOptions(indicesOptions); remoteRequest.indices(originalIndices.indices()); remoteRequest.fields(request.fields()); remoteRequest.filters(request.filters()); @@ -621,7 +643,7 @@ private static FieldCapabilitiesRequest prepareRemoteRequest( remoteRequest.indexFilter(request.indexFilter()); remoteRequest.nowInMillis(nowInMillis); remoteRequest.includeEmptyFields(request.includeEmptyFields()); - remoteRequest.includeResolvedTo(request.includeResolvedTo()); + remoteRequest.includeResolvedTo(request.includeResolvedTo() || resolveCrossProject); return remoteRequest; } @@ -695,6 +717,10 @@ private static FieldCapabilitiesResponse merge( ); } } + Map builtResolvedRemotely = resolvedRemotely.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().build())); + validate(request.indicesOptions(), request.getProjectRouting(), resolvedLocally, builtResolvedRemotely); FieldCapabilitiesResponse.Builder responseBuilder = FieldCapabilitiesResponse.builder() .withIndices(indices) @@ -703,7 +729,7 @@ private static FieldCapabilitiesResponse merge( .withMinTransportVersion(minTransportVersion.get()); if (request.includeResolvedTo() && minTransportVersion.get().supports(RESOLVED_FIELDS_CAPS)) { // add resolution to response iff includeResolvedTo and all the nodes in the cluster supports it - responseBuilder.withResolvedLocally(new ResolvedIndexExpressions(collect)).withResolvedRemotelyBuilder(resolvedRemotely); + responseBuilder.withResolvedLocally(new ResolvedIndexExpressions(collect)).withResolvedRemotely(builtResolvedRemotely); } return responseBuilder.build(); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java index 11b5c97aeb48c..0149db57f0922 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java @@ -18,6 +18,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.xcontent.ObjectParser; import org.elasticsearch.xcontent.ParseField; @@ -33,9 +34,11 @@ public class RestFieldCapabilitiesAction extends BaseRestHandler { private final Settings settings; + private final CrossProjectModeDecider crossProjectModeDecider; public RestFieldCapabilitiesAction(Settings settings) { this.settings = settings; + this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @Override @@ -55,15 +58,25 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { - if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) { + final FieldCapabilitiesRequest fieldRequest = new FieldCapabilitiesRequest(); + + final boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); + if (crossProjectModeDecider.crossProjectEnabled()) { // accept but drop project_routing param until fully supported request.param("project_routing"); + fieldRequest.includeResolvedTo(true); } final String[] indices = Strings.splitStringByCommaToArray(request.param("index")); - final FieldCapabilitiesRequest fieldRequest = new FieldCapabilitiesRequest(); fieldRequest.indices(indices); + if (crossProjectEnabled && fieldRequest.allowsCrossProject()) { + var cpsIdxOpts = IndicesOptions.builder(fieldRequest.indicesOptions()) + .crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true)) + .build(); + fieldRequest.indicesOptions(cpsIdxOpts); + } + fieldRequest.indicesOptions(IndicesOptions.fromRequest(request, fieldRequest.indicesOptions())); fieldRequest.includeUnmapped(request.paramAsBoolean("include_unmapped", false)); fieldRequest.includeEmptyFields(request.paramAsBoolean("include_empty_fields", true)); From 812ef2887885b012825d80e4d34ab1c14dd403d2 Mon Sep 17 00:00:00 2001 From: Matteo Piergiovanni <134913285+piergm@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:53:12 +0100 Subject: [PATCH 2/6] Update docs/changelog/137530.yaml --- docs/changelog/137530.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/137530.yaml diff --git a/docs/changelog/137530.yaml b/docs/changelog/137530.yaml new file mode 100644 index 0000000000000..461c7474f9d20 --- /dev/null +++ b/docs/changelog/137530.yaml @@ -0,0 +1,5 @@ +pr: 137530 +summary: Allows field caps to be cross project +area: Search +type: enhancement +issues: [] From 4a838436030b8aa9e0d515ce4f0af158707a7832 Mon Sep 17 00:00:00 2001 From: piergm <134913285+piergm@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:06:09 +0100 Subject: [PATCH 3/6] accept projectRouting --- .../fieldcaps/FieldCapabilitiesRequest.java | 10 ++++ .../TransportFieldCapabilitiesAction.java | 47 ++++++++++++------- .../action/RestFieldCapabilitiesAction.java | 4 +- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java index cacf1e9dedba2..a8adfe2b31e2f 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java @@ -60,6 +60,7 @@ public final class FieldCapabilitiesRequest extends LegacyActionRequest implemen private transient boolean includeIndices = false; private boolean includeResolvedTo = false; + private String projectRouting; /** * Controls whether all local indices should be returned if no remotes matched @@ -264,6 +265,15 @@ public boolean allowsCrossProject() { return true; } + public void projectRouting(String projectRouting) { + this.projectRouting = projectRouting; + } + + @Override + public String getProjectRouting() { + return projectRouting; + } + @Override public boolean includeDataStreams() { return true; diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java index 78f2d1bdb7f4b..a7f5d0b89fc83 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java @@ -55,6 +55,7 @@ import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.search.SearchService; +import org.elasticsearch.search.crossproject.CrossProjectIndexResolutionValidator; import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; @@ -90,7 +91,6 @@ import static org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest.RESOLVED_FIELDS_CAPS; import static org.elasticsearch.action.search.TransportSearchHelper.checkCCSVersionCompatibility; import static org.elasticsearch.search.crossproject.CrossProjectIndexResolutionValidator.indicesOptionsForCrossProjectFanout; -import static org.elasticsearch.search.crossproject.CrossProjectIndexResolutionValidator.validate; public class TransportFieldCapabilitiesAction extends HandledTransportAction { public static final String EXCLUSION = "-"; @@ -280,9 +280,9 @@ private void doExecuteForked( indexResponses.clear(); indexMappingHashToResponses.clear(); }; - Map resolvedRemotely = new ConcurrentHashMap<>(); + Map resolvedRemotelyBuilder = new ConcurrentHashMap<>(); for (String clusterAlias : remoteClusterIndices.keySet()) { - resolvedRemotely.put(clusterAlias, ResolvedIndexExpressions.builder()); + resolvedRemotelyBuilder.put(clusterAlias, ResolvedIndexExpressions.builder()); } final Consumer handleIndexResponse = resp -> { if (fieldCapTask.isCancelled()) { @@ -345,12 +345,28 @@ private void doExecuteForked( if (fieldCapTask.notifyIfCancelled(listener)) { releaseResourcesOnCancel.run(); } else { + Map resolvedRemotely = resolvedRemotelyBuilder.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().build())); + ResolvedIndexExpressions resolvedLocally = new ResolvedIndexExpressions(resolvedLocallyList); + if (resolveCrossProject) { + final Exception ex = CrossProjectIndexResolutionValidator.validate( + request.indicesOptions(), + request.getProjectRouting(), + resolvedLocally, + resolvedRemotely + ); + if (ex != null) { + listener.onFailure(ex); + return; + } + } mergeIndexResponses( request, fieldCapTask, indexResponses, indexFailures, - resolvedLocallyList, + resolvedLocally, resolvedRemotely, minTransportVersion, listener.map(linkedRequestExecutor::wrapPrimary) @@ -394,7 +410,7 @@ private void doExecuteForked( // for bwc we need to check that resolvedOnRemoteProject Exists in the response if (resolvedOnRemoteProject != null) { for (ResolvedIndexExpression remoteResolvedExpression : resolvedOnRemoteProject.expressions()) { - resolvedRemotely.computeIfPresent(clusterAlias, (k, v) -> { + resolvedRemotelyBuilder.computeIfPresent(clusterAlias, (k, v) -> { v.addExpression(remoteResolvedExpression); return v; }); @@ -429,7 +445,7 @@ private void doExecuteForked( ), Set.of() ); - resolvedRemotely.computeIfPresent(clusterAlias, (k, v) -> { + resolvedRemotelyBuilder.computeIfPresent(clusterAlias, (k, v) -> { v.addExpression(err); return v; }); @@ -455,7 +471,7 @@ private void doExecuteForked( ), Set.of() ); - resolvedRemotely.computeIfPresent(clusterAlias, (k, v) -> { + resolvedRemotelyBuilder.computeIfPresent(clusterAlias, (k, v) -> { v.addExpression(err); return v; }); @@ -568,12 +584,11 @@ private static void mergeIndexResponses( CancellableTask task, Map indexResponses, FailureCollector indexFailures, - List resolvedLocallyList, - Map resolvedRemotely, + ResolvedIndexExpressions resolvedLocally, + Map resolvedRemotely, AtomicReference minTransportVersion, ActionListener listener ) { - ResolvedIndexExpressions resolvedLocally = new ResolvedIndexExpressions(resolvedLocallyList); List failures = indexFailures.build(indexResponses.keySet()); if (indexResponses.isEmpty() == false) { if (request.isMergeResults()) { @@ -586,7 +601,7 @@ private static void mergeIndexResponses( FieldCapabilitiesResponse.builder() .withIndexResponses(new ArrayList<>(indexResponses.values())) .withResolvedLocally(resolvedLocally) - .withResolvedRemotelyBuilder(resolvedRemotely) + .withResolvedRemotely(resolvedRemotely) .withMinTransportVersion(minTransportVersion.get()) .withFailures(failures) .build() @@ -606,7 +621,7 @@ private static void mergeIndexResponses( FieldCapabilitiesResponse.builder() .withFailures(failures) .withResolvedLocally(resolvedLocally) - .withResolvedRemotelyBuilder(resolvedRemotely) + .withResolvedRemotely(resolvedRemotely) .withMinTransportVersion(minTransportVersion.get()) .build() ); @@ -656,7 +671,7 @@ private static boolean hasSameMappingHash(FieldCapabilitiesIndexResponse r1, Fie private static FieldCapabilitiesResponse merge( Map indexResponsesMap, ResolvedIndexExpressions resolvedLocally, - Map resolvedRemotely, + Map resolvedRemotely, CancellableTask task, FieldCapabilitiesRequest request, List failures, @@ -717,10 +732,6 @@ private static FieldCapabilitiesResponse merge( ); } } - Map builtResolvedRemotely = resolvedRemotely.entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().build())); - validate(request.indicesOptions(), request.getProjectRouting(), resolvedLocally, builtResolvedRemotely); FieldCapabilitiesResponse.Builder responseBuilder = FieldCapabilitiesResponse.builder() .withIndices(indices) @@ -729,7 +740,7 @@ private static FieldCapabilitiesResponse merge( .withMinTransportVersion(minTransportVersion.get()); if (request.includeResolvedTo() && minTransportVersion.get().supports(RESOLVED_FIELDS_CAPS)) { // add resolution to response iff includeResolvedTo and all the nodes in the cluster supports it - responseBuilder.withResolvedLocally(new ResolvedIndexExpressions(collect)).withResolvedRemotely(builtResolvedRemotely); + responseBuilder.withResolvedLocally(new ResolvedIndexExpressions(collect)).withResolvedRemotely(resolvedRemotely); } return responseBuilder.build(); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java index 0149db57f0922..d5d7b90eeead5 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java @@ -62,8 +62,8 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC final boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); if (crossProjectModeDecider.crossProjectEnabled()) { - // accept but drop project_routing param until fully supported - request.param("project_routing"); + // accept project_routing param and set includeResolved to true + fieldRequest.projectRouting(request.param("project_routing", null)); fieldRequest.includeResolvedTo(true); } From b4c8399e96d525b6fa66dae98c492600d67e81ac Mon Sep 17 00:00:00 2001 From: piergm <134913285+piergm@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:31:41 +0100 Subject: [PATCH 4/6] more overrides --- .../fieldcaps/FieldCapabilitiesRequest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java index a8adfe2b31e2f..e2f696e12e3b0 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java @@ -14,11 +14,13 @@ import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.action.LegacyActionRequest; +import org.elasticsearch.action.ResolvedIndexExpressions; import org.elasticsearch.action.ValidateActions; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.Nullable; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; @@ -51,6 +53,8 @@ public final class FieldCapabilitiesRequest extends LegacyActionRequest implemen private String[] types = Strings.EMPTY_ARRAY; private boolean includeUnmapped = false; private boolean includeEmptyFields = true; + @Nullable + private ResolvedIndexExpressions resolvedIndexExpressions = null; /** * Controls whether the field caps response should always include the list of indices * where a field is defined. This flag is only used locally on the coordinating node, @@ -265,6 +269,17 @@ public boolean allowsCrossProject() { return true; } + @Override + public void setResolvedIndexExpressions(ResolvedIndexExpressions expressions) { + this.resolvedIndexExpressions = expressions; + } + + @Override + @Nullable + public ResolvedIndexExpressions getResolvedIndexExpressions() { + return resolvedIndexExpressions; + } + public void projectRouting(String projectRouting) { this.projectRouting = projectRouting; } From b71854d0d6e266df0e9eef02f1f97d1ffe43f2d7 Mon Sep 17 00:00:00 2001 From: piergm <134913285+piergm@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:31:05 +0100 Subject: [PATCH 5/6] iter --- .../action/fieldcaps/TransportFieldCapabilitiesAction.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java index a7f5d0b89fc83..9162f2a8bc446 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java @@ -206,7 +206,8 @@ private void doExecuteForked( final Map remoteClusterIndices = transportService.getRemoteClusterService() .groupIndices( resolveCrossProject ? indicesOptionsForCrossProjectFanout(originalIndicesOptions) : originalIndicesOptions, - request.indices() + request.indices(), + request.returnLocalAll() ); final OriginalIndices localIndices = remoteClusterIndices.remove(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY); From 9aeafd04ff8e77d548e0d5fce134bc60387d9d85 Mon Sep 17 00:00:00 2001 From: piergm <134913285+piergm@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:37:34 +0100 Subject: [PATCH 6/6] iter --- .../elasticsearch/rest/action/RestFieldCapabilitiesAction.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java index d5d7b90eeead5..9100e5ae0d7de 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/RestFieldCapabilitiesAction.java @@ -62,8 +62,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC final boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); if (crossProjectModeDecider.crossProjectEnabled()) { - // accept project_routing param and set includeResolved to true fieldRequest.projectRouting(request.param("project_routing", null)); + // Setting includeResolvedTo to always include index resolution data structure in the linked project responses, + // in order to allow the coordinating node to call CrossProjectIndexResolutionValidator#validate fieldRequest.includeResolvedTo(true); }