Create a histogram with N buckets of interval X where the last bucket also includes the counts greater than its interval

Viewed 104

I have objects where every object has a nonnegative "weight" field. i want to sort the objects into 10 weight classes of interval 100, i tried putting in the "aggs" field, the following:

        "aggs":{
          "weights":{
            "histogram":{
              "interval":100,
              "field":"weight"
            }
          }
        }

But this would give me every interval of 100, e.g.(starting interval : doc_count)

(0 : 3) (100 : 5) ... (900 : 3) (1000 : 2) (1100 : 5)

What I would like instead is

(0 : 3) (100 : 5) ... (900 : 10) where 10 comes from the bucket itself and all buckets after it

I tried using the range feature: "range":{"weight":{"to":"1000"}} but that ignores all the buckets that come after the 10th one. Is this possible with the histogram feature on elastic? Or would this require something else?

1 Answers

If you're only interested in the count of the buckets (and not, say, the sum of all weights), you could force all values above 900 into the last bucket using a range aggregation value script:

{
  "size": 0,
  "aggs": {
    "weight_ranges": {
      "range": {
        "field": "weight", 
        "script": {
          "lang": "painless",
          "source": "_value <= 900 ? _value : 900"
        },
        "ranges": [
          { "to": 100 },
          { "from": 100, "to": 200 },
          { "from": 200, "to": 300 },
          { "from": 300, "to": 400 },
          { "from": 400, "to": 500 },
          { "from": 500, "to": 600 },
          { "from": 600, "to": 700 },
          { "from": 700, "to": 800 },
          { "from": 800, "to": 900 },
          { "from": 900 }
        ]
      }
    }
  }
}

If you're dynamically generating these histograms and the value 900 is arbitrary / parametrizable, you could store the script like so:

POST _scripts/histogram_cutoff
{
  "script": {
    "lang": "painless",
    "source": "_value <= params.cutoff ? _value : params.cutoff"
  }
}

and then reference it in any subsequent query by its ID:

POST weights/_search
{
  "size": 0,
  "aggs": {
    "weight_ranges": {
      "range": {
        "field": "weight", 
        "script": {
          "id": "histogram_cutoff",     <--
          "params": {
            "cutoff": 900
          }
        },
        "ranges": [
          { "to": 100 },
          ...
          { "from": 900 }
        ]
      }
    }
  }
}
Related