Добавление дополнительных полей в агрегацию терминов ElasticSearch

Индексированные документы выглядят следующим образом:

{
  id: 1, 
  title: 'Blah',
  ...
  platform: {id: 84, url: 'http://facebook.com', title: 'Facebook'}
  ...
}

То, что я хочу, это подсчет и вывод статистики по платформе. Для подсчета я могу использовать агрегирование терминов с platform.id как поле для подсчета:

aggs: {
  platforms: {
    terms: {field: 'platform.id'}
  }
}

Таким образом, я получаю статистику как несколько ведер, выглядящих как {key: 8, doc_count: 162511}, как и ожидалось.

Теперь, могу ли я как-то добавить к этим ковшим также platform.name и platform.url (для отличного вывода статистики)? Самое лучшее, что я придумал, выглядит так:

aggs: {
  platforms: {
    terms: {field: 'platform.id'},
    aggs: {
      name: {terms: {field: 'platform.name'}},
      url: {terms: {field: 'platform.url'}}
    }
  }
}

На самом деле, работает и возвращает довольно сложную структуру в каждом ковше:

{key: 7,
  doc_count: 528568,
  url:
   {doc_count_error_upper_bound: 0,
    sum_other_doc_count: 0,
    buckets: [{key: "http://facebook.com", doc_count: 528568}]},
  name:
   {doc_count_error_upper_bound: 0,
    sum_other_doc_count: 0,
    buckets: [{key: "Facebook", doc_count: 528568}]}},

Конечно, имя и URL-адрес платформы можно извлечь из этой структуры (например, bucket.url.buckets.first.key), но есть ли более простой и простой способ выполнить задачу?

Ответы

Ответ 1

Кажется, лучший способ показать намерения - это top hits aggregation: "из каждой агрегированной группы выберите только один документ", а затем извлеките из нее платформу:

aggs: {
  platforms: {
    terms: {field: 'platform.id'},
    aggs: {
      platform: {top_hits: {size: 1, _source: {include: ['platform']}}}
  }
}

Таким образом, каждый из них будет выглядеть следующим образом:

{"key": 7,
  "doc_count": 529939,
  "platform": {
    "hits": {
      "hits": [{
       "_source": {
        "platform": 
          {"id": 7, "name": "Facebook", "url": "http://facebook.com"}
        }
      }]
    }
  },
}

Какая-то слишком изощренная (как обычно, с ES), но чистая: bucket.platform.hits.hits.first._source.platform

Ответ 2

Если вам не обязательно нужно получить значение platform.id, вы можете уйти с одной агрегацией, используя script, который объединяет два поля name и url:

aggs: {
  platforms: {
    terms: {script: 'doc["platform.name"].value + "," + doc["platform.url"].value'}
  }
}