Как получить получить ранжирование значениея поля по уникальным записям


(Yuri Mosiychuk) #1

Индекс содержит записи о прыжках спортсменов. Попыток у одного спортсмена может быть множество.

Структура документа:

{
   'event_at' : '2015-01-01T12:12:10', - дата прыжка
   'user_id' : 2142, - id спортсмена
   'distance' : 4 - результат
}

Необходимо получить выборку:

{
  'distance_range' : {
    '*-5' : 12, - кол-во уникальных спортсменов у которых максимальный прыжок от 0 до 5. 
    '6-10' : 14, - кол-во уникальных спортсменов у которых максимальный прыжок от 6 до 10.
    '11-15' : 5 - кол-во уникальных спортсменов у которых максимальный прыжок от 10 до 15.
  }
}

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

На SQL это могло бы выглядеть так:

SELECT `distace_range`, count(*) FROM (
  SELECT 
    `user_id`,
    IF(MAX(`distace`) <=5, 
      '*-5', 
      IF(MAX(`distace`) >= 6 AND MAX(`distace`) >= 10,
        '6-10',
        '11-15'        
      ) 
    ) `distace_range`
  FROM `events`
  GROUP BY `user_id`
) t
GROUP BY `distace_range;

(Igor Motov) #2

К сожалению, в текущей версии elasticsearch это не возможно без создания временного индекса, который бы содержал максимальный результат для каждого спортсмена.


(Yuri Mosiychuk) #3

Если выбирать так

      'aggregations' => [
            'distance_range' => [
              'terms' => [
                'field' => 'doc.user_id',

              ],
              'aggregations' => [
                'max_distance' => [
                  'max' => [
                    'field' => 'doc.distance'
                  ]
                ]
              ]
            ]
          ]

то не хватает Pipeline агрегатора по range, я правильно понимаю?

Что мне не нравится в создании отдельного индекса, то что его надо поддерживать в актуальном состоянии, например периодически пересчитывать .

Есть ли варианты со скриптами или плагинами?


(Igor Motov) #4

Да, нужен Pipeline агрегатор либо по range, либо по term, но ни того, ни другого пока нет. Это можно, конечно, реализовать скриптами в Scripted Metric Aggregation, но мне кажется, будет гораздо проще и быстрее выбрать, как вы показали, и просуммировать результат на клиенте.


(system) #5