# Watcherで各bucketのdoc\_countを集計したい

**URL:** <https://discuss.elastic.co/t/watcher-bucket-doc-count/305789>\
**Category:** 日本語による質問・議論はこちら\
**Tags:** painless\
**Created:** [May 27, 2022, 10:06am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789 "2022-05-27T10:06:31Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 27, 2022, 10:06am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/1 "2022-05-27T10:06:31Z")

</div>

お世話になります。  
異なるkeyの各bucketの件数を集計して、その件数に応じてアラートを発報したいのですが実装方法で悩んでおり、お知恵をお借りしたいです。

wacherで以下のようなaggsを作成して、stsCodeの値ごとにbucketを作成しています。

```auto
"aggs": {
  "sts_success_count": {
    "terms": {
      "field": "info.stsCode",
      "include": [
        "00000",
        "99998",
        "99999"
      ]
    }
  }
}

```

この結果は以下のようにレスポンスが返ってきています。

```auto
"buckets": [
  {
    "doc_count": 5966,
    "key": "00000"
  },
  {
    "doc_count": 8,
    "key": "99999"
  }
]

```

includeに記載しているすべてのstsCodeに対し結果が必ずしも返るわけではありません。  
これらのstsCodeが示すのはいずれも正常終了のステータスなので、正常終了のステータスが9割を超えた場合にアラートが出る仕組みを作りたい、というのが今回の目標です。

試しに以下のように実装したのですが、sts\_success\_countに直接対応するdoc\_count という要素はないのでエラーとなっています。  
この箇所を、正常終了のステータスを示すstsCodeの合計件数に置き換える必要があると考えていますが、実装方法がわかりません。

```auto
"condition": {
  "script": {
    "source": "if ( ctx.payload.aggregations.sts_success_count.doc_count / ctx.payload.hits.total < params.threshold ) { return true; } return false;",
    "lang": "painless",
    "params": {
      "threshold": 0.9
    }
  }
},
"actions": {

```

よいやり方があれば教えていただけますと幸いです。

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 28, 2022, 11:03am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/2 "2022-05-28T11:03:49Z")

</div>

はじめまして。

`ctx.payload.aggregations.sts_success_count.doc_count`の部分がエラーの原因のようですね。できれば、エラーコード自体も貼っていただけると良いかと思います。

（inputのterms aggregationに`min_doc_count: 0`を加えて全て返るようにした上で、）[arrayの中のインデックスを指定](https://www.elastic.co/guide/en/elasticsearch/reference/8.2/input-search.html#_accessing_the_search_results)して

```auto
ctx.payload.aggregations.sts_success_count.buckets.0.doc_count + ctx.payload.aggregations.sts_success_count.buckets.1.doc_count + ctx.payload.aggregations.sts_success_count.buckets.2.doc_count

```

とするか、

最初からterms aggregationではなく、terms queryを使った[filter aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html)などを用いて、inputの段階で条件を満たす文書数を合計してしまう方法もありそうです。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 1:24am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/3 "2022-05-30T01:24:42Z")

</div>

アドバイスいただきありがとうございます。  
アドバイスいただいた内容のうち、インデックスを指定して加算していく方法を試そうとしました。  
しかしながら、こちらもエラーが出てうまくいかず、原因がわからなかったのでご確認をいただけますでしょうか？

まず、aggsは以下のように記述しています。

```auto
"aggs": {
  "sts_success_count": {
    "terms": {
      "field": "info.stsCode",
      "include": [
        "00000",
        "99998",
        "99999"
      ]
    },
    "min_doc_count": 0
  }
}

```

これに対して以下のようなエラーが返ってきています。

```auto
"result": {
  "execution_time": "2022-05-30T01:21:03.647Z",
  "execution_duration": 0,
  "input": {
    "type": "search",
    "status": "failure",
    "error": {
      "root_cause": [
        {
          "type": "parsing_exception",
          "reason": "Expected [START_OBJECT] under [min_doc_count], but got a [VALUE_NUMBER] in [sts_success_count]",
          "line": 1,
          "col": 298
        }
      ],

```

