Count API

Count Request

The CountRequest is used to execute a query and get the number of matches for the query. The query to use in CountRequest can be set in similar way as query in SearchRequest using SearchSourceBuilder.

In its most basic form, we can add a query to the request:

CountRequest countRequest = new CountRequest(); 
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); 
countRequest.source(searchSourceBuilder); 

Creates the CountRequest. Without arguments this runs against all indices.

Most search parameters are added to the SearchSourceBuilder.

Add a match_all query to the SearchSourceBuilder.

Add the SearchSourceBuilder to the CountRequest.

Count Request optional arguments

A CountRequest also takes the following optional arguments:

CountRequest countRequest = new CountRequest("blog") 
    .routing("routing") 
    .indicesOptions(IndicesOptions.lenientExpandOpen()) 
    .preference("_local"); 

Restricts the request to an index

Set a routing parameter

Setting IndicesOptions controls how unavailable indices are resolved and how wildcard expressions are expanded

Use the preference parameter e.g. to execute the search to prefer local shards. The default is to randomize across shards.

Using the SearchSourceBuilder in CountRequest

Both in search and count API calls, most options controlling the search behavior can be set on the SearchSourceBuilder, which contains more or less the equivalent of the options in the search request body of the Rest API.

Here are a few examples of some common options:

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); 
sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy")); 

Create a SearchSourceBuilder with default options.

Set the query. Can be any type of QueryBuilder

After this, the SearchSourceBuilder only needs to be added to the CountRequest:

CountRequest countRequest = new CountRequest();
countRequest.indices("blog", "author");
countRequest.source(sourceBuilder);

Note subtle difference when using SearchSourceBuilder in SearchRequest and using SearchSourceBuilder in CountRequest - using SearchSourceBuilder in SearchRequest one can use SearchSourceBuilder.size() and SearchSourceBuilder.from() methods to set the number of search hits to return, and the starting index. In CountRequest we’re interested in total number of matches and these methods have no meaning.

The Building Queries page gives a list of all available search queries with their corresponding QueryBuilder objects and QueryBuilders helper methods.

Synchronous Execution

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

CountResponse countResponse = client
    .count(countRequest, 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 CountRequest 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 count method:

client.countAsync(countRequest, RequestOptions.DEFAULT, listener); 

The CountRequest 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 count looks like:

ActionListener<CountResponse> listener =
    new ActionListener<CountResponse>() {

        @Override
        public void onResponse(CountResponse countResponse) {
            
        }

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

Called when the execution is successfully completed.

Called when the whole CountRequest fails.

CountResponse

The CountResponse that is returned by executing the count API call provides total count of hits and details about the count execution itself, like the HTTP status code, or whether the request terminated early:

long count = countResponse.getCount();
RestStatus status = countResponse.status();
Boolean terminatedEarly = countResponse.isTerminatedEarly();

The response also provides information about the execution on the shard level by offering statistics about the total number of shards that were affected by the underlying search, and the successful vs. unsuccessful shards. Possible failures can also be handled by iterating over an array off ShardSearchFailures like in the following example:

int totalShards = countResponse.getTotalShards();
int skippedShards = countResponse.getSkippedShards();
int successfulShards = countResponse.getSuccessfulShards();
int failedShards = countResponse.getFailedShards();
for (ShardSearchFailure failure : countResponse.getShardFailures()) {
    // failures should be handled here
}