Watcher - Write painless script for looping aggregated buckets

Hi,

My Watcher condition is giving output as below:

Watcher condition Output:

{
    "_shards": {
        "total": 1,
        "failed": 0,
        "successful": 1,
        "skipped": 0
    },
    "hits": {
        "hits": [],
        "total": {
            "value": 23,
            "relation": "eq"
        },
        "max_score": null
    },
    "took": 26,
    "timed_out": false,
    "aggregations": {
        "data_aggs_interval": {
            "buckets": [
                {
                    "key_as_string": "2022-11-24T00:00:00.000Z",
                    "doc_count": 8,
                    "tag_names": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 2,
                        "buckets": [
                            {
                                "doc_count": 3,
                                "metrics": {
                                    "value": 3000
                                },
                                "key": "I_DRV155_CFB"
                            },
                            {
                                "doc_count": 3,
                                "metrics": {
                                    "value": 197
                                },
                                "key": "M_E2MDD_CFB"
                            }
                        ]
                    },
                    "key": 1669248000000
                },
                {
                    "key_as_string": "2022-12-04T00:00:00.000Z",
                    "doc_count": 15,
                    "tag_names": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 1,
                        "buckets": [
                            {
                                "doc_count": 10,
                                "metrics": {
                                    "value": 197
                                },
                                "key": "M_E2MDD_CFB"
                            },
                            {
                                "doc_count": 4,
                                "metrics": {
                                    "value": 197
                                },
                                "key": "I_RM3201_RTD_08"
                            }
                        ]
                    },
                    "key": 1670112000000
                }
            ]
        }
    }
}

I want to write a trigger condition, to trigger an alert when each bucket contains "key" : I_DRV155_CFB and "value" > "200".

Below is my trigger condition, I am able to build condition to check only 1 bucket which is bucket[0], I tried writing trigger condition to check for all buckets using for loop, but no luck.

Current working trigger condition which is accessing single bucket:

return ctx.results[0].aggregations.data_aggs_interval.buckets[0].tag_names.buckets[0].metrics.value == null ? false:
(ctx.results[0].aggregations.data_aggs_interval.buckets[0].tag_names.buckets[0].metrics.value >= 3000 && 
ctx.results[0].aggregations.data_aggs_interval.buckets[0].tag_names.buckets[0].key == "I_DRV155_CFB")

Let me how to implement trigger condition on all buckets.

I tried it using for loop but getting error:

for (int i = 0; i < ctx.results[0].aggregations.data_aggs_interval.buckets.size(); i++) 
{
return ctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].metrics.value == null ? false:
(ctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].metrics.value >= 3000 && 
ctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].key == "I_DRV155_CFB")
}

Error:

{
  "type" : "script_exception",
  "reason" : "compile error",
  "script_stack" : [
    "for (int i = 0; i < ctx.r ...",
    "^---- HERE"
  ],
  "script" : "for (int i = 0; i < ctx.results[0].aggregations.data_aggs_interval.buckets.size(); i++) \n{\nreturn ctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].metrics.value == null ? false:\n(ctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].metrics.value >= 3000 && \nctx.results[0].aggregations.data_aggs_interval.buckets[i].tag_names.buckets[i].key == \"I_DRV155_CFB\")\n}",
  "lang" : "painless",
  "position" : {
    "offset" : 0,
    "start" : 0,
    "end" : 25
  },
  "caused_by" : {
    "type" : "illegal_argument_exception",
    "reason" : "extraneous for loop"
  }
}

Ref link: ElasticSearch Watcher Painless script : illegal_argument_exception, reson: Extraneous for loop - Elasticsearch - Discuss the Elastic Stack

So, you need two (nested) loops, the first to iterate over the data_aggs_interval.buckets and then within that, iterate over the tag_names.buckets. Something like this:

    "condition": {
      "script": """
        for (def interval : ctx.payload.aggregations.data_aggs_interval.buckets) {
            for (def tag : interval.tag_names.buckets) {
                if (tag.key == "I_DRV155_CFB" && tag.avg_resp.value >= 3000) {
                  return true;
                }
          }
        }
        """
    },
1 Like

Ful working example using demo data: alert_on_entity_in_an_interval.txt · GitHub

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.