何か記述に誤りがありますでしょうか？  
ご教示いただけますと幸いです。

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 30, 2022, 2:08am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/4 "2022-05-30T02:08:29Z")

</div>

[min\_doc\_countはterms aggregationのパラメーター](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_minimum_document_count_4)なので、

```auto
"aggs": {
  "sts_success_count": {
    "terms": {
      "field": "info.stsCode",
      "include": [
        "00000",
        "99998",
        "99999"
      ],
      "min_doc_count": 0
    }
  }
}

```

です。jsonのネスト位置って見づらいですよね…。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 3:14am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/5 "2022-05-30T03:14:51Z")

</div>

ありがとうございます。  
パラメータの位置を勘違いしてしまっておりました。この通りに位置を修正し、エラーは解消できました。  
通知条件自体はうまくいったので、通知設定を行い、以下の通りにメール文面を組み立てようとしました。

```auto
"actions": {
    "send_email": {
      "email": {
        "profile": "standard",
        "to": [
          "xxx@xxx.xxx"
        ],
        "cc": [
        ],
        "subject": "title",
        "body": {
          "html": "時間：{{ctx.payload.time_triggered}}<br />直近 1 時間の総取引数：{{ctx.payload.ctx.payload.hits.total}}<br />直近 1 時間の正常取引数：{{ctx.payload.aggregations.sts_success_count.buckets.0.doc_count}} + {{ctx.payload.aggregations.sts_success_count.buckets.1.doc_count}} + {{ctx.payload.aggregations.sts_success_count.buckets.2.doc_count}}<br />"

```

しかしながらこの記述では、エラーは発生していないのですが、送信された文面に以下の問題がありました。

1. 「時間」項目が空欄で送信されてしまう
2. 「直近 1 時間の総取引数」項目が空欄で送信されてしまう
3. 「直近 1 時間の正常取引数」項目が計算できずそのまま出力されてしまう

これらの問題を解消して想定通りの値をメール文面として送信する方法はありますでしょうか？

よろしくお願いします。

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 30, 2022, 3:28am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/6 "2022-05-30T03:28:11Z")

</div>

