0

I want to use Elasticsearch's aggregation to do OLAP data analysis. What I want to do is nested a scriptedMetric aggregation into a term aggregation,as below (it's correct)

{
    "from": 0,
    "size": 0,
  "query":{
    "bool":{
      "must":[
        {
          "match":{
            "poi_id":1
          }
        }
        ]
    }
  },
    "aggregations": {
        "poi_id": {
            "terms": {
                "script": {
                    "inline": "doc['poi_id'].value + 1"
                }
            },
            "aggregations": {
                "price": {
                    "sum": {
                        "field": "price"
                    }
                }
            }
        }
    }
}

But I didn't find how to do this in Elasticsearch's java api.

I've tried it this way:

SearchResponse response = client.prepareSearch("poi")
        .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
        .setFetchSource(new String[]{"poi_id","poi_name"}, null)
        .setQuery(QueryBuilders.termQuery("poi_id", 1))
        .addAggregation(AggregationBuilders.terms("poi_id").subAggregation((AggregationBuilders.scriptedMetric("poi_id").mapScript(new Script("doc['poi_id'].value + 1")))))
        .execute()
        .actionGet();

But got an error

Caused by: NotSerializableExceptionWrapper[: value source config is invalid; must have either a field context or a script or marked as unwrapped]; nested: IllegalStateException[value source config is invalid; must have either a field context or a script or marked as unwrapped];

I've searched a lot, but can't find a demo.

Any help would be appreciated.

Thanks!

lulijun
  • 415
  • 3
  • 22

1 Answers1

0
    @Override
public Map<String, Object> sumPriceAggregation(String field, int page, int size) {
    if (StringUtils.isEmpty(field)) {
        field = "brandName";
    }
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    PageRequest pageRequest = PageRequest.of(page, size);
    queryBuilder.withPageable(pageRequest);
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[] {""}, null));
    String termStr = field.toUpperCase();
    TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(termStr)
            .field(field)
            .subAggregation(AggregationBuilders.sum("totalPrice").field("price")); //be aware this is subAggregation
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.addAggregation(termsAggregationBuilder);
    AggregatedPage<GamingLaptop> aggregatedPage = elasticsearchRestTemplate.queryForPage(
            nativeSearchQueryBuilder.build(), GamingLaptop.class);
    Aggregations aggregations = aggregatedPage.getAggregations();
    ParsedStringTerms stringTerms = aggregations.get(termStr);
    List<? extends Terms.Bucket> buckets = stringTerms.getBuckets();
    HashMap<String, Object> map = new HashMap<>();
    buckets.parallelStream().forEach(bucket -> {
        String key = bucket.getKeyAsString();
        long docCount = bucket.getDocCount();
        map.put(key, docCount);
        ParsedSum sum = (ParsedSum) bucket.getAggregations().asMap().get("totalPrice"); //make sure you get the aggregation here
        map.putIfAbsent("sum", sum.getValue());
    });
    return map;
}

'value source config is invalid; must have either a field context or a script or marked as unwrapped' i encountered this error as well, please read the comments in the codes, which is my solution. Either ParsedStringTerms or TermsAggregationBuilder need to be retrieved.

redfisky
  • 11
  • 1
  • 4