Conditional Aggregations

The doc is right. Your code is missing this critical part:

        .extension( ElasticsearchExtension.get() )

That’s what allows you to introduce Elasticsearch-specific code (like .fromJson) to your query. Without that, adding JSON in your query just does not make sense, since your query could be targeting a non-Elasticsearch backend (e.g. embedded Lucene).

You’re not using the right type nor the right generic type arguments for the step variable.
If you’re on Java 11+, I’d recommend the var keyword in this particular case; that’ll save you some headaches:

var step = searchSession.search(myClass)
    .extension( ElasticsearchExtension.get() )
    .where(w -> { /* ... Stuff to handle the searchFilters ... */ })
    .sort(s -> { /* ... Stuff to handle the sortOrders ... */ });

List<AggregationKey<Map<String, Long>>> aggKeys = new ArrayList<>();
for(String agg_field: agg_field_list) {
    AggregationKey<Map<String, Long>> aggKey = AggregationKey.of(agg_field);
    aggKeys.add(aggKey);
    step = step.aggregation(aggKey, p -> p.terms().field(agg_field, String.class).maxTermCount(10));
}

SearchResult<MyClass> result = step.fetch(20);
// I presume you'll want to retrieve the aggregations? You can do it like this.
Map<String, Map<String, Long>> aggByField = aggKeys.stream()
        .collect(Collectors.toMap(AggregationKey::name, result::aggregation));

If you’re still on Java 8, things will get a bit more complex, but that’s still possible:

ElasticsearchSearchQueryOptionsStep<MyClass, SearchLoadingOptionsStep> step = searchSession.search(myClass)
    .extension( ElasticsearchExtension.get() )
    .where(w -> { /* ... Stuff to handle the searchFilters ... */ })
    .sort(s -> { /* ... Stuff to handle the sortOrders ... */ });

List<AggregationKey<Map<String, Long>>> aggKeys = new ArrayList<>();
for(String agg_field: agg_field_list) {
    AggregationKey<Map<String, Long>> aggKey = AggregationKey.of(agg_field);
    aggKeys.add(aggKey);
    step = step.aggregation(aggKey, p -> p.terms().field(agg_field, String.class).maxTermCount(10));
}

SearchResult<MyClass> result = step.fetch(20);
// I presume you'll want to retrieve the aggregations? You can do it like this.
Map<String, Map<String, Long>> aggByField = aggKeys.stream()
        .collect(Collectors.toMap(AggregationKey::name, result::aggregation));

Had you not been using the Elasticsearch extension, the type of “step” would have been a tad more complex:

SearchQueryOptionsStep<?, MyClass, SearchLoadingOptionsStep, ?, ?> step = searchSession.search(myClass)
    .where(w -> { /* ... Stuff to handle the searchFilters ... */ })
    .sort(s -> { /* ... Stuff to handle the sortOrders ... */ });

List<AggregationKey<Map<String, Long>>> aggKeys = new ArrayList<>();
for(String agg_field: agg_field_list) {
    AggregationKey<Map<String, Long>> aggKey = AggregationKey.of(agg_field);
    aggKeys.add(aggKey);
    step = step.aggregation(aggKey, p -> p.terms().field(agg_field, String.class).maxTermCount(10));
}

SearchResult<MyClass> result = step.fetch(20);
// I presume you'll want to retrieve the aggregations? You can do it like this.
Map<String, Map<String, Long>> aggByField = aggKeys.stream()
        .collect(Collectors.toMap(AggregationKey::name, result::aggregation));
1 Like