diff --git a/docs/changelog/138105.yaml b/docs/changelog/138105.yaml new file mode 100644 index 0000000000000..65ff1fb5f86a8 --- /dev/null +++ b/docs/changelog/138105.yaml @@ -0,0 +1,5 @@ +pr: 138105 +summary: MRT should default to `true` for CPS searches +area: CCS +type: enhancement +issues: [] diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java index 5a5b1df64907d..6ce25436af54e 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java @@ -18,10 +18,12 @@ import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.rest.action.search.RestMultiSearchAction; import org.elasticsearch.rest.action.search.RestSearchAction; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.xcontent.XContentType; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.Set; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -35,11 +37,11 @@ public class RestMultiSearchTemplateAction extends BaseRestHandler { private static final Set RESPONSE_PARAMS = Set.of(RestSearchAction.TYPED_KEYS_PARAM, RestSearchAction.TOTAL_HITS_AS_INT_PARAM); private final boolean allowExplicitIndex; - private final Settings settings; + private final CrossProjectModeDecider crossProjectModeDecider; public RestMultiSearchTemplateAction(Settings settings) { this.allowExplicitIndex = MULTI_ALLOW_EXPLICIT_INDEX.get(settings); - this.settings = settings; + this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @Override @@ -67,7 +69,8 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client * Parses a {@link RestRequest} body and returns a {@link MultiSearchTemplateRequest} */ public MultiSearchTemplateRequest parseRequest(RestRequest restRequest, boolean allowExplicitIndex) throws IOException { - if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) { + boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); + if (crossProjectEnabled) { // accept but drop project_routing param until fully supported restRequest.param("project_routing"); } @@ -90,7 +93,8 @@ public MultiSearchTemplateRequest parseRequest(RestRequest restRequest, boolean throw new IllegalArgumentException("Malformed search template"); } RestSearchAction.validateSearchRequest(restRequest, searchRequest); - } + }, + Optional.of(crossProjectEnabled) ); return multiRequest; } diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestSearchTemplateAction.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestSearchTemplateAction.java index 72e58b651e486..7ac6d758ae04c 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestSearchTemplateAction.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestSearchTemplateAction.java @@ -19,10 +19,12 @@ import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.rest.action.search.RestSearchAction; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Predicate; @@ -37,11 +39,11 @@ public class RestSearchTemplateAction extends BaseRestHandler { private static final Set RESPONSE_PARAMS = Set.of(TYPED_KEYS_PARAM, RestSearchAction.TOTAL_HITS_AS_INT_PARAM); private final Predicate clusterSupportsFeature; - private final Settings settings; + private final CrossProjectModeDecider crossProjectModeDecider; public RestSearchTemplateAction(Predicate clusterSupportsFeature, Settings settings) { this.clusterSupportsFeature = clusterSupportsFeature; - this.settings = settings; + this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @Override @@ -61,7 +63,8 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) { + boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); + if (crossProjectEnabled) { // accept but drop project_routing param until fully supported request.param("project_routing"); } @@ -73,7 +76,9 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client request, null, clusterSupportsFeature, - size -> searchRequest.source().size(size) + size -> searchRequest.source().size(size), + null, + Optional.of(crossProjectEnabled) ); // Creates the search template request diff --git a/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java b/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java index aa728e888b87e..447c3ccca42b0 100644 --- a/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java +++ b/server/src/main/java/org/elasticsearch/action/search/MultiSearchRequest.java @@ -18,7 +18,9 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.rest.action.search.SearchParamsParser; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; @@ -36,6 +38,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import static org.elasticsearch.action.ValidateActions.addValidationError; @@ -167,7 +170,12 @@ public static void readMultiLineFormat( String routing, String searchType, Boolean ccsMinimizeRoundtrips, - boolean allowExplicitIndex + boolean allowExplicitIndex, + /* + * Refer to RestSearchAction#parseSearchRequest()'s JavaDoc to understand why this is an Optional + * and what its values mean with respect to an endpoint's Cross Project Search status/support. + */ + Optional crossProjectEnabled ) throws IOException { readMultiLineFormat( xContent, @@ -180,7 +188,8 @@ public static void readMultiLineFormat( searchType, ccsMinimizeRoundtrips, allowExplicitIndex, - (s, o, r) -> false + (s, o, r) -> false, + crossProjectEnabled ); } @@ -196,10 +205,16 @@ public static void readMultiLineFormat( String searchType, Boolean ccsMinimizeRoundtrips, boolean allowExplicitIndex, - TriFunction extraParamParser + TriFunction extraParamParser, + /* + * Refer to RestSearchAction#parseSearchRequest()'s JavaDoc to understand why this is an Optional + * and what its values mean with respect to an endpoint's Cross Project Search status/support. + */ + Optional crossProjectEnabled ) throws IOException { int from = 0; byte marker = xContent.bulkSeparator(); + boolean warnedMrtForCps = false; while (true) { int nextMarker = findNextMarker(marker, from, data); if (nextMarker == -1) { @@ -219,6 +234,11 @@ public static void readMultiLineFormat( if (searchType != null) { searchRequest.searchType(searchType); } + /* + * This `ccsMinimizeRoundtrips` refers to the value specified as the query parameter and is extracted in + * `RestMultiSearchAction#parseMultiLineRequest()`. If in a Cross Project Search environment, it is + * guaranteed to be `true`. Otherwise, its value is whatever that the user is provided. + */ if (ccsMinimizeRoundtrips != null) { searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); } @@ -250,7 +270,11 @@ public static void readMultiLineFormat( } else if ("search_type".equals(entry.getKey()) || "searchType".equals(entry.getKey())) { searchRequest.searchType(nodeStringValue(value, null)); } else if ("ccs_minimize_roundtrips".equals(entry.getKey()) || "ccsMinimizeRoundtrips".equals(entry.getKey())) { - searchRequest.setCcsMinimizeRoundtrips(nodeBooleanValue(value)); + searchRequest.setCcsMinimizeRoundtrips(crossProjectEnabled.orElse(false) || nodeBooleanValue(value)); + if (crossProjectEnabled.orElse(false) && warnedMrtForCps == false) { + HeaderWarning.addWarning(SearchParamsParser.MRT_SET_IN_CPS_WARN); + warnedMrtForCps = true; + } } else if ("request_cache".equals(entry.getKey()) || "requestCache".equals(entry.getKey())) { searchRequest.requestCache(nodeBooleanValue(value, entry.getKey())); } else if ("preference".equals(entry.getKey())) { diff --git a/server/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java b/server/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java index 9edaff7563db5..992a044868a3b 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java @@ -28,6 +28,7 @@ import org.elasticsearch.rest.action.RestCancellableNodeClient; import org.elasticsearch.rest.action.RestRefCountedChunkedToXContentListener; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.usage.SearchUsageHolder; import org.elasticsearch.xcontent.XContent; import org.elasticsearch.xcontent.XContentParser; @@ -35,6 +36,7 @@ import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Predicate; @@ -48,13 +50,13 @@ public class RestMultiSearchAction extends BaseRestHandler { private final boolean allowExplicitIndex; private final SearchUsageHolder searchUsageHolder; private final Predicate clusterSupportsFeature; - private final Settings settings; + private final CrossProjectModeDecider crossProjectModeDecider; public RestMultiSearchAction(Settings settings, SearchUsageHolder searchUsageHolder, Predicate clusterSupportsFeature) { - this.settings = settings; this.allowExplicitIndex = MULTI_ALLOW_EXPLICIT_INDEX.get(settings); this.searchUsageHolder = searchUsageHolder; this.clusterSupportsFeature = clusterSupportsFeature; + this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @Override @@ -77,11 +79,18 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC if (client.threadPool() != null && client.threadPool().getThreadContext() != null) { client.threadPool().getThreadContext().setErrorTraceTransportHeader(request); } - if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) { + boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); + if (crossProjectEnabled) { // accept but drop project_routing param until fully supported request.param("project_routing"); } - final MultiSearchRequest multiSearchRequest = parseRequest(request, allowExplicitIndex, searchUsageHolder, clusterSupportsFeature); + final MultiSearchRequest multiSearchRequest = parseRequest( + request, + allowExplicitIndex, + searchUsageHolder, + clusterSupportsFeature, + Optional.of(crossProjectEnabled) + ); return channel -> { final RestCancellableNodeClient cancellableClient = new RestCancellableNodeClient(client, request.getHttpChannel()); cancellableClient.execute( @@ -99,9 +108,17 @@ public static MultiSearchRequest parseRequest( RestRequest restRequest, boolean allowExplicitIndex, SearchUsageHolder searchUsageHolder, - Predicate clusterSupportsFeature + Predicate clusterSupportsFeature, + Optional crossProjectEnabled ) throws IOException { - return parseRequest(restRequest, allowExplicitIndex, searchUsageHolder, clusterSupportsFeature, (k, v, r) -> false); + return parseRequest( + restRequest, + allowExplicitIndex, + searchUsageHolder, + clusterSupportsFeature, + (k, v, r) -> false, + crossProjectEnabled + ); } /** @@ -113,7 +130,8 @@ public static MultiSearchRequest parseRequest( boolean allowExplicitIndex, SearchUsageHolder searchUsageHolder, Predicate clusterSupportsFeature, - TriFunction extraParamParser + TriFunction extraParamParser, + Optional crossProjectEnabled ) throws IOException { MultiSearchRequest multiRequest = new MultiSearchRequest(); IndicesOptions indicesOptions = IndicesOptions.fromRequest(restRequest, multiRequest.indicesOptions()); @@ -143,11 +161,11 @@ public static MultiSearchRequest parseRequest( RestSearchAction.preparePointInTime(searchRequest, restRequest); } else { searchRequest.setCcsMinimizeRoundtrips( - restRequest.paramAsBoolean("ccs_minimize_roundtrips", searchRequest.isCcsMinimizeRoundtrips()) + SearchParamsParser.parseCcsMinimizeRoundtrips(crossProjectEnabled, restRequest, searchRequest.isCcsMinimizeRoundtrips()) ); } multiRequest.add(searchRequest); - }, extraParamParser); + }, extraParamParser, crossProjectEnabled); List requests = multiRequest.requests(); for (SearchRequest request : requests) { // preserve if it's set on the request @@ -168,9 +186,10 @@ public static void parseMultiLineRequest( RestRequest request, IndicesOptions indicesOptions, boolean allowExplicitIndex, - CheckedBiConsumer consumer + CheckedBiConsumer consumer, + Optional crossProjectEnabled ) throws IOException { - parseMultiLineRequest(request, indicesOptions, allowExplicitIndex, consumer, (k, v, r) -> false); + parseMultiLineRequest(request, indicesOptions, allowExplicitIndex, consumer, (k, v, r) -> false, crossProjectEnabled); } /** @@ -182,12 +201,13 @@ public static void parseMultiLineRequest( IndicesOptions indicesOptions, boolean allowExplicitIndex, CheckedBiConsumer consumer, - TriFunction extraParamParser + TriFunction extraParamParser, + Optional crossProjectEnabled ) throws IOException { String[] indices = Strings.splitStringByCommaToArray(request.param("index")); String searchType = request.param("search_type"); - boolean ccsMinimizeRoundtrips = request.paramAsBoolean("ccs_minimize_roundtrips", true); + boolean ccsMinimizeRoundtrips = SearchParamsParser.parseCcsMinimizeRoundtrips(crossProjectEnabled, request); String routing = request.param("routing"); final Tuple sourceTuple = request.contentOrSourceParam(); @@ -204,7 +224,8 @@ public static void parseMultiLineRequest( searchType, ccsMinimizeRoundtrips, allowExplicitIndex, - extraParamParser + extraParamParser, + crossProjectEnabled ); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java b/server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java index 861aeb35f938b..287e42f31dcf2 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Optional; import java.util.Set; import java.util.function.IntConsumer; import java.util.function.Predicate; @@ -68,13 +69,11 @@ public class RestSearchAction extends BaseRestHandler { private final SearchUsageHolder searchUsageHolder; private final Predicate clusterSupportsFeature; - private final Settings settings; private final CrossProjectModeDecider crossProjectModeDecider; public RestSearchAction(SearchUsageHolder searchUsageHolder, Predicate clusterSupportsFeature, Settings settings) { this.searchUsageHolder = searchUsageHolder; this.clusterSupportsFeature = clusterSupportsFeature; - this.settings = settings; this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @@ -134,7 +133,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC clusterSupportsFeature, setSize, searchUsageHolder, - crossProjectEnabled + Optional.of(crossProjectEnabled) ) ); @@ -146,7 +145,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC /** * Parses the rest request on top of the SearchRequest, preserving values that are not overridden by the rest request. - * + * The endpoint calling this method is treated as if it does not support Cross Project Search (CPS). In case it supports + * CPS, it should call in the other appropriate overload and pass in the CPS state explicitly either via Optional.of(true) + * or Optional.of(false). * @param searchRequest the search request that will hold what gets parsed * @param request the rest request to read from * @param requestContentParser body of the request to read. This method does not attempt to read the body from the {@code request} @@ -172,7 +173,15 @@ public static void parseSearchRequest( IntConsumer setSize, @Nullable SearchUsageHolder searchUsageHolder ) throws IOException { - parseSearchRequest(searchRequest, request, requestContentParser, clusterSupportsFeature, setSize, searchUsageHolder, false); + parseSearchRequest( + searchRequest, + request, + requestContentParser, + clusterSupportsFeature, + setSize, + searchUsageHolder, + Optional.empty() + ); } /** @@ -185,7 +194,10 @@ public static void parseSearchRequest( * @param clusterSupportsFeature used to check if certain features are available in this cluster * @param setSize how the size url parameter is handled. {@code udpate_by_query} and regular search differ here. * @param searchUsageHolder the holder of search usage stats - * @param crossProjectEnabled whether serverless.cross_project.enabled is set to true + * @param crossProjectEnabled Specifies the state of Cross Project Search (CPS) for the endpoint that's calling this method. + * Optional.of(true) - signifies that the endpoint supports CPS, + * Optional.of(false) - signifies that the endpoint supports CPS but CPS is disabled, and, + * Optional.empty() - signifies that the endpoint does not support CPS. */ public static void parseSearchRequest( SearchRequest searchRequest, @@ -194,7 +206,7 @@ public static void parseSearchRequest( Predicate clusterSupportsFeature, IntConsumer setSize, @Nullable SearchUsageHolder searchUsageHolder, - boolean crossProjectEnabled + Optional crossProjectEnabled ) throws IOException { if (searchRequest.source() == null) { searchRequest.source(new SearchSourceBuilder()); @@ -205,7 +217,7 @@ public static void parseSearchRequest( * We only do it if in a Cross Project Environment, though, because outside it, such details are not * expected and valid. */ - SearchRequest searchRequestForParsing = crossProjectEnabled ? searchRequest : null; + SearchRequest searchRequestForParsing = crossProjectEnabled.orElse(false) ? searchRequest : null; if (requestContentParser != null) { if (searchUsageHolder == null) { searchRequest.source().parseXContent(searchRequestForParsing, requestContentParser, true, clusterSupportsFeature); @@ -250,7 +262,7 @@ public static void parseSearchRequest( searchRequest.routing(request.param("routing")); searchRequest.preference(request.param("preference")); IndicesOptions indicesOptions = IndicesOptions.fromRequest(request, searchRequest.indicesOptions()); - if (crossProjectEnabled && searchRequest.allowsCrossProject() && searchRequest.pointInTimeBuilder() == null) { + if (crossProjectEnabled.orElse(false) && searchRequest.allowsCrossProject() && searchRequest.pointInTimeBuilder() == null) { indicesOptions = IndicesOptions.builder(indicesOptions) .crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true)) .build(); @@ -263,7 +275,7 @@ public static void parseSearchRequest( preparePointInTime(searchRequest, request); } else { searchRequest.setCcsMinimizeRoundtrips( - request.paramAsBoolean("ccs_minimize_roundtrips", searchRequest.isCcsMinimizeRoundtrips()) + SearchParamsParser.parseCcsMinimizeRoundtrips(crossProjectEnabled, request, searchRequest.isCcsMinimizeRoundtrips()) ); } if (request.paramAsBoolean("force_synthetic_source", false)) { diff --git a/server/src/main/java/org/elasticsearch/rest/action/search/SearchParamsParser.java b/server/src/main/java/org/elasticsearch/rest/action/search/SearchParamsParser.java new file mode 100644 index 0000000000000..33f787dd09e61 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/rest/action/search/SearchParamsParser.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.rest.action.search; + +import org.elasticsearch.common.logging.HeaderWarning; +import org.elasticsearch.rest.RestRequest; + +import java.util.Optional; + +public class SearchParamsParser { + public static final String MRT_SET_IN_CPS_WARN = "ccs_minimize_roundtrips always defaults to true in Cross Project Search context." + + " Setting it explicitly has no effect irrespective of the value specified and is ignored." + + " It will soon be deprecated and made unavailable for Cross project Search."; + + /** + * For CPS, we do not necessarily want to use the MRT value that the user has provided. + * Instead, we'd want to ignore it and default searches to `true` whilst issuing a warning + * via the headers. + * @param crossProjectEnabled If running in Cross Project Search environment. + * @param request Rest request that we're parsing. + * @return A boolean that determines if round trips should be minimised for this search request. + */ + public static boolean parseCcsMinimizeRoundtrips(Optional crossProjectEnabled, RestRequest request) { + return parseCcsMinimizeRoundtrips(crossProjectEnabled, request, true); + } + + public static boolean parseCcsMinimizeRoundtrips(Optional crossProjectEnabled, RestRequest request, boolean defaultValue) { + if (crossProjectEnabled.orElse(false)) { + if (request.hasParam("ccs_minimize_roundtrips")) { + request.param("ccs_minimize_roundtrips"); + HeaderWarning.addWarning(MRT_SET_IN_CPS_WARN); + return true; + } + + // MRT was not provided; default to true. + return true; + } else { + // This is not a CPS request; use the value the user has provided. + return request.paramAsBoolean("ccs_minimize_roundtrips", defaultValue); + } + } +} diff --git a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java index 3ed63ff5e90d1..e3998a8cddbcd 100644 --- a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import static java.util.Collections.singletonList; import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest; @@ -98,7 +99,13 @@ public void testFailWithUnknownKey() { ).build(); IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, - () -> RestMultiSearchAction.parseRequest(restRequest, true, new UsageService().getSearchUsageHolder(), nf -> false) + () -> RestMultiSearchAction.parseRequest( + restRequest, + true, + new UsageService().getSearchUsageHolder(), + nf -> false, + Optional.empty() + ) ); assertEquals("key [unknown_key] is not supported in the metadata section", ex.getMessage()); } @@ -116,7 +123,8 @@ public void testSimpleAddWithCarriageReturn() throws Exception { restRequest, true, new UsageService().getSearchUsageHolder(), - nf -> false + nf -> false, + Optional.empty() ); assertThat(request.requests().size(), equalTo(1)); assertThat(request.requests().get(0).indices()[0], equalTo("test")); @@ -139,7 +147,8 @@ public void testDefaultIndicesOptions() throws IOException { restRequest, true, new UsageService().getSearchUsageHolder(), - nf -> false + nf -> false, + Optional.empty() ); assertThat(request.requests().size(), equalTo(1)); assertThat(request.requests().get(0).indices()[0], equalTo("test")); @@ -249,7 +258,13 @@ public void testMsearchTerminatedByNewline() throws Exception { ).build(); IllegalArgumentException expectThrows = expectThrows( IllegalArgumentException.class, - () -> RestMultiSearchAction.parseRequest(restRequest, true, new UsageService().getSearchUsageHolder(), nf -> false) + () -> RestMultiSearchAction.parseRequest( + restRequest, + true, + new UsageService().getSearchUsageHolder(), + nf -> false, + Optional.empty() + ) ); assertEquals("The msearch request must be terminated by a newline [\n]", expectThrows.getMessage()); @@ -262,7 +277,8 @@ public void testMsearchTerminatedByNewline() throws Exception { restRequestWithNewLine, true, new UsageService().getSearchUsageHolder(), - nf -> false + nf -> false, + Optional.empty() ); assertEquals(3, msearchRequest.requests().size()); } @@ -283,7 +299,7 @@ private MultiSearchRequest parseMultiSearchRequest(RestRequest restRequest) thro new SearchSourceBuilder().parseXContent(parser, false, new UsageService().getSearchUsageHolder(), nf -> false) ); request.add(searchRequest); - }); + }, Optional.empty()); return request; } @@ -340,7 +356,8 @@ public void testMultiLineSerialization() throws IOException { null, null, null, - true + true, + Optional.empty() ); assertEquals(originalRequest, parsedRequest); } diff --git a/x-pack/plugin/async-search/src/main/java/org/elasticsearch/xpack/search/RestSubmitAsyncSearchAction.java b/x-pack/plugin/async-search/src/main/java/org/elasticsearch/xpack/search/RestSubmitAsyncSearchAction.java index c6e3a38007d88..711e68e3908c0 100644 --- a/x-pack/plugin/async-search/src/main/java/org/elasticsearch/xpack/search/RestSubmitAsyncSearchAction.java +++ b/x-pack/plugin/async-search/src/main/java/org/elasticsearch/xpack/search/RestSubmitAsyncSearchAction.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.IntConsumer; import java.util.function.Predicate; @@ -70,6 +71,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); if (crossProjectEnabled) { + submit.getSearchRequest().setCcsMinimizeRoundtrips(true); submit.getSearchRequest().setProjectRouting(request.param("project_routing")); } @@ -86,7 +88,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli clusterSupportsFeature, setSize, searchUsageHolder, - crossProjectEnabled + Optional.of(crossProjectEnabled) ) ); diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/RestEqlSearchAction.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/RestEqlSearchAction.java index 538414d35ea59..b6e1040339705 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/RestEqlSearchAction.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/RestEqlSearchAction.java @@ -21,6 +21,8 @@ import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestCancellableNodeClient; +import org.elasticsearch.rest.action.search.SearchParamsParser; +import org.elasticsearch.search.crossproject.CrossProjectModeDecider; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentType; @@ -30,6 +32,7 @@ import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.Set; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -40,10 +43,10 @@ public class RestEqlSearchAction extends BaseRestHandler { private static final Logger LOGGER = LogManager.getLogger(RestEqlSearchAction.class); private static final String SEARCH_PATH = "/{index}/_eql/search"; - private final Settings settings; + private final CrossProjectModeDecider crossProjectModeDecider; public RestEqlSearchAction(Settings settings) { - this.settings = settings; + this.crossProjectModeDecider = new CrossProjectModeDecider(settings); } @Override @@ -53,7 +56,7 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - final boolean crossProjectEnabled = settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false); + boolean crossProjectEnabled = crossProjectModeDecider.crossProjectEnabled(); EqlSearchRequest eqlRequest; String indices; try (XContentParser parser = request.contentOrSourceParamParser()) { @@ -77,7 +80,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli eqlRequest.keepAlive(request.paramAsTime("keep_alive", eqlRequest.keepAlive())); } eqlRequest.keepOnCompletion(request.paramAsBoolean("keep_on_completion", eqlRequest.keepOnCompletion())); - eqlRequest.ccsMinimizeRoundtrips(request.paramAsBoolean("ccs_minimize_roundtrips", eqlRequest.ccsMinimizeRoundtrips())); + eqlRequest.ccsMinimizeRoundtrips(SearchParamsParser.parseCcsMinimizeRoundtrips(Optional.of(crossProjectEnabled), request)); eqlRequest.allowPartialSearchResults( request.paramAsBoolean("allow_partial_search_results", eqlRequest.allowPartialSearchResults()) ); diff --git a/x-pack/plugin/fleet/src/main/java/org/elasticsearch/xpack/fleet/rest/RestFleetMultiSearchAction.java b/x-pack/plugin/fleet/src/main/java/org/elasticsearch/xpack/fleet/rest/RestFleetMultiSearchAction.java index 1550a9a942b1f..a88100cfd8932 100644 --- a/x-pack/plugin/fleet/src/main/java/org/elasticsearch/xpack/fleet/rest/RestFleetMultiSearchAction.java +++ b/x-pack/plugin/fleet/src/main/java/org/elasticsearch/xpack/fleet/rest/RestFleetMultiSearchAction.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Predicate; @@ -95,7 +96,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli } else { return false; } - } + }, + // Fleet searches neither support CCS nor CPS. + Optional.empty() ); for (SearchRequest searchRequest : multiSearchRequest.requests()) {