Search code examples
javaspringspring-bootelasticsearchspring-data-elasticsearch

spring data elastic : Aggregator [total_sum_metric] of type [sum] cannot accept sub-aggregation


I'm new on spring data elastic and i'm facing issue about query aggregation. My stack is : spring boot 3, spring 6, elastic client 8.5.x. My elastic search host version is 7.xx. So let's assume we have this query on elastic

GET someIndex-* /_search
{

  "size": 0,
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "@timestamp": {
              "gte": "1688688000000",
              "lte": "1688774399999",
              "format": "epoch_millis"
            }
          }
        },
        {
          "query_string": {
            "analyze_wildcard": true,
            "query": "name: alise"
          }
        }
      ]
    }
  },
  "aggs": {
    "by_term": {
      "terms": {
        "field": "Product_type.keyword",
        "size": 10,
        "order": {
          "total_sum_metric": "desc"
        },
        "min_doc_count": 1
      },
      "aggs": {
        "total_sum_metric": {
          "sum": {
            "field": "metric"
          }
        },
        "group_by_date": {
          "date_histogram": {
            "interval": "30s",
            "field": "@timestamp",
            "min_doc_count": 1,
            "extended_bounds": {
              "min": "1688688000000",
              "max": "1688774399999"
            },
            "format": "epoch_millis"
          },
          "aggs": {
            "total_sum_metric": {
              "sum": {
                "field": "metric"
              }
            }
          }
        }
      }
    }
  }
}

I wrote this query to spring data native query.

 public void retrieveApplicationDetails(String applicationName, @NonNull LocalDateTime startDateTime, @NonNull LocalDateTime endDateTime) {
       final var startmilliSecond = startDateTime
             .atZone(ZoneOffset.UTC)
             .toInstant()
             .toEpochMilli();
       final var endmilliSecond = endDateTime
             .minusMinutes(1)
             .atZone(ZoneOffset.UTC)
             .toInstant()
             .toEpochMilli();
final var query = buildSearchQuery(applicationName, startmilliSecond, endmilliSecond);
       SearchHits<Object> search = elasticsearchOperations.search(query, Object.class, IndexCoordinates.of("Index-*"));
private static NativeQuery buildSearchQuery(String applicationName, long startmilliSecond, long endmilliSecond) {
    var rangeQuery = new Query.Builder()
          .range(ran -> ran
                .field("@timestamp")
                .format("epoch_millis")
                .gte(JsonData.of(startmilliSecond))
                .lte(JsonData.of(endmilliSecond)))
          .build();

    var queryString = new QueryStringQuery.Builder()
          .query("name: %s".formatted(applicationName))
          .analyzeWildcard(true)
          .build()
          ._toQuery();

    final var termsAggregation = TermsAggregation.of(termBuilder -> termBuilder
          .field("Product_type.keyword")
          .size(10)
          .minDocCount(1)
          .order(new NamedValue<>("total_sum_metric", SortOrder.Desc)));

    final var sumAggregation = SumAggregation.of(metricAggregation -> metricAggregation.field("metric"));

    final var query = QueryBuilders.bool(boolBuilder -> boolBuilder.filter(List.of(rangeQuery, queryString)));

    final var groupByDateAggregation = Aggregation.of(byDateBuilder -> byDateBuilder
          .dateHistogram(dateHistoBuilder -> dateHistoBuilder
                .field("@timestamp")
                .fixedInterval(intervalBuilder -> intervalBuilder.time("30s"))
                .minDocCount(1)
                .extendedBounds(extendsBoundBuilder -> extendsBoundBuilder
                      .min(FieldDateMath.of(minBuilder -> minBuilder.value((double) startmilliSecond)))
                      .max(FieldDateMath.of(maxBuilder -> maxBuilder.value((double) endmilliSecond))))
                .format("epoch_millis")

          )
          .aggregations("total_sum_metric", sumAggregation));

    final var byTermAggregation = Aggregation.of(aggBuilder -> aggBuilder
          .terms(termsAggregation)
          .aggregations("total_sum_metric", Aggregation.of(sumMetricBuilder -> sumMetricBuilder
                .sum(sumAggregation)
                .aggregations("group_by_date", groupByDateAggregation))));

    return NativeQuery
          .builder()
          .withQuery(query)
          .withAggregation("by_term", byTermAggregation)
          .withMaxResults(0)
          .withPageable(PageRequest.of(0, MAX_PAGE_REQUEST_SIZE))
          .build();

}

So when I'm trying to request this on my elastic I'm getting this error Aggregator [total_sum_metric] of type [sum] cannot accept sub-aggregation. Some one knows what is my mistakes ? Thanks to those who will take the time to read me


Solution

  • my issue was in byTermAggregation. I added another nested aggregation on total_sum_metric. this is the good query :

    final var byTermAggregation = Aggregation.of(aggBuilder -> aggBuilder
              .terms(termsAggregation)
              .aggregations("total_sum_metric", Aggregation.of(sumMetricBuilder -> sumMetricBuilder.sum(sumAggregation))
              .aggregations("group_by_date", groupByDateAggregation))));