NestedAggregation in co.elastic.clients:elasticsearch-java

Hi,

I'm currently migrating my project to use the new client co.elastic.clients:elasticsearch-java:7.17.22. Previously, with org.elasticsearch:elasticsearch:7.8.1, I created nested aggregations in my JUnit tests like this:

TermsAggregationBuilder expectedTerms = new TermsAggregationBuilder("agg");
        expectedTerms.field("data.Nested.NestedInner.NestedInnerField");
        expectedTerms.size(1000);
NestedAggregationBuilder expectedInnerNested = new NestedAggregationBuilder("nested", "data.Nested.NestedInner");
expectedInnerNested.subAggregation(expectedTerms);

NestedAggregationBuilder expectedParentNested = new NestedAggregationBuilder("nested", "data.Nested");
expectedParentNested.subAggregation(expectedInnerNested);

This would return a JSON structure like:

{
   "nested": {
      "nested": {
         "path": "data.Nested"
      },
      "aggregations": {
         "nested": {
            "nested": {
               "path": "data.Nested.NestedInner"
            },
            "aggregations": {
               "agg": {
                  "terms": {
                     "field": "data.Nested.NestedInner.NestedInnerField",
                     "size": 1000,
                     "min_doc_count": 1,
                     "shard_min_doc_count": 0,
                     "show_term_doc_count_error": false,
                     "order": [
                        { "_count": "desc" },
                        { "_key": "asc" }
                     ]
                  }
               }
            }
         }
      }
   }
}

Now, with the new client, I tried to create the same nested aggregation using:

String jsonString = "{\"nested\":{\"nested\":{\"path\":\"data.Nested\"},\"aggregations\":{\"nested\":{\"nested\":{\"path\":\"data.Nested.NestedInner\"},\"aggregations\":{\"agg\":{\"terms\":{\"field\":\"data.Nested.NestedInner.NestedInnerField\",\"size\":1000,\"min_doc_count\":1,\"shard_min_doc_count\":0,\"show_term_doc_count_error\":false,\"order\":[{\"_count\":\"desc\"},{\"_key\":\"asc\"}]}}}}}}}";

return new NestedAggregation.Builder()
    .withJson(stringReader)
    .build();

or

new Aggregation
            .Builder()
                .withJson(stringReader)
                .build();

However, I received the following error:

co.elastic.clients.json.JsonpMappingException: Error deserializing co.elastic.clients.elasticsearch._types.aggregations.NestedAggregation: Unknown field 'nested' (JSON path: nested) (line no=1, column no=10, offset=9)

or

Caused by: co.elastic.clients.json.JsonpMappingException: Error deserializing co.elastic.clients.elasticsearch._types.aggregations.NestedAggregation: Unknown field 'nested' (JSON path: nested.nested) (line no=1, column no=20, offset=19)
	at co.elastic.clients.json.ObjectDeserializer.parseUnknownField

Can anyone help me understand what I'm doing wrong? How can I properly create a NestedAggregation with sub-aggregations using the new client?

Thanks!

Hello and welcome!

The first part of the json structure you sent:

   "nested": {
      "nested": {
         "path": "data.Nested"
      },

isn't part of the aggregation structure, that's why the new client doesn't recognize it. I was trying to understand what it actually is by sending the request to the server using the Kibana dev tools, but it doesn't seem to be a query, could you give me more information on this?

In the meantime, this is how to write a nested aggregation with the 7.17.21 version of the java client:

 esClient.search(s -> s.index("my-index")
     .aggregations("nested", a -> a
         .nested(n -> n.path("data.Nested.NestedInner"))
         .aggregations("agg", ag -> ag
             .terms(t -> t
                 .field("data.Nested.NestedInner.NestedInnerField")
                 .size(1000)
                 .minDocCount(1)
                 .showTermDocCountError(false)
                  .order(NamedValue.of("_count", SortOrder.Desc),NamedValue.of("_key",SortOrder.Asc)))))
     , Object.class);

There's one field missing which is shard_min_doc_count, we just recently noticed it was missing from TermsAggregation, we already merged a fix for it which will be available in the 7.17.23 version coming out in a few days.

Hi,

We have a junit test to create nestedAggregations + subAggregations:

TermsAggregationBuilder expectedTerms = new TermsAggregationBuilder("agg");
        expectedTerms.field("data.Nested.NestedInner.NestedInnerField");
        expectedTerms.size(1000);
        NestedAggregationBuilder expectedInnerNested = new NestedAggregationBuilder("nested", "data.Nested.NestedInner");
        expectedInnerNested.subAggregation(expectedTerms);
        NestedAggregationBuilder expectedParentNested = new NestedAggregationBuilder("nested1", "data.Nested");
        expectedParentNested.subAggregation(expectedInnerNested);

expectedParentNested will have

{
   "nested":{
      "nested":{
         "path":"data.Nested"
      },
      "aggregations":{
         "nested":{
            "nested":{
               "path":"data.Nested.NestedInner"
            },
            "aggregations":{
               "agg":{
                  "terms":{
                     "field":"data.Nested.NestedInner.NestedInnerField",
                     "size":1000,
                     "min_doc_count":1,
                     "shard_min_doc_count":0,
                     "show_term_doc_count_error":false,
                     "order":[
                        {
                           "_count":"desc"
                        },
                        {
                           "_key":"asc"
                        }
                     ]
                  }
               }
            }
         }
      }
   }
}

As far as I understand this test, we wanted to have

"nested":{
         "path":"data.Nested",
         "name": "nested"
      }

instead of

 "nested":{
      "nested":{
         "path":"data.Nested"
      }

In java docs, I found `NestedAggregationBuilder(name, path), name - is name of Aggregation but not a node 'Nested'

A new client:

Aggregation.of(builder -> builder
                .nested(n -> n.path("data.Nested"))
                .aggregations("nested", n -> n.nested(s ->s.path("data.Nested.NestedInner").name("nested1"))).aggregations("agg",
                        a -> a.terms(t -> t.field("data.Nested.NestedInner.NestedInnerField").size(100))));
nested:{
"path": data.Nested.NestedInner
"name: nested1
}

I think it is OK.

Hope it helped! If you're still having issues with aggregations here are some other examples of nested/sub aggregations:

1 Like

Thank you :wink: