Возврат журналов с последней отметкой времени из групп с уникальными идентификаторами

У нас есть группы журналов в нашем Elasticsearch, каждая группа содержит от 1 до 7 журналов с общим уникальным идентификатором (с именем transactionId). Каждый журнал в каждой группе имеет уникальную временную метку (eventTimestamp).

Например:

{
  "transactionId": "id111",
  "eventTimestamp": "1505864112047",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

{
  "transactionId": "id111",
  "eventTimestamp": "1505864112051",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

{
  "transactionId": "id222",
  "eventTimestamp": "1505863719467",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

{
  "transactionId": "id222",
  "eventTimestamp": "1505863719478",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

Мне нужно написать запрос, который возвращает все последние метки времени для всех идентификаторов транзакций в определенном диапазоне дат.

Продолжая мой упрощенный пример, результат запроса должен вернуть следующие журналы:

{
  "transactionId": "id111",
  "eventTimestamp": "1505864112051",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

{
  "transactionId": "id222",
  "eventTimestamp": "1505863719478",
  "otherfieldA": "fieldAvalue",
  "otherfieldB": "fieldBvalue"
}

Любые идеи о том, как построить запрос, который выполняет это?


person udidol    schedule 24.09.2017    source источник


Ответы (1)


Вы можете получить желаемый результат не с помощью самого запроса, а с помощью комбинации агрегация терминов и вложенные агрегация лучших результатов.

Агрегация терминов отвечает за создание сегментов, в которых все элементы с одинаковым термином находятся в одном сегменте. Это то, что может генерировать ваши группы за transactionId. Таким образом, агрегация лучших попаданий представляет собой агрегацию метрик, которую можно настроить для возврата x первых попаданий корзины в соответствии с заданным порядком сортировки. Это позволяет получить событие журнала с наибольшей временной меткой каждого сегмента.

Предполагая сопоставление ваших образцов данных по умолчанию (где строки индексируются как thekey (текст) и thekey.keyword (как неанализируемый текст)) этот запрос:

GET so-logs/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "eventTimestamp.keyword": {
              "gte": 1500000000000,
              "lte": 1507000000000
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "by_transaction_id": {
      "terms": {
        "field": "transactionId.keyword",
        "size": 10
      },
      "aggs": {
        "latest": {
          "top_hits": {
            "size": 1,
            "sort": [
              {
                "eventTimestamp.keyword": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

выдаст следующий вывод:

{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "by_transaction_id": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "id111",
          "doc_count": 2,
          "latest": {
            "hits": {
              "total": 2,
              "max_score": null,
              "hits": [
                {
                  "_index": "so-logs",
                  "_type": "entry",
                  "_id": "AV6z9Yj4QYbhNp_FoXa1",
                  "_score": null,
                  "_source": {
                    "transactionId": "id111",
                    "eventTimestamp": "1505864112051",
                    "otherfieldA": "fieldAvalue",
                    "otherfieldB": "fieldBvalue"
                  },
                  "sort": [
                    "1505864112051"
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "id222",
          "doc_count": 2,
          "latest": {
            "hits": {
              "total": 2,
              "max_score": null,
              "hits": [
                {
                  "_index": "so-logs",
                  "_type": "entry",
                  "_id": "AV6z9ZlOQYbhNp_FoXa4",
                  "_score": null,
                  "_source": {
                    "transactionId": "id222",
                    "eventTimestamp": "1505863719478",
                    "otherfieldA": "fieldAvalue",
                    "otherfieldB": "fieldBvalue"
                  },
                  "sort": [
                    "1505863719478"
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}

где вы можете найти желаемые результаты внутри результатов агрегации by_transaction_id.latest в соответствии с именами агрегации, определенными в запросе.

Имейте в виду, что агрегация терминов имеет ограничение на количество возвращаемых сегментов, и установка этого значения > 10 000, вероятно, не является разумной идеей с точки зрения производительности. Подробнее см. в разделе раздел о size агрегации терминов. Если вы хотите иметь дело с огромным количеством различных идентификаторов транзакций, я бы предложил сделать избыточное хранилище «верхней» записи по идентификатору транзакции.

Кроме того, вам, вероятно, следует переключить поле eventTimestamp на date для повышения производительности и более широкий набор возможностей запроса.

person Andreas Jägle    schedule 24.09.2017