Skip to content

Commit 4d78e1a

Browse files
committed
Added msearch api to high level client
1 parent c203cff commit 4d78e1a

File tree

12 files changed

+759
-126
lines changed

12 files changed

+759
-126
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.action.get.GetRequest;
3636
import org.elasticsearch.action.index.IndexRequest;
3737
import org.elasticsearch.action.search.ClearScrollRequest;
38+
import org.elasticsearch.action.search.MultiSearchRequest;
3839
import org.elasticsearch.action.search.SearchRequest;
3940
import org.elasticsearch.action.search.SearchScrollRequest;
4041
import org.elasticsearch.action.support.ActiveShardCount;
@@ -49,6 +50,7 @@
4950
import org.elasticsearch.common.unit.TimeValue;
5051
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
5152
import org.elasticsearch.common.xcontent.ToXContent;
53+
import org.elasticsearch.common.xcontent.XContent;
5254
import org.elasticsearch.common.xcontent.XContentBuilder;
5355
import org.elasticsearch.common.xcontent.XContentHelper;
5456
import org.elasticsearch.common.xcontent.XContentParser;
@@ -381,6 +383,18 @@ static Request clearScroll(ClearScrollRequest clearScrollRequest) throws IOExcep
381383
return new Request("DELETE", "/_search/scroll", Collections.emptyMap(), entity);
382384
}
383385

386+
static Request multiSearch(MultiSearchRequest multiSearchRequest) throws IOException {
387+
Params params = Params.builder();
388+
params.putParam(RestSearchAction.TYPED_KEYS_PARAM, "true");
389+
if (multiSearchRequest.maxConcurrentSearchRequests() != MultiSearchRequest.MAX_CONCURRENT_SEARCH_REQUESTS_DEFAULT) {
390+
params.putParam("max_concurrent_searches", Integer.toString(multiSearchRequest.maxConcurrentSearchRequests()));
391+
}
392+
XContent xContent = REQUEST_BODY_CONTENT_TYPE.xContent();
393+
byte[] source = MultiSearchRequest.writeMultiLineFormat(multiSearchRequest, xContent);
394+
HttpEntity entity = new ByteArrayEntity(source, createContentType(xContent.type()));
395+
return new Request("GET", "/_msearch", params.getParams(), entity);
396+
}
397+
384398
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
385399
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
386400
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));

client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.elasticsearch.action.main.MainResponse;
3939
import org.elasticsearch.action.search.ClearScrollRequest;
4040
import org.elasticsearch.action.search.ClearScrollResponse;
41+
import org.elasticsearch.action.search.MultiSearchRequest;
42+
import org.elasticsearch.action.search.MultiSearchResponse;
4143
import org.elasticsearch.action.search.SearchRequest;
4244
import org.elasticsearch.action.search.SearchResponse;
4345
import org.elasticsearch.action.search.SearchScrollRequest;
@@ -377,6 +379,28 @@ public final void searchAsync(SearchRequest searchRequest, ActionListener<Search
377379
performRequestAsyncAndParseEntity(searchRequest, Request::search, SearchResponse::fromXContent, listener, emptySet(), headers);
378380
}
379381

