class DistinctAction extends Action<DistinctRequest> {

    @Override
    public ActionResponse execute(DistinctRequest request) throws QueryStoreException {
        request.setTable(ElasticsearchUtils.getValidTableName(request.getTable()));
        if (null == request.getFilters()) {
            request.setFilters(Lists.<Filter>newArrayList(new AnyFilter(request.getTable())));
        }
        if (request.getTable() == null) {
            throw new QueryStoreException(QueryStoreException.ErrorCode.INVALID_REQUEST, "Invalid Table");
        }
        try {
            SearchRequestBuilder query = getConnection().getClient().prepareSearch(ElasticsearchUtils.getIndices(
                    request.getTable(), request));
            TermsBuilder rootBuilder = null;
            TermsBuilder termsBuilder = null;

            for (ResultSort nestedField : request.getNesting()) {
                if (nestedField.getField() == null || nestedField.getField().trim().isEmpty()) {
                    throw new QueryStoreException(QueryStoreException.ErrorCode.INVALID_REQUEST, "Illegal Nesting Parameters");
                }

                String aggregationKey = Utils.sanitizeFieldForAggregation(nestedField.getField());
                Terms.Order order = (nestedField.getOrder() == ResultSort.Order.desc) ? Terms.Order.term(false) : Terms.Order.term(true);

                if (null == termsBuilder) {
                    termsBuilder = AggregationBuilders.terms(aggregationKey).field(nestedField.getField()).order(order);
                } else {
                    TermsBuilder tempBuilder = AggregationBuilders.terms(aggregationKey).field(nestedField.getField()).order(order);
                    termsBuilder.subAggregation(tempBuilder);
                    termsBuilder = tempBuilder;
                }
                termsBuilder.size(0);
                if (null == rootBuilder) {
                    rootBuilder = termsBuilder;
                }
            }
            query.setQuery(new ElasticSearchQueryGenerator(FilterCombinerType.and)
                    .genFilter(request.getFilters()))
                    .setSearchType(SearchType.COUNT)
                    .addAggregation(rootBuilder);
            SearchResponse response = query.execute().actionGet();
            Aggregations aggregations = response.getAggregations();
            // Check if any aggregation is present or not
            if (aggregations == null) {
                logger.error("Null response for Group. Request : " + request.toString());
                return new DistinctResponse(new ArrayList<String>(), new ArrayList<List<String>>());
            }
            return getDistinctResponse(request, aggregations);
        } catch (QueryStoreException ex) {
            throw ex;
        } catch (Exception e) {
            logger.error("Error running grouping: ", e);
            throw new QueryStoreException(QueryStoreException.ErrorCode.QUERY_EXECUTION_ERROR,
                    "Error running group query.", e);
        }
    }

    public  DistinctAction(DistinctRequest request,
                          TableMetadataManager tableMetadataManager,
                          DataStore dataStore,
                          QueryStore queryStore,
                          ElasticsearchConnection connection,
                          String cacheToken);

}