1

I have an interface extending ElasticsearchRepository and have successfully created methods to search such as:

Page<AuditResult> findByCustomerCodeAndHost(String customerCode, String host, Pageable pageable);

Now, I want an endpoint to hit that would return me all of the possible host values for that customerCode so that I can build a dropdown list in my front end to select a value to send to that findByCustomerCodeAndHost endpoint, something like:

List<String> findUniqueHostByCustomerCode(String customerCode)

Is this even possible using an ElasticsearchRepository?

I know there is the Distinct keyword I can use like List<String> findDistinctByCustomerCode(String customerCode); but this doesn't let me specify the host field.


Edit: Here is how I accomplished what I wanted but as it is not currently possible to actually do this with ElasticsearchRepository it isn't an actual "answer".

I created a Spring web @RestController class that I exposed a @GetMapping REST endpoint that executed an aggregation query.

The query in kibana console:

GET auditresult/_search
{
  "size": "0",
  "aggs" : {
    "uniq_custCode" : {
      "terms" : { "field" : "customerCode", "include": "<CUSTOMER_CODE>" },
        "aggs" : {
          "uniq_host" : {
           "terms" : { "field" : "host"}
          }
        }
      }
    }
  }

And, based off this question ElasticSearch aggregation with Java I came up with

@GetMapping("/hosts/{customerCode}")
String getHostsByCustomer(@PathVariable String customerCode) {
    SearchRequest searchRequest = new SearchRequest("auditresult");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0);
    IncludeExclude ie = new IncludeExclude(customerCode, "");
    TermsAggregationBuilder aggregation =
            AggregationBuilders
                    .terms("uniq_custCode").includeExclude(ie)
                    .field("customerCode")
                    .subAggregation(
                            AggregationBuilders
                                    .terms("uniq_host")
                                    .field("host")
                    );
    searchSourceBuilder.aggregation(aggregation);
    searchRequest.source(searchSourceBuilder);
    try {
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        Terms cust = searchResponse.getAggregations().get("uniq_custCode");
        StringBuilder sb = new StringBuilder();
        sb.append("{\"hosts\":[");
        for (Terms.Bucket bucket : cust.getBuckets()) {
            Terms hosts = bucket.getAggregations().get("uniq_hosts");
            for (Terms.Bucket host : hosts.getBuckets()) {
                System.out.println(host.getKey());
                sb.append("\"" + host.getKey() + "\",");
            }
        }
        String out = sb.toString();
        out = out.substring(0, out.length() - 1);
        return out + "]}";
    } catch (IOException e) {
        e.printStackTrace();
        return "{\"hosts\":[]}";
    }
}

1 Answer 1

1

What you would need here is something Spring Data calls projections, for Spring Data MongoDB you can read the documentation to see how it works there.

Alas this is not implemented in Spring Data Elasticsearch (yet), I created an issue in Jira for this.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.