Выбор максимальных значений в пилообразном паттерне (локальный максимум) - PullRequest
0 голосов
/ 13 сентября 2018

У меня в postgres есть таблица ts, которая выглядит следующим образом:

dev -- numeric device id
ts -- Unix epoch timestamp
key -- string (only interested in records where key is 'u')
val -- int representing uptime in ms

Я регистрирую время безотказной работы процесса в этой таблице, и я делаю это каждые 30 секунд или около того.В результате получается таблица с постоянно увеличивающимся значением val, которое периодически сбрасывается в 0 при перезапуске процесса, создавая пилообразный шаблон.Обратите внимание, что фактическое зарегистрированное значение может не быть 0, так как регистрация может не произойти сразу после перезапуска.

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

Пример:

dev ts      key  val
1   100000  'u'  50      -- boring
1   130100  'u'  30050   -- delete this
1   160100  'u'  60050   -- >> keep this one
1   190200  'u'  100     -- this record dies
1   220200  'u'  30100   -- >> keep this one too
1   250200  'u'  300    

Я хочу, чтобы запрос выбрал все записи, кромепомеченные выше, которые неинтересны и могут быть удалены.

Отбор будет периодически выполняться в пакетном режиме.

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

Если вы просто хотите сохранить локальные максимумы, вы можете использовать lead() и lag():

select t.*
from (select t.*,
             lead(val) over (partition by dev order by ts) as next_val,
             lag(val) over (partition by dev order by ts) as prev_val
      from t
      where key = 'u'
     ) t
where val > prev_val and val > next_val;
0 голосов
/ 13 сентября 2018

Потому что это весело: использовала новую PostgreSQL 11 функцию "GROUPS в оконных функциях" для решения проблемы с привязанными локальными максимумами.

Проблема:

dev key ts      val
1   u   100000  50
1   u   130100  30050
1   u   160100  60050 -- really single local maximum
1   u   190200  100
1   u   220200  30100 -- local maximum together with next value
1   u   250200  30100 
1   u   300000  300
1   u   500000  100
1   u   550000  1000  -- a (tied) local maximum if only 1 before and 1 after is used, which is wrong
1   u   600000  1000
1   u   650000  2000  -- real local maximum together with 2 next rows
1   u   700000  2000
1   u   720000  2000
1   u   750000  300

Новая функция PostgreSQL 11:

В блоге JOOQ объясняется эта функция

Документация Postgres 11

demo: db <> fiddle

SELECT 
    dev, key, ts, val 
FROM (
     SELECT
        *, 
        -- B:
        max(val) over (order by sum, val GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as local_max 
     FROM (
        SELECT -- A
            *, 
            sum(is_diff) over (order by ts) 
        FROM (
            SELECT 
                *,
                CASE WHEN val = lag(val) over (order by ts) THEN 0 ELSE 1 END as is_diff
            FROM test t
            WHERE key = 'u'
        )s
    )s
)s 
WHERE val = local_max

A: Это всего лишь подготовительная часть.Оконным функциям нужен определенный порядок.Если вы сделаете PARTITION BY val, стол будет заказан сначала val.Но в этом примере вы хотели бы удерживать ордер на ts.И тогда вы хотите, чтобы оконная функция магия для val.Таким образом, в этой части я вычисляю номер группы для тех же значений в прямых следующих строках, удерживая порядок на ts.( Может быть, это можно сделать лучше? )

Результат таков:

dev key ts      val     is_diff  sum
1   u   100000  50      1        1
1   u   130100  30050   1        2
1   u   160100  60050   1        3
1   u   190200  100     1        4
1   u   220200  30100   1        5     \ same group
1   u   250200  30100   0        5     /
1   u   300000  300     1        6
1   u   500000  100     1        7
1   u   550000  1000    1        8     \ same group
1   u   600000  1000    0        8     /
1   u   650000  2000    1        9     \
1   u   700000  2000    0        9     | same group
1   u   720000  2000    0        9     /
1   u   750000  300     1        10

B: Это новая функция Postgres 11.Теперь можно проверить значения для групп.В прошлом можно было искать фиксированный номер строки.Но теперь вы можете проверить значение следующей группы.Говоря: Если у вас есть 3 три строки с одинаковым значением, вы можете проверить следующее или предыдущее значение, которое не связано независимо от того, сколько строк вы связываете.Это решило проблему очень круто:

Для примера с двумя значениями 1000: Теперь мы можем проверить: следующее значение больше текущего?Нет, это то же самое.Так что это та же группа.Итак, давайте посмотрим на следующий ряд.Это 2000, и это больше.Таким образом, текущая строка не может быть локальным максимумом.

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

0 голосов
/ 13 сентября 2018

Вместо этого, почему бы не обновить саму соответствующую запись?И вставлять новую запись только после перезапуска процесса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...