Springdata elasticsearch 5.2 nested aggregation without subAggregation

Help Needed: Nested Aggregations with Java API Client v8

I'm working on a project using Elasticsearch with the Java API Client v8, and I'm struggling to correctly implement nested aggregations. I'd greatly appreciate any help or guidance.

Index Mapping

Here's the relevant part of my index mapping:

{
  "actions" : {
    "mappings" : {
      "properties" : {
        "actionRoles" : {
          "type" : "nested",
          "properties" : {
            "roleName" : {
              "type" : "keyword"
            }
          }
        },
        // ... other fields ...
      }
    }
  }
}

I need to find out how to make this TODO

fun toNativeQuery(): NativeQuery {
        val criteriaQuery = CriteriaQuery(criteria)
        val queryBuilder = NativeQuery.builder().withQuery(criteriaQuery)
        //...
            
        queryBuilder.withAggregation(
            AGG_ACTION_ROLE,
            //TODO: Add the nested aggregation for 'actionRoles.roleName'
            
        )
        //...
        return queryBuilder.build()
    }

I should be able to get this aggregation generated, which is working in Kibana

{
  "aggregations": {
    "actionRoles": {
      "nested": {
        "path": "actionRoles"
      },
      "aggregations": {
        "roleNames": {
          "terms": {
            "field": "actionRoles.roleName",
            "size": 1000
          }
        }
      }
    }
  }

Since subAggregation has been removed in elasticsearch-rest-client 8, I couldn't make it work for now.

I guess I have to do something like

queryBuilder.withAggregation(
            AGG_ACTION_ROLE,
            //TODO: Add the nested aggregation for 'actionRoles'
            AggregationBuilders.nested {
                //how to do the nested aggregation here?
            }
        ) 

Any ideas guys? Thanks a lot!

Hello and welcome! Not sure about spring data, but using the elasticsearch-java client here's how that nested aggregation with a sub aggregation should be written:

esClient.search(s -> s
    .index("my-index")
    .aggregations("actionRoles", a -> a.nested(n -> n.path("actionRoles"))
        .aggregations("roleNames", subAgg -> subAgg
            .terms(t -> t.field("actionRoles.roleName")
            .size(1000))))
    , Object.class);

Thanks @ltrotta for your answer,
Yes I saw that already but I must stick with Springdata and NativeQuery.

The closest I could do is the following:

kotlin

        queryBuilder.withAggregation(
            AGG_ACTION_ROLE,
            //TODO: Add the nested aggregation for 'actionRoles'
            AggregationBuilders.nested { nestedAgg: NestedAggregation.Builder ->
                nestedAgg.path(ActionEntity::actionRoles.name)
            },
        )

But it is incomplete and I can't get the result I need. I just get a count of the number of actionRoles with that.

In this case I'd suggest contacting the owners of spring-data-elasticsearch, it's a separate project which we're not really familiar with.

In case it might help someone, my tech lead could help and provided this solution that is indeed working

fun toNativeQuery(): NativeQuery {
            val criteriaQuery = CriteriaQuery(criteria)
            val queryBuilder = NativeQuery.builder().withQuery(criteriaQuery)
            //...
    
            val subAggRoleName =
            AggregationBuilders.terms { it.field("${ActionEntity::actionRoles.name}.${ActionRoleEntity::roleName.name}") }
            // AggregationBuilder.nested does support sub-aggregations,
            // so we need to build it with the Aggregation.Builder()
            val aggNestedActionRolesName =
            Aggregation
                .Builder()
                .nested { it.path(ActionEntity::actionRoles.name) }
                .aggregations(
                    mapOf("roleNames" to subAggRoleName),
                ).build()
            queryBuilder.withAggregation(AGG_ACTION_ROLE, aggNestedActionRolesName)

            //...
            return queryBuilder.build()
}