1

Using ElasticSearch 7.0, I can get how many log I have for each user with an aggregation :

"aggs": {
    "by_user": {
        "terms": {
            "field": "user_id",
        }
    }
}

This returns me something like:

user32: 25
user52: 20
user10: 20
...

What I would like is to know how many user have 25 logs, and how many user have 20 logs etc. The ideal result would be something like :

25: 1
20: 2
19: 4
12: 54

Because 54 users have 12 logs lines.

How can I make an aggregation that returns this result ?

blue112
  • 52,634
  • 3
  • 45
  • 54
  • I´ll would go with this as a sub aggregation https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html – ibexit May 22 '19 at 14:07

1 Answers1

2

It sounds like you can use Bucket Script Aggregation to simplify your query but the problem is that there is still open PR on this topic.

So, for now i think the simplest is to use painless script with Scripted Metric Aggregation. I recommend you to carefully read about the stages of its execution.

In terms of code I know it's not the best algorithm for your problem but quick and dirty your query could look something like this:

GET my_index/_search
{
  "size": 0, 
    "query" : {
        "match_all" : {}
    },
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : "state.transactions = [:];", 
                "map_script" :
                """
                def key = doc['firstName.keyword'];
                if (key != null && key.value != null) {
                  def value = state.transactions[key.value];
                  if(value==null) value = 0;
                  state.transactions[key.value] = value+1
                }
                """,
                "combine_script" : "return state.transactions",
                "reduce_script" : 
                """
                def result = [:];
                for (state in states) {
                  for (item in state.entrySet()) {
                    def key=item.getValue().toString();
                    def value = result[key];
                    if(value==null)value = 0;
                    result[key]=value+1;
                  }
                } 
                return result;
                """
            }
        }
    }
}
Andrey Borisko
  • 4,511
  • 2
  • 22
  • 31
  • 1
    I really doubt if this is possible using `bucket script aggregation`. The one you've proposed seems to be the only way to achieve it! Brilliant solution though!! – Kamal Kunjapur May 22 '19 at 22:00