382+
/**
383+
* Executes a multi search using the msearch API
384+
*
385+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html">Multi search API on
386+
* elastic.co</a>
387+
*/
388+
public final MultiSearchResponse multiSearch(MultiSearchRequest multiSearchRequest, Header... headers) throws IOException {
389+
return performRequestAndParseEntity(multiSearchRequest, Request::multiSearch, MultiSearchResponse::fromXContext,
390+
emptySet(), headers);
391+
}
392+
393+
/**
394+
* Asynchronously executes a multi search using the msearch API
395+
*
396+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html">Multi search API on
397+
* elastic.co</a>
398+
*/
399+
public final void multiSearchAsync(MultiSearchRequest searchRequest, ActionListener<MultiSearchResponse> listener, Header... headers) {
400+
performRequestAsyncAndParseEntity(searchRequest, Request::multiSearch, MultiSearchResponse::fromXContext, listener,
401+
emptySet(), headers);
402+
}
403+
380404
/**
381405
* Executes a search using the Search Scroll API
382406
*

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.action.get.GetRequest;
3333
import org.elasticsearch.action.index.IndexRequest;
3434
import org.elasticsearch.action.search.ClearScrollRequest;
35+
import org.elasticsearch.action.search.MultiSearchRequest;
3536
import org.elasticsearch.action.search.SearchRequest;
3637
import org.elasticsearch.action.search.SearchScrollRequest;
3738
import org.elasticsearch.action.search.SearchType;
@@ -42,6 +43,7 @@
4243
import org.elasticsearch.action.support.replication.ReplicatedWriteRequest;
4344
import org.elasticsearch.action.support.replication.ReplicationRequest;
4445
import org.elasticsearch.action.update.UpdateRequest;
46+
import org.elasticsearch.common.CheckedBiConsumer;
4547
import org.elasticsearch.common.Strings;
4648
import org.elasticsearch.common.bytes.BytesArray;
4749
import org.elasticsearch.common.bytes.BytesReference;
@@ -56,6 +58,7 @@
5658
import org.elasticsearch.index.VersionType;
5759
import org.elasticsearch.index.query.TermQueryBuilder;
5860
import org.elasticsearch.rest.action.search.RestSearchAction;
61+
import org.elasticsearch.search.Scroll;
5962
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
6063
import org.elasticsearch.search.aggregations.support.ValueType;
6164
import org.elasticsearch.search.builder.SearchSourceBuilder;
@@ -72,16 +75,21 @@
7275
import java.io.InputStream;
7376
import java.lang.reflect.Constructor;
7477
import java.lang.reflect.Modifier;
78+
import java.util.ArrayList;
7579
import java.util.HashMap;
80+
import java.util.List;
7681
import java.util.Locale;
7782
import java.util.Map;
7883
import java.util.StringJoiner;
84+
import java.util.function.BiConsumer;
7985
import java.util.function.Consumer;
8086
import java.util.function.Function;
8187
import java.util.function.Supplier;
8288

8389
import static java.util.Collections.singletonMap;
90+
import static org.elasticsearch.client.Request.REQUEST_BODY_CONTENT_TYPE;
8491
import static org.elasticsearch.client.Request.enforceSameContentType;
92+
import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest;
8593
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
8694

8795
public class RequestTests extends ESTestCase {
@@ -771,6 +779,55 @@ public void testSearch() throws Exception {
771779
}
772780
}
773781

782+
public void testMultiSearch() throws IOException {
783+
int numberOfSearchRequests = randomIntBetween(0, 32);
784+
MultiSearchRequest multiSearchRequest = new MultiSearchRequest();
785+
for (int i = 0; i < numberOfSearchRequests; i++) {
786+
SearchRequest searchRequest = randomSearchRequest(() -> {
787+
// No need to return a very complex SearchSourceBuilder here, that is tested elsewhere
788+
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
789+
searchSourceBuilder.from(randomInt(10));
790+
searchSourceBuilder.size(randomIntBetween(20, 100));
791+
return searchSourceBuilder;
792+
});
793+
// scroll is not supported in the current msearch api, so unset it:
794+
searchRequest.scroll((Scroll) null);
795+
// only expand_wildcards, ignore_unavailable and allow_no_indices can be specified from msearch api, so unset other options:
796+
IndicesOptions randomlyGenerated = searchRequest.indicesOptions();
797+
IndicesOptions msearchDefault = new MultiSearchRequest().indicesOptions();
798+
searchRequest.indicesOptions(IndicesOptions.fromOptions(
799+
randomlyGenerated.ignoreUnavailable(), randomlyGenerated.allowNoIndices(), randomlyGenerated.expandWildcardsOpen(),
800+
randomlyGenerated.expandWildcardsClosed(), msearchDefault.allowAliasesToMultipleIndices(),
801+
msearchDefault.forbidClosedIndices(), msearchDefault.ignoreAliases()
802+
));
803+
multiSearchRequest.add(searchRequest);
804+
}
805+
806+
Map<String, String> expectedParams = new HashMap<>();
807+
expectedParams.put(RestSearchAction.TYPED_KEYS_PARAM, "true");
808+
if (randomBoolean()) {
809+
multiSearchRequest.maxConcurrentSearchRequests(randomIntBetween(1, 8));
810+
expectedParams.put("max_concurrent_searches", Integer.toString(multiSearchRequest.maxConcurrentSearchRequests()));
811+
}
812+
813+
Request request = Request.multiSearch(multiSearchRequest);
814+
assertEquals("/_msearch", request.getEndpoint());
815+
assertEquals(expectedParams, request.getParameters());
816+
817+
List<SearchRequest> requests = new ArrayList<>();
818+
CheckedBiConsumer<SearchRequest, XContentParser, IOException> consumer = (searchRequest, p) -> {
819+
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(p);
820+
if (searchSourceBuilder.equals(new SearchSourceBuilder()) == false) {
821+
searchRequest.source(searchSourceBuilder);
822+
}
823+
requests.add(searchRequest);
824+
};
825+
MultiSearchRequest.readMultiLineFormat(new BytesArray(EntityUtils.toByteArray(request.getEntity())),
826+
REQUEST_BODY_CONTENT_TYPE.xContent(), consumer, null, multiSearchRequest.indicesOptions(), null, null,
827+
null, xContentRegistry(), true);
828+
assertEquals(requests, multiSearchRequest.requests());
829+
}
830+
774831
public void testSearchScroll() throws IOException {
775832
SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
776833
searchScrollRequest.scrollId(randomAlphaOfLengthBetween(5, 10));
@@ -782,7 +839,7 @@ public void testSearchScroll() throws IOException {
782839
assertEquals("/_search/scroll", request.getEndpoint());
783840
assertEquals(0, request.getParameters().size());
784841
assertToXContentBody(searchScrollRequest, request.getEntity());
785-
assertEquals(Request.REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
842+
assertEquals(REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
786843
}
787844

788845
public void testClearScroll() throws IOException {
@@ -796,11 +853,11 @@ public void testClearScroll() throws IOException {
796853
assertEquals("/_search/scroll", request.getEndpoint());
797854
assertEquals(0, request.getParameters().size());
798855
assertToXContentBody(clearScrollRequest, request.getEntity());
799-
assertEquals(Request.REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
856+
assertEquals(REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
800857
}
801858

802859
private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {
803-
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, Request.REQUEST_BODY_CONTENT_TYPE, false);
860+
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false);
804861
assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue());
805862
assertEquals(expectedBytes, new BytesArray(EntityUtils.toByteArray(actualEntity)));
806863
}

0 commit comments

Comments
 (0)