Elasticsearch post_filter агрегатный запрос - PullRequest
1 голос
/ 24 июня 2019

Меня интересуют все API, которые не вернули ни одного ответа 200 (за определенный промежуток времени).

Мне в основном нужно это:

     select url from api_log
      except/minus 
     select url from api_log where status='200'

Перевод на ES, IЯ пытаюсь эквивалентно этому:

  1. Сначала рассчитать агрегаты.
     select url, status, count(*) from api_log
     group by url, status
Исходя из полученных результатов, отфильтруйте все записи, у которых есть дети со статусом: 200

Пример данных ES

{
    "_index": "api_log",
    "_type": "_doc",
    "_id": "1",
    "_version": 1,
    "_score": 1,
    "_source": {
        "in_time": "2019-05-13T17:20:51.108945",
        "out_time": "2019-05-13T17:20:51.145549",
        "duration": 36.6041660308838,
        "status": "200",
        "url": "/api/myFirstAPI"
    }
}
,
{
    "_index": "api_log",
    "_type": "_doc",
    "_id": "2",
    "_version": 1,
    "_score": 1,
    "_source": {
        "in_time": "2019-05-13T17:20:57.915694",
        "out_time": "2019-05-13T17:20:57.941989",
        "duration": 26.2949466705322,
        "status": "403",
        "url": "/api/mySecondAPI"
    }
},
{
    "_index": "api_log",
    "_type": "_doc",
    "_id": "3",
    "_version": 1,
    "_score": 1,
    "_source": {
        "in_time": "2019-05-13T17:22:35.274372",
        "out_time": "2019-05-13T17:22:35.288944",
        "duration": 14.5719051361084,
        "status": "400",
        "url": "/api/myFirstAPI"
    }
}

Для приведенных выше данных Iхотите получить URL-адрес результата как {'/api/mySecondAPI' угр.*

{
  "took" : 880,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "url" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 394668,
      "buckets" : [
        {
          "key" : "/api/myFirstRequest",
          "doc_count" : 1352845,
          "status" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "200",
                "doc_count" : 1187611
              },
              {
                "key" : "302",
                "doc_count" : 139932
              },
              {
                "key" : "401",
                "doc_count" : 22615
              },
              {
                "key" : "500",
                "doc_count" : 2250
              },
              {
                "key" : "403",
                "doc_count" : 437
              }
            ]
          }
        },
...
...
...

Сверху мне нужно отфильтровать все сегменты (URL), которые НЕ имеют вложенных сегментов со статусом: «200»

Я зашел так далеко.Выглядит довольно близко, но очень далеко ... Не могу понять, что должно быть в поле типа.

Запрос с фильтром

POST /api_log/_search
{
  "size": 0,
  "aggs": {
    "page_name": {
      "terms": {
        "field": "url.keyword"
      },
      "aggregations": {
        "status": {
          "terms": {
            "field": "status.keyword"
          }
        }
      }
    }
  },
   "post_filter": {
      "bool": {
        "must_not": [
            {
                "has_child" : {
                    "type" : "?????",
                    "query" : {
                        "term" : {"status" : "200"}
                    }
                }
            }
        ]
      }
    }
}

Пример ввода (из журнала apache):

t1 /api/FirstAPI 200  <-- Eliminate First API completely
t2 /api/FirstAPI 400
t3 /api/FirstAPI 403
t4 /api/SecondAPI 403
t5 /api/SecondAPI 400
t6 /api/ThirdAPI 500
t7 /api/ThirdAPI 500
t8 /api/SecondAPI 200   <---Eliminate Second API completely
t9 /api/ThirdAPI 500
t10 /api/ThirdAPI 403

Приведенный выше ввод я хочу только на страницах, которые НИКОГДА не давали 200 ответов во временном интервале t1-t10.

Ожидаемый результат

Итак, выходные данные должны быть просто / api / ThirdAPI

Если я сначала отфильтрую 200, а затем применю Agg, я получу все три API.Это не то, что я хочу.

1 Ответ

0 голосов
/ 25 июня 2019

Если я правильно понимаю, вы просто хотите исключить 200 из агрегации. Я не вижу смысла использовать post_filter здесь. Вы можете использовать условия агрегации .

Исключить или отфильтровать значение состояния в агрегатах . Это подсчитает все ответы 200 и добавит в поле doc_count, но исключит сегменты в ответе агрегации и не покажет 200

POST /api_log/_search
{
  "size": 0,
  "aggs": {
    "url": {
      "terms": {
        "field": "url.keyword"
      },
      "aggregations": {
        "status": {
          "terms": {
            "field": "status.keyword",
            "exclude": "200"
          }
        }
      }
    }
  }
}

Альтернатива:

Исходя из вашего ввода, похоже, что вы хотите 200 как часть набора результатов (поскольку вы используете post_filter), но если нет, то есть другой способ, если это не так. Агрегирование производится по ответу на запрос; поэтому, если вы используете bool query для исключения 200 из набора результатов, у вас не будет никаких сегментов со статусом 200.

POST /api_log/_search
    {
      "size": 0,
      "query": {
        "bool": {
          "must_not": [
            {
              "terms": {
                "status": [
                  "200"
                ]
              }
            }
          ]
        }
      }, 
      "aggs": {
        "url": {
          "terms": {
            "field": "url.keyword"
          },
          "aggregations": {
            "status": {
              "terms": {
                "field": "status.keyword"
              }
            }
          }
        }
      }
    } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...