time\_triggeredの指定が違う場所を指しているように思います。[Watch execution context](https://www.elastic.co/guide/en/elasticsearch/reference/current/how-watcher-works.html#watch-execution-context)を確認してみてください。

なお、前の話に戻りますが、filter aggregationを使うとこのようなクエリになりそうです。この方がすっきりしますね。

```auto
GET test_filter_agg/_search
{
  "size":0,
  "aggs": {
    "RESULT": {
      "filters": {
        "filters": {
          "SUCCESS": {"terms": {
            "info.stsCode": [
              "00000",
              "99998",
              "99999"
            ]
          }},
          "ALL":{"match_all":{}}
        }
      }
    }
  }
}

```

```auto
{
  "aggregations" : {
    "RESULT" : {
      "buckets" : {
        "ALL" : {
          "doc_count" : 4
        },
        "SUCCESS" : {
          "doc_count" : 3
        }
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 30, 2022, 3:32am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/7 "2022-05-30T03:32:43Z")

</div>

3.については"html"の内容はあくまでstringで、Mustache内だけが変換されるので、当然計算されないですね。Mustache内で加算するようなスクリプトが書けるかは分かりません。。前のリプライに入れたfilters aggregationを用いて前もって計算する方が妥当に思います。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 4:18am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/8 "2022-05-30T04:18:04Z")

</div>

ありがとうございます。  
文面としてはstringで出すことになるとのこと、理解しました。  
他に出したかったエラーのパターンも含めて以下のように書き換えて、期待通りに動作するようになりました。

```auto
"aggs": {
  "RESULT": {
    "filters": {
      "filters": {
        "SUCCESS": {
          "terms": {
            "info.stsCode": [
              "00000",
              "99998",
              "99999"
            ]
          }
        },
        "ERR_1": {
          "terms": {
            "info.stsCode": [
              "00002"
            ]
          }
        },
        "ERR_2": {
          "terms": {
            "info.stsCode": [
              "50120"
            ]
          }
        },
        "ALL":{
          "match_all":{}
        }
      }
    }
  }
}

```

文面は以下の通りにしました。

```auto
 "html": "時間：{{ctx.execution_time}}<br />直近 1 時間の総取引数：{{ctx.payload.aggregations.RESULT.buckets.ALL.doc_count}}<br />直近 1 時間の正常取引数：{{ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count}}<br />直近 1 時間のエラー1件数：{{ctx.payload.aggregations.RESULT.buckets.ERR_1.doc_count}}<br />直近 1 時間のエラー2件数：{{ctx.payload.aggregations.RESULT.buckets.ERR_2.doc_count}}<br />"

```

もう一点、追加で、「その他エラー」として、上記termsで絞っているstsCode以外のコードが出た場合の件数も出力したいと考えています。

算術演算子が文中に利用できないということなので、filtersの中身にstsCode以外という条件で新規に追加してやる必要があるかと思うのですが、どのような記述方法ができるでしょうか？  
SQLでいうところのNOT INのようなパターンの記法が見つからず、ご教授いただきたいです。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 8:02am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/9 "2022-05-30T08:02:43Z")

</div>

自己解決しました。

```auto
"OTHER_ERR": {
  "bool": {
    "must_not": {
      "terms": {
        "info.stsCode": [
          "00000",
          "99998",
          "99999",
          "00002",
          "50120"
        ]
      }
    }
  }
},

```

課題の解決に向け様々なアドバイスを頂戴し、誠にありがとうございました。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 8:47am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/10 "2022-05-30T08:47:31Z")

</div>

たびたび申し訳ございません。  
どうやら実装に不足があったようなので改めて確認をさせていただけますでしょうか。

本件で作成したwatcherについて実際に稼働させてみたところ、以下のconditionを満たしていないにも関わらずメール通知が飛ぶようになってしまいました。

本来やりたかった内容としては、  
SUCCESSの件数 / ALLの件数 = SUCCESSの割合 を求め、  
SUCCESSの割合が閾値（threshold）未満となっている場合にアラートを飛ばす、というものです。

```auto
"condition": {
  "script": {
    "source": "if ( ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count / ctx.payload.aggregations.RESULT.buckets.ALL.doc_count < params.threshold ) { return true; } return false;",
    "lang": "painless",
    "params": {
      "threshold": 0.85
    }
  }
},

```

エラーは発生しておらず、resultは以下の通りでした。

```auto
"result": {
  "execution_time": "2022-05-30T08:18:11.145Z",
  "execution_duration": 72,
  "input": {
    "type": "search",
    "status": "success",
    "payload": {
      "_shards": {
        "total": 15,
        "failed": 0,
        "successful": 15,
        "skipped": 0
      },
      "hits": {
        "hits": [],
        "total": 4801,
        "max_score": null
      },
      "took": 5,
      "timed_out": false,
      "aggregations": {
        "RESULT": {
          "buckets": {
            "ALL": {
              "doc_count": 4801
            },
            "SUCCESS": {
              "doc_count": 4379
            },
            "ERR_1": {
              "doc_count": 0
            },
            "ERR_2": {
              "doc_count": 177
            },
            "OTHER_ERR": {
              "doc_count": 245
            }
          }
        }
      }
    },

```

上記のresultによればSUCCESSの割合は  
4379 / 4801 = 0.912...  
となるので発火しない想定でしたが、通知が飛んでしまっています。  
閾値を変更しながら通知を確認してみたのですが、conditionの条件が閾値によらず発火する状態になってしまっているようです。  
scriptの内部ではdoc\_countの値を正しく扱えていないのでしょうか？  
それともif文の書き方に問題があるのでしょうか？

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 30, 2022, 9:41am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/11 "2022-05-30T09:41:09Z")

</div>

resultの中にconditionなかったですか？  
script自体はあっていそうに見えますが…。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 9:57am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/12 "2022-05-30T09:57:11Z")

</div>

resultのconditionは以下の内容しか載っていませんでした。

```auto
    "condition": {
      "type": "script",
      "status": "success",
      "met": true
    },

```

整数型で丸められてしまったのかと思い、両辺それぞれ100倍して計算するように試してみましたが、それでも結果は変わらず、trueが返ってしまっています。  
試したのは以下のようなscriptです。

```auto
  "condition": {
    "script": {
      "source": "if ( ( ( ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count * 100 ) / ( ctx.payload.aggregations.RESULT.buckets.ALL.doc_count * 100 ) ) * 100 < 85 ) { return true; } return false;",
      "lang": "painless"
    }
  },

```

これでも85%以上の割合でも通知が飛んでしまっています。

たとえばconditionでどのような計算が行われているかデバッグできればより掘り下げた調査できるかとも思うのですが、何かやり方はございますでしょうか？

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [May 30, 2022, 11:12am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/13 "2022-05-30T11:12:45Z")

</div>

改めて確認したところ、以下の2つのconditionがtrueを返していました。

```auto
  "condition": {
    "script": {
      "source": "ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count * ctx.payload.aggregations.RESULT.buckets.ALL.doc_count == 0",
      "lang": "painless"
    }
  },

```

```auto
"condition": {
  "script": {
    "source": "ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count / ctx.payload.aggregations.RESULT.buckets.ALL.doc_count == 0",
    "lang": "painless"
  }
},

```

つまり少なくとも ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc\_count が0を返している、という結果だと思います。  
しかしながら、以下の結果を確認するとこちらはそれぞれfalseなので、上記の内容と一致しません。

```auto
"condition": {
  "script": {
    "source": "ctx.payload.aggregations.RESULT.buckets.ALL.doc_count == 0",
    "lang": "painless"
  }
},

```

```auto
"condition": {
  "script": {
    "source": "ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count == 0",
    "lang": "painless"
  }
},

```

算術演算子を用いた場合のみ条件がおかしくなっているように見受けられます。  
こちらの回避方法をご存知でしたらご教示いただきたいです。

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [May 31, 2022, 12:46pm UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/14 "2022-05-31T12:46:41Z")

</div>

整数型で丸められたというのはありそうですね。

その場合は、

```auto
if ( ( ( ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count * 100 ) / ( ctx.payload.aggregations.RESULT.buckets.ALL.doc_count * 100 ) ) * 100 < 85 )

```

ではなく、

```auto
if ( ( ctx.payload.aggregations.RESULT.buckets.SUCCESS.doc_count * 100 ) / ctx.payload.aggregations.RESULT.buckets.ALL.doc_count < 85 )

```

とすべきかと思います。分母分子両方100倍してしまうと結局丸まってしまいますので。

ただ、それでも`SUCCESS.doc_count*ALL.doc_count==0`が`true`の部分は説明がつきません。私の手に余る気がするので、解決しない場合は、また新たにスレッドを立てて聞いていただいた方が良いかもしれません。

---

<div class="post-metadata">

**Author:** ![NikaidoKota](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/nikaidokota/32/106257_2.png) [@NikaidoKota](https://discuss.elastic.co/u/NikaidoKota)\
**Post date:** [June 2, 2022, 12:03am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/15 "2022-06-02T00:03:53Z")

</div>

ありがとうございます。  
ひとまず当初の目的は果たしておりますので、いったんこのスレッドはクローズとして、新たにスレッドを立ち上げさせていただこうと思います。

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [June 30, 2022, 12:04am UTC](https://discuss.elastic.co/t/watcher-bucket-doc-count/305789/16 "2022-06-30T00:04:16Z")

</div>

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