Агрегации и фильтры в Elastic — найдите последние хиты и отфильтруйте их потом

Я пытаюсь работать с Elastic (5.6) и найти способ получить лучшие документы по некоторой категории.

У меня есть индекс со следующими типами документов:

{
      "@timestamp": "2018-03-22T00:31:00.004+01:00",
      "statusInfo": {
        "status": "OFFLINE",
        "timestamp": 1521675034892
      },
      "name": "myServiceName",
      "id": "xxxx",
      "type": "Http",
      "key": "key1",
      "httpStatusCode": 200
    }
  }

Что я пытаюсь сделать с ними, так это получить последний документ (на основе @timestamp) для name (мои категории), посмотреть, является ли его статусInfo.status OFFLINE или UP, и получить эти результаты в части ответов, поэтому я могу поместить его на панель инструментов Kibana count или куда-нибудь еще (инструмент на основе REST, который я не контролирую и не могу модифицировать самостоятельно). По сути, я хочу знать, сколько моих сервисов (name) отключено (statusInfo.status) в их последнем обновлении (@timestamp) для целей мониторинга. Я застрял в части "Получить сколько моих услуг".

Мой запрос до сих пор:

GET actuator/_search
{
  "size": 0,
  "aggs": {
    "name_agg": {
      "terms": {
        "field": "name.raw",
        "size": 1000
      },
      "aggs": {
        "last_document": {
          "top_hits": {
            "_source": ["@timestamp", "name", "statusInfo.status"], 
            "size": 1,
            "sort": [
              {
                "@timestamp": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  },
  "post_filter": {
    "bool": {
      "must_not": {
        "term": {
          "statusInfo.status.raw": "UP"
        }
      }
    }
  }
}

Это обеспечивает следующий ответ:

{
  "all_the_meta":{...},
  "hits": {
    "total": 1234,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "name_agg": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "myCategory1",
          "doc_count": 225,
          "last_document": {
            "hits": {
              "total": 225,
              "max_score": null,
              "hits": [
                {
                  "_index": "myIndex",
                  "_type": "Http",
                  "_id": "dummy id",
                  "_score": null,
                  "_source": {
                    "@timestamp": "2018-04-06T00:06:00.005+02:00",
                    "statusInfo": {
                      "status": "UP"
                    },
                    "name": "myCategory1"
                  },
                  "sort": [
                    1522965960005
                  ]
                }
              ]
            }
          }
        },
        {other_buckets...}
      ]
    }
  }
}

Удаление размера приводит к тому, что результат содержит ВСЕ документы, что мне не нужно, мне нужно только содержимое каждой корзины (каждая содержит одно ведро). Удаление пост-фильтра, похоже, мало что дает.

Я думаю, что это было бы возможно в ORACLE SQL с предложением PARTITION BY OVER, за которым следует условие.

Кто-нибудь знает, как этого можно добиться?


person Matthieu Borgraeve    schedule 05.04.2018    source источник
comment
Какая версия Elasticsearch?   -  person sramalingam24    schedule 06.04.2018
comment
5.6, мой плохой. Отредактировал мой пост.   -  person Matthieu Borgraeve    schedule 06.04.2018


Ответы (1)


Если я вас правильно понял, вы ищете последний документ, который имеет статус OFFLINE в каждой группе (сгруппирован по имени)?. В этом случае вы можете попробовать запрос ниже, и количество элементов в ведре должно дать вам «сколько не работает» (для увеличения вы должны изменить термин в фильтре)

ПРИМЕЧАНИЕ. Это сделано в последней версии, поэтому вместо необработанных данных используется поле ключевого слова.

POST /index/_search
{
    "size": 0,
  "query":{
    "bool":{
        "filter":{
            "term": {"statusInfo.status.keyword": "OFFLINE"}
        }
    }
  },
  "aggs":{
    "services_agg":{
        "terms":{
            "field": "name.keyword"
        },
        "aggs":{
            "latest_doc":{
                "top_hits": {
                    "sort": [
                        {
                            "@timestamp":{
                                "order": "desc"
                            }
                        }
                        ],
                        "size": 1,
                    "_source": ["@timestamp", "name", "statusInfo.status"]
                }
            }
        }
    }
  }
}
person sramalingam24    schedule 06.04.2018
comment
Привет, не совсем так, это получит последний статус OFFLINE, верно? Это отфильтровало бы статус UP, который я мог бы получить впоследствии? Мне нужны последние статусы (в качестве первого фильтра) UP или OFFLINE, затем мне нужно отфильтровать не OFFLINE, чтобы получить текущие OFFLINE услуги, что в настоящее время означает последний статус, который они отправили. - person Matthieu Borgraeve; 06.04.2018
comment
Да, это правильно, поэтому вы хотите сначала агрегировать, а затем фильтровать, теперь я вижу это - person sramalingam24; 06.04.2018