Alex Zhulin
Alex Zhulin

Reputation: 1305

ElasticSearch aggregation with Java

I want to get aggregation in my java application.

First of all I've constracted REST query with curl. It's looks like:

curl -XGET 'localhost:9200/analysis/_search?pretty' -H 'Content-Type: 

application/json' -d'
{
  "size": 0,
  "query" : {
      "bool": {
          "must": [
              { "term" : { "customer_id" : 5117 } }
          ]
      }
  },
  "aggs": {
    "customer_id": {
      "terms": {
        "field": "customer_id", 
        "order": {
          "contract_sum": "desc"
        }
      },
      "aggs": {
        "contract_sum": {
          "sum": {
            "field": "contract_sum"
          }
        }
      }
    }
  }
}
'

It returned result as I expected

enter image description here

After that I've created some code in java

    Settings settings = Settings.builder().put("cluster.name", elasticProperties.getElasticClusterName()).build();
    log.info("Initializing ElasticSearch client");
    try (TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(
            InetAddress.getByName(elasticProperties.getElasticTransportAddress()), elasticProperties.getElasticTransportPort()))) {

        // Base query
        log.info("Preparing query");
        SearchRequestBuilder requestBuilder = client.prepareSearch(elasticProperties.getElasticIndexName())
                .setTypes(elasticProperties.getElasticTypeName())
                .setSize(Top);

        // Add aggregations
        AggregationBuilder aggregation =
                AggregationBuilders
                        .terms("customer_id")
                        .field("customer_id")
                        //.order(Terms.Order.aggregation("customer_id", "contract_sum", false))
                        .subAggregation(
                                AggregationBuilders.sum("total_contract_sum")
                                .field("contract_sum")
                        );
        requestBuilder.addAggregation(aggregation);
        // Get response
        log.info("Executing query");
        SearchResponse response = requestBuilder.get();

        log.info("Query results:");

        Terms contractSums = response.getAggregations().get("customer_id");
        for (Terms.Bucket bucket : contractSums.getBuckets()) {
            log.info("  " + bucket.getKey() + " ");
        }

The question is:

How to get "contract_sum" aggregation value for current bucket item?

When I use debug tool in IntelliJ Idea it seems that it can

enter image description here

Please help me with code example.

Upvotes: 9

Views: 24422

Answers (3)

Vikas Tiwari
Vikas Tiwari

Reputation: 11

public Map<String, Collection<Map<String, Object>>> processAggregation(SearchResponse response) {
    Map<String,Collection<Map<String, Object>>> responseMap = new HashMap<>();
    try {
        if(response.getAggregations() != null) {
            for (Aggregation agg : response.getAggregations().asList()) {
                String key = agg.getName();
                Terms terms = response.getAggregations().get(key);
                Collection<Map<String, Object>> objects = new HashSet<>();
                Map<String, Object> result = new HashMap<>();
                for(Terms.Bucket bucket : terms.getBuckets()){
                    String extLabel = (String) bucket.getKey();
                    Object count = bucket.getDocCount();
                    result.put(extLabel,count);
                }
                objects.add(result);
                responseMap.put(key,objects);
            }
        }
        return responseMap;
    } catch (Exception e) {
        log.error("Unable to process search response");
    }
    return null;
}

Upvotes: 0

Ameya Sawant
Ameya Sawant

Reputation: 1

https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_bucket_aggregations.html

public List<StringBuilder> aggregation(String filterField, Object start, Object end, String... fields) throws IOException {
    List<StringBuilder> results = new LinkedList<>();
    SearchRequest searchRequest = new SearchRequest(this.index);
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    if (!StringUtils.isEmpty(filterField)){
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery(filterField).gte(start).lte(end);
        searchSourceBuilder.query(queryBuilder);
    }
    AggregationBuilder aggregationBuilder = buildAggregation(fields, 0);

    if(aggregationBuilder == null)
        return results;
    searchSourceBuilder.aggregation(aggregationBuilder);

    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);

    Terms terms = searchResponse.getAggregations().get(fields[0]);
    processBuckets(terms, new Stack<>(), results);
    return results;
}

public AggregationBuilder buildAggregation(String[] fields, int i) {
    if(i == fields.length - 1)
        return aggregationBuilder(fields[i]);

    return aggregationBuilder(fields[i]).subAggregation(buildAggregation(fields, i + 1));
}

private AggregationBuilder aggregationBuilder(String term) {
    return AggregationBuilders
            .terms(term)
            .field(term)
            .size(1000)
            .order(BucketOrder.count(false));
}

public void processBuckets(Terms terms, Stack<String> stack, List<StringBuilder> results) {
    if(terms != null) {
        for (Terms.Bucket bucket : terms.getBuckets()) {
            stack.push(bucket.getKeyAsString() + ":" + bucket.getDocCount() + ";");
            if(bucket.getAggregations().asList().isEmpty()) {
                StringBuilder result = new StringBuilder();
                for (String s : stack) {
                    result.append(s);
                }
                results.add(result);
            }

            for (Aggregation aggregation : bucket.getAggregations().asList()) {
                processBuckets((Terms) aggregation, stack, results);
            }
            stack.pop();
        }
    }
}

Upvotes: 0

Alex Zhulin
Alex Zhulin

Reputation: 1305

I've found solution with my Internet friends

log.info("Query results:");
Terms contractSums = response.getAggregations().get("customer_id");
for (Terms.Bucket bucket : contractSums.getBuckets()) {
    Sum aggValue = bucket.getAggregations().get("total_contract_sum");
    DecimalFormat formatter = new DecimalFormat("0.00");
    log.info("  " + bucket.getKey() + " " + formatter.format(aggValue.getValue()));
}

Upvotes: 9

Related Questions