ElasticSearch Watcher Painless script : illegal_argument_exception, reson: Extraneous for loop

I'm running a applicaiton and I want to alert on apiName with different threshold
here is my query result:

{
  "took": 120,
  "timed_out": false,
  "_shards": {
    "total": 139,
    "successful": 139,
    "skipped": 133,
    "failed": 0
  },
  "hits": {
    "total": 70,
    "max_score": 0,
    "hits": [
      ...
    ]
  },
  "aggregations": {
    "failed_api": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "articlenumber",
          "doc_count": 38
        },
        {
          "key": "authorad",
          "doc_count": 15
        },
        {
          "key": "articlepv",
          "doc_count": 13
        },
        {
          "key": "authorarticlelist",
          "doc_count": 3
        },
        {
          "key": "author",
          "doc_count": 1
        }
      ]
    }
  }
}

key is the apiName, and alert is triggerd when key ' articlenumber' occurs over 5 time or any other individual key occurs over 20 times, so I have a conditon of painless script like this

"condition" : {
      "script" : """
      for (int i = 0 ; i < ctx.payload.aggregations.failed_api.buckets.size(); i ++) {
        String key = ctx.payload.aggregations.failed_api.buckets.get(i).key;
        int value = ctx.payload.aggregations.failed_api.buckets.get(i).doc_count;
        if(key == 'articlenumber'){
            return value >= 5;
        }
        return value >= 20;
      }
      """
    }

and I get a illegal_argument_exception with reason: Extraneous for loop

{
  "error": {
    "root_cause": [
      {
        "type": "script_exception",
        "reason": "compile error",
        "script_stack": [
          "      for (int i = 0 ; i < ctx. ...",
          "      ^---- HERE"
        ],
        "script": "      for (int i = 0 ; i < ctx.payload.aggregations.failed_api.buckets.size(); i ++) {\n        String key = ctx.payload.aggregations.failed_api.buckets.get(i).key;\n        int value = ctx.payload.aggregations.failed_api.buckets.get(i).doc_count;\n        if(key == 'articlenumber'){\n            return value >= 5;\n        }\n        return value >= 20;\n      }",
        "lang": "painless"
      }
    ],
    "type": "script_exception",
    "reason": "compile error",
    "script_stack": [
      "      for (int i = 0 ; i < ctx. ...",
      "      ^---- HERE"
    ],
    "script": "      for (int i = 0 ; i < ctx.payload.aggregations.failed_api.buckets.size(); i ++) {\n        String key = ctx.payload.aggregations.failed_api.buckets.get(i).key;\n        int value = ctx.payload.aggregations.failed_api.buckets.get(i).doc_count;\n        if(key == 'articlenumber'){\n            return value >= 5;\n        }\n        return value >= 20;\n      }",
    "lang": "painless",
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "Extraneous for loop."
    }
  },
  "status": 500
}

I‘m stucked here for a few days and just can't find a way out,how can I solve this problem?

if you are calling return from a for loop then only the first iteration will be run - which makes the for loop unneeded.

Judging from a very quick view, I think what you are after is only the buckets contain a certain amount of documents, which can be done using the min_doc_count parameter.

If you still want to use painless, you have to loop through all the results and collect them instead of using return.

1 Like

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