Multi-Get API

The multiGet API executes multiple get requests in a single http request in parallel.

Multi-Get Request

A MultiGetRequest is built empty and you add `MultiGetRequest.Item`s to configure what to fetch:

MultiGetRequest request = new MultiGetRequest();
request.add(new MultiGetRequest.Item(
    "index",         
    "example_id"));  
request.add(new MultiGetRequest.Item("index", "another_id")); 

Index

Document id

Add another item to fetch

Optional arguments

multiGet supports the same optional arguments that the get API supports. You can set most of these on the Item:

request.add(new MultiGetRequest.Item("index", "example_id")
    .fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE));  

Disable source retrieval, enabled by default

String[] includes = new String[] {"foo", "*r"};
String[] excludes = Strings.EMPTY_ARRAY;
FetchSourceContext fetchSourceContext =
        new FetchSourceContext(true, includes, excludes);
request.add(new MultiGetRequest.Item("index", "example_id")
    .fetchSourceContext(fetchSourceContext));  

Configure source inclusion for specific fields

String[] includes = Strings.EMPTY_ARRAY;
String[] excludes = new String[] {"foo", "*r"};
FetchSourceContext fetchSourceContext =
        new FetchSourceContext(true, includes, excludes);
request.add(new MultiGetRequest.Item("index", "example_id")
    .fetchSourceContext(fetchSourceContext));  

Configure source exclusion for specific fields

request.add(new MultiGetRequest.Item("index", "example_id")
    .storedFields("foo"));  
MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
MultiGetItemResponse item = response.getResponses()[0];
String value = item.getResponse().getField("foo").getValue(); 

Configure retrieval for specific stored fields (requires fields to be stored separately in the mappings)

Retrieve the foo stored field (requires the field to be stored separately in the mappings)

request.add(new MultiGetRequest.Item("index", "with_routing")
    .routing("some_routing"));          
request.add(new MultiGetRequest.Item("index", "with_version")
    .versionType(VersionType.EXTERNAL)  
    .version(10123L));                  

Routing value

Version

Version type

preference, realtime and refresh can be set on the main request but not on any items:

request.preference("some_preference");  
request.realtime(false);                
request.refresh(true);                  

Preference value

Set realtime flag to false (true by default)

Perform a refresh before retrieving the document (false by default)

Synchronous Execution

When executing a MultiGetRequest in the following manner, the client waits for the MultiGetResponse to be returned before continuing with code execution:

MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);

Synchronous calls may throw an IOException in case of either failing to parse the REST response in the high-level REST client, the request times out or similar cases where there is no response coming back from the server.

In cases where the server returns a 4xx or 5xx error code, the high-level client tries to parse the response body error details instead and then throws a generic ElasticsearchException and adds the original ResponseException as a suppressed exception to it.

Asynchronous Execution

Executing a MultiGetRequest can also be done in an asynchronous fashion so that the client can return directly. Users need to specify how the response or potential failures will be handled by passing the request and a listener to the asynchronous multi-get method:

client.mgetAsync(request, RequestOptions.DEFAULT, listener); 

The MultiGetRequest to execute and the ActionListener to use when the execution completes

The asynchronous method does not block and returns immediately. Once it is completed the ActionListener is called back using the onResponse method if the execution successfully completed or using the onFailure method if it failed. Failure scenarios and expected exceptions are the same as in the synchronous execution case.

A typical listener for multi-get looks like:

listener = new ActionListener<MultiGetResponse>() {
    @Override
    public void onResponse(MultiGetResponse response) {
        
    }

    @Override
    public void onFailure(Exception e) {
        
    }
};

Called when the execution is successfully completed.

Called when the whole MultiGetRequest fails.

Multi Get Response

The returned MultiGetResponse contains a list of MultiGetItemResponse`s in `getResponses in the same order that they were requested. MultiGetItemResponse contains either a GetResponse if the get succeeded or a MultiGetResponse.Failure if it failed. A success looks just like a normal GetResponse.

MultiGetItemResponse firstItem = response.getResponses()[0];
assertNull(firstItem.getFailure());              
GetResponse firstGet = firstItem.getResponse();  
String index = firstItem.getIndex();
String id = firstItem.getId();
if (firstGet.isExists()) {
    long version = firstGet.getVersion();
    String sourceAsString = firstGet.getSourceAsString();        
    Map<String, Object> sourceAsMap = firstGet.getSourceAsMap(); 
    byte[] sourceAsBytes = firstGet.getSourceAsBytes();          
} else {
    
}

getFailure returns null because there isn’t a failure.

getResponse returns the GetResponse.

Retrieve the document as a String

Retrieve the document as a Map<String, Object>

Retrieve the document as a byte[]

Handle the scenario where the document was not found. Note that although the returned response has 404 status code, a valid GetResponse is returned rather than an exception thrown. Such response does not hold any source document and its isExists method returns false.

When one of the subrequests as performed against an index that does not exist getFailure will contain an exception:

assertNull(missingIndexItem.getResponse());                
Exception e = missingIndexItem.getFailure().getFailure();  
ElasticsearchException ee = (ElasticsearchException) e;    
// TODO status is broken! fix in a followup
// assertEquals(RestStatus.NOT_FOUND, ee.status());        
assertThat(e.getMessage(),
    containsString("reason=no such index [missing_index]")); 

getResponse is null.

getFailure isn’t and contains an Exception.

That Exception is actually an ElasticsearchException

and it has a status of NOT_FOUND. It’d have been an HTTP 404 if this wasn’t a multi get.

getMessage explains the actual cause, no such index.

In case a specific document version has been requested, and the existing document has a different version number, a version conflict is raised:

MultiGetRequest request = new MultiGetRequest();
request.add(new MultiGetRequest.Item("index", "example_id")
    .version(1000L));
MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
MultiGetItemResponse item = response.getResponses()[0];
assertNull(item.getResponse());                          
Exception e = item.getFailure().getFailure();            
ElasticsearchException ee = (ElasticsearchException) e;  
// TODO status is broken! fix in a followup
// assertEquals(RestStatus.CONFLICT, ee.status());          
assertThat(e.getMessage(),
    containsString("version conflict, current version [1] is "
        + "different than the one provided [1000]"));    

getResponse is null.

getFailure isn’t and contains an Exception.

That Exception is actually an ElasticsearchException

and it has a status of CONFLICT. It’d have been an HTTP 409 if this wasn’t a multi get.

getMessage explains the actual cause, `