Сборка мозаики
От: pva  
Дата: 03.11.23 12:24
Оценка:
Привет,

как бы вы решали такую задачу?
На сервер льется телеметрия в формате "индекс"-"тип"-"значение". Она приходит пакетами. Записи внутри пакета и сами пакеты не упорядочены по индексу.
Задача: максимально оперативно выдавать упорядоченные по индексу непрерывные куски заданной длительности. Кусок должен содержать все "типы".

Например при заданной длительности 2:
Входящие

"1"-"1"-"Б" => []
"0"-"1"-"A" => []
"0"-"2"-"A" => []
"1"-"2"-"В" => [ААБВ]
...

newbie
Re: Сборка мозаики
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.11.23 13:03
Оценка:
Здравствуйте, pva, Вы писали:

pva>как бы вы решали такую задачу?


Я бы сделал скользящее reordering window с фиксированным количеством слотов. Каждый приходящий пакет сначала вставлял бы на свое место, а потом "выдвигал" бы из окна столько записей, сколько собраных накопилось. Ну и сдвигал бы границы окна.

Ну и если очередной новый пакет в окно не помещается, потому, что старые недособраные записи не дают окну сдвинуться, значит, сдвигаем принудительно, выбрасывая старые недособраные пакеты (это в любом случае надо делать, иначе пропавший куда-то случайно фаргмент записи заблокирует эту конструкцию навечно).
Re: Сборка мозаики
От: BlackEric http://black-eric.lj.ru
Дата: 03.11.23 13:51
Оценка:
Здравствуйте, pva, Вы писали:

pva>Привет,


pva>как бы вы решали такую задачу?

pva>На сервер льется телеметрия в формате "индекс"-"тип"-"значение". Она приходит пакетами. Записи внутри пакета и сами пакеты не упорядочены по индексу.
pva>Задача: максимально оперативно выдавать упорядоченные по индексу непрерывные куски заданной длительности. Кусок должен содержать все "типы".

pva>Например при заданной длительности 2:

pva>Входящие
pva>

"1"-"1"-"Б" => []
pva>"0"-"1"-"A" => []
pva>"0"-"2"-"A" => []
pva>"1"-"2"-"В" => [ААБВ]
pva>...


Возможно я не понял задачу, но я бы всё это сложил в ClickHouse, построил индексы и забирал упорядоченные данные из него SQL запросом.
https://github.com/BlackEric001
Re[2]: Сборка мозаики
От: pva  
Дата: 03.11.23 13:56
Оценка:
Здравствуйте, Pzz, Вы писали:

не, чуток не то. Исторические данные могут прийти и несколько дней спустя. Свежие данные имеют приоритет, но при этом обрабатывать исторические данные тоже нужно.
Пока я остановился на таком варианте:
— сортирую и сливаю в непрерывные сегменты пришедший пакет
— затем новые сегменты вливаю в кеш, который содержит разреженные данные и заодно оставляю себе те сегменты, которые после слияния длиннее лимита
— затем пробегаюсь по остальным каналам в кеше, проверяя содержат ли они те же данные что и отобранные сегменты
— при совпадении — выдаю обнаруженные куски, заодно удаляя их из кеша

недостатком такого метода является фрагментация кеша. Например, для примера выше, приход индексов 4 и 5 (с пропуском 3) сгенерировал бы сегмент "45" и пришедшая позже "3" зависла бы в воздухе навсегда.
В качестве альтернативы можно установить дискретный шаг, размером с лимит. Но тогда, например, ".4" + "5." останутся "выпавшими".
newbie
Re[2]: Сборка мозаики
От: pva  
Дата: 03.11.23 14:01
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Возможно я не понял задачу, но я бы всё это сложил в ClickHouse, построил индексы и забирал упорядоченные данные из него SQL запросом.

Боюсь, что это чересчур энтерпрайзно.
Во-первых, это решает только проблему сортировки и слияния, но никоим образом не решает вопросов определения "готовности" данных (наличие непрерывного сегмента данных во всех "типах").
Во-вторых, я уже проходил подобное пару раз ))) оверхед при использовании СУБД настолько огромный, что ни в сказке сказать, ни пером описать.
newbie
Re[3]: Сборка мозаики
От: BlackEric http://black-eric.lj.ru
Дата: 03.11.23 14:08
Оценка:
Здравствуйте, pva, Вы писали:

pva>Здравствуйте, BlackEric, Вы писали:


BE>>Возможно я не понял задачу, но я бы всё это сложил в ClickHouse, построил индексы и забирал упорядоченные данные из него SQL запросом.

pva>Боюсь, что это чересчур энтерпрайзно.
pva>Во-первых, это решает только проблему сортировки и слияния, но никоим образом не решает вопросов определения "готовности" данных (наличие непрерывного сегмента данных во всех "типах").
pva>Во-вторых, я уже проходил подобное пару раз ))) оверхед при использовании СУБД настолько огромный, что ни в сказке сказать, ни пером описать.

Если у вас данные идут с задержкой в несколько дней, то что вы используете в качестве кеша?
Наличие непрерывности тоже в принципе можно через sql проверять.
https://github.com/BlackEric001
Re: Сборка мозаики
От: Буравчик Россия  
Дата: 03.11.23 14:15
Оценка: +1
Здравствуйте, pva, Вы писали:

pva>Например при заданной длительности 2:

pva>Входящие
pva>

"1"-"1"-"Б" => []
pva>"0"-"1"-"A" => []
pva>"0"-"2"-"A" => []
pva>"1"-"2"-"В" => [ААБВ]
pva>...


1. Сохранять поступающие элементы в dict/hash
2. При сохранении поддерживать количество для каждого индекса/типа (+1 для пришедшего элемента)
3. Как только наберется нужно количество (пришло каждого по два), доставать серию из п.1

Сложность — амортизированное O(1)
Best regards, Буравчик
Отредактировано 03.11.2023 14:16 Буравчик . Предыдущая версия .
Re[4]: Сборка мозаики
От: pva  
Дата: 03.11.23 14:20
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Если у вас данные идут с задержкой в несколько дней, то что вы используете в качестве кеша?

redis. Но я в нем храню только списки границ непрерывных сегментов. Например, "1-4" "6-7"... Сами данные хранятся в другом месте.

BE>Наличие непрерывности тоже в принципе можно через sql проверять.

Даже боюсь себе представить. Не только с точки зрения sql, но и с точки зрения необходимых ресурсов.

Лет эдак 8 назад законтрактили меня на один проект "посмотреть одним глазом". Там чуваки использовали mssql для телеметрии, вида time-value. По таблице на канал. Ну и там еще много смешного было.
Пара таких серверов с трудом тянула чуть больше десятка "клиентов", жрала под $10k на AWS и помирала каждую ночь при выгрузке суточных данных.
newbie
Re: Сборка мозаики
От: Dair Россия https://dair.spb.ru
Дата: 03.11.23 14:23
Оценка:
Здравствуйте, pva, Вы писали:

pva>как бы вы решали такую задачу?


Непонятно условие выдавания значений наружу.
Что значит "все типы"? Есть какой-то словарь "всех типов", существующий отдельно? Тогда чему он равен для приведённого примера? [1,2]? Тогда почему в третьей строчке ничего не вывели? Что такое "длительность" в данном случае?
Re[2]: Сборка мозаики
От: pva  
Дата: 03.11.23 14:30
Оценка:
Здравствуйте, Dair, Вы писали:

D>Непонятно условие выдавания значений наружу.

D>Что значит "все типы"? Есть какой-то словарь "всех типов", существующий отдельно? Тогда чему он равен для приведённого примера? [1,2]?
"все типы" для данного примера — это [1,2] как вы и указали. Да, словарь типов фиксированный. Иначе мы не могли бы определить условие — содержать все "типы".

D>Тогда почему в третьей строчке ничего не вывели?

Потому что в третьей строчке тип "1" "готов" — содержит непрерывный сегмент размером 2 семпла, а тип "2" в третьей строчке получил только свой первый семпл — не соответствует условию достаточной "длительности".

D>Что такое "длительность" в данном случае?

Размер непрерывного сегмента в семплах.
newbie
Re[3]: Сборка мозаики
От: Dair Россия https://dair.spb.ru
Дата: 03.11.23 14:35
Оценка:
Здравствуйте, pva, Вы писали:

pva>"все типы" для данного примера — это [1,2] как вы и указали. Да, словарь типов фиксированный. Иначе мы не могли бы определить условие — содержать все "типы".


Ага.

D>>Тогда почему в третьей строчке ничего не вывели?

pva>Потому что в третьей строчке тип "1" "готов" — содержит непрерывный сегмент размером 2 семпла, а тип "2" в третьей строчке получил только свой первый семпл — не соответствует условию достаточной "длительности".

А, то есть, в искомой нам последовательности должно быть по "длительности" каждого "типа", то есть, минимальный фиксированный размер выдаваемого пакета "длительность"*кол-во-"типов", да?

D>>Что такое "длительность" в данном случае?

pva>Размер непрерывного сегмента в семплах.

А вот вопрос — что будет если в пятой строчке приведённого примера придёт, например, "0"-"1"-"Г"? "ААГБВ"?

А, нет, сам себя поправляю — длительность заданная, а не минимальная. Тогда я не знаю правильного ответа, что надо вывести?
Отредактировано 03.11.2023 14:37 Dair . Предыдущая версия . Еще …
Отредактировано 03.11.2023 14:37 Dair . Предыдущая версия .
Отредактировано 03.11.2023 14:36 Dair . Предыдущая версия .
Re[4]: Сборка мозаики
От: pva  
Дата: 03.11.23 14:44
Оценка:
Здравствуйте, Dair, Вы писали:

D>А, то есть, в искомой нам последовательности должно быть по "длительности" каждого "типа", то есть, минимальный фиксированный размер выдаваемого пакета "длительность"*кол-во-"типов", да?

Да, именно так. Не просто по длительности каждого типа, а они должны быть тех же самых индексов. То есть, если у нас тип "1":[0, 1], а тип "2":[1, 2] то это не "наш пациент".
И "длительность" задает минимальное ограничение на размер. Тоесть, нет проблем если при лимите 2 мы получим из "1.3" + "2" = "123" (по индексам).

D>А вот вопрос — что будет если в пятой строчке приведённого примера придёт, например, "0"-"1"-"Г"? "ААГБВ"?

Такое прийти не может — индекс является автоинкрементом на клиенте. Но из-за зашумленности сети пакеты могут теряться и для потеряшек повтор будет только через какой-то промежуток времени с тем же индексом.

D>А, нет, сам себя поправляю — длительность заданная, а не минимальная. Тогда я не знаю правильного ответа, что надо вывести?

Если у нас только два типа [1, 2], то что бы ни пришло пятой строчкой — оно будет частью нового сегмента, поскольку в примере выше предыдущие четыре строчки уже сформировали законченный сегмент и больше не участвуют в игре.
newbie
Отредактировано 03.11.2023 14:47 pva . Предыдущая версия .
Re[5]: Сборка мозаики
От: Dair Россия https://dair.spb.ru
Дата: 03.11.23 15:07
Оценка: 2 (1)
Здравствуйте, pva, Вы писали:

pva>Да, именно так. Не просто по длительности каждого типа, а они должны быть тех же самых индексов. То есть, если у нас тип "1":[0, 1], а тип "2":[1, 2] то это не "наш пациент".


Тут я потерялся. Исходно ты говорил про индекс и тип как отдельные друг от друга сущности.
А тут ты накладываешь уже ограничения на индекс тоже, то есть, их надо воспринимать совместно?..

Я уже думал что я почти всё понял, а вот нет!

Накидай ещё примеров, пожалуйста.

Вот, например, если в исходном примере индексы поменять на 1234 вместо 1001 — что поменяется?

"1"-"1"-"Б" => []
"2"-"1"-"A" => []
"3"-"2"-"A" => []
"4"-"2"-"В" => ??
Re[6]: Сборка мозаики
От: pva  
Дата: 03.11.23 18:23
Оценка:
Здравствуйте, Dair, Вы писали:

D>Тут я потерялся. Исходно ты говорил про индекс и тип как отдельные друг от друга сущности.

Спасибо что пытаешься разобраться. Исходно я писал

Задача: максимально оперативно выдавать упорядоченные по индексу непрерывные куски заданной длительности. Кусок должен содержать все "типы".

Тоесть, здесь присутствуют ограничения:
1) непрерывность
2) для выбранного куска — суть, заданной последовательности индексов [a..b] — присутсвие во всех типах.
То есть, выход есть только в случае когда у нас [a..b] существует для всех типов.

D>Вот, например, если в исходном примере индексы поменять на 1234 вместо 1001 — что поменяется?

D>
D>"1"-"1"-"Б" => []
D>"2"-"1"-"A" => []
D>"3"-"2"-"A" => []
D>"4"-"2"-"В" => ??
D>

[]. Потому что ни одна из последовательностей индексов длины 2+ не содержится во всех типах. Но вот если дальше прилетит
"2"-"2"-"Б" => []
"3"-"1"-"A" => [АБАА]

Потому что появляется непрерывный сегмент минимальной длины (2), существующий для обоих типов.
newbie
Re: Сборка мозаики
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.11.23 04:32
Оценка: 2 (1)
Здравствуйте, pva, Вы писали:
pva>Задача: максимально оперативно выдавать упорядоченные по индексу непрерывные куски заданной длительности. Кусок должен содержать все "типы".
Куски могут(должны) перекрываться?
Ну, то есть если у нас ровно один тип, то что должно выдаваться при таком входе для длительности 2?

0-0-A
1-0-B -> AB
2-0-C -> BC или ""?
3-0-D -> CD

В целом, задача выглядит достаточно прямолинейно.
Берём любую отсортированную структуру queue, например B-дерево. Ключ сортировки — (индекс, тип).
Параллельно с ней заводим структуру message фиксированным размером L*N, где L — длительность, N — количество типов.
Заводим lsn — текущий номер индекса, и readyCount — количество готовых к отправке отсчётов. Оба инициализируются нулём.
При поступлении каждого сэмпла
1. Если индекс — в диапазоне [lsn, lsn+L), и в message пришедшего отсчёта ещё нет, то
1.1. Кладём отсчёт в message
2.2. Увеличиваем readyCount. Если он равен L*N, то
1.2.3. "выдаём" содержимое message
1.2.3. Сдвигаем lsn: в зависимости от ответа на мой вопрос вначале, либо на L, либо на 1.
1.2.4. Правим message: в зависимости от ответа на мой вопрос вначале, либо очищаем, либо "сдвигаем" на N, освобождая новую строку.
1.2.5. Правим readyCount: в зависимости от ответа на мой вопрос вначале, либо обнуляем, либо уменьшаем на N.
1.2.5. Заполняем освободившееся место в message из queue
1.2.6. Выбрасываем из queue все данные с ключом меньше lsn
2. Иначе (индекс >= lsn+L) — кладём отсчёт в queue.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Сборка мозаики
От: pva  
Дата: 05.11.23 09:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

pva>>Задача: максимально оперативно выдавать упорядоченные по индексу непрерывные куски заданной длительности. Кусок должен содержать все "типы".

S>Куски могут(должны) перекрываться?
S>Ну, то есть если у нас ровно один тип, то что должно выдаваться при таком входе для длительности 2?
S>

S>0-0-A
S>1-0-B -> AB
S>2-0-C -> BC или ""?
S>3-0-D -> CD

После выдачи AB индексы 01 больше не участвуют. Тоесть для 2-0-C -> ""

S>В целом, задача выглядит достаточно прямолинейно.

Насколько я понял алгоритм, то он реализует дискрeтный шаг наблюдения.
В таком случае мы можем просто разбить весь диаппазон на "окна" размера N и хранить только счетчики для каждого окна при условии что во входящем потоке нет дубликатов.
По входящему индексу просто определяем какому окну принадлежит и увеличиваем там счетчик. По достижению N — выдаем результат.

Давайте увеличу лимит до 4, чтобы показать некоторые примеры
Текущее состояние "кеша"
Тип 1: 1 2 3 4 5 6 7 8 . . . 12
Тип 2: . 2 3 4 . . 7 8 9 . . 12
Входящий
Тип 1: 9 
Тип 2: 10 
Новое состояние
Тип 1: 1 2 3 4 5 6 7 8 9 .  . 12
Тип 2: . 2 3 4 . . 7 8 9 10 . 12
Результат: [] - потому что нет в обоих типах последовательности длины 4+

Входящий
Тип 2: 5 6
Новое состояние (промежуточное)
Тип 1: 1 2 3 4 5 6 7 8 9 .  . 12
Тип 2: . 2 3 4 5 6 7 8 9 10 . 12
Новое состояние
Тип 1: 1 .  . 12
Тип 2: . 10 . 12
Результат: [ 2 3 4 5 6 7 8 9 ] - непрерывная последовательность длины 4+ в обоих типах
newbie
Отредактировано 05.11.2023 9:29 pva . Предыдущая версия .
Re[3]: Сборка мозаики
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.11.23 02:19
Оценка:
Здравствуйте, pva, Вы писали:

pva>В таком случае мы можем просто разбить весь диаппазон на "окна" размера N и хранить только счетчики для каждого окна при условии что во входящем потоке нет дубликатов.

pva>По входящему индексу просто определяем какому окну принадлежит и увеличиваем там счетчик. По достижению N — выдаем результат.
Да. Гарантия отсутствия дубликатов упрощает алгоритм.
Update: Нужно быть аккуратным, и всё же держать очередь окон. Иначе есть риск первым собрать полный комплект не от "текущего" окна, а от "следующего" — тогда наивный алгоритм отправит сначала "следуюшее" окно, а уже потом — предыдущее.
В остальном, всё остаётся вполне простым.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 06.11.2023 16:27 Sinclair . Предыдущая версия .
Re[4]: Сборка мозаики
От: pva  
Дата: 07.11.23 16:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Update: Нужно быть аккуратным, и всё же держать очередь окон. Иначе есть риск первым собрать полный комплект не от "текущего" окна, а от "следующего" — тогда наивный алгоритм отправит сначала "следуюшее" окно, а уже потом — предыдущее.

Нет ограничения на порядок отправки, равно как и требования фиксированного шага. Выше я уже показал как для размера 4 получить кусок, размером 8 не по границе "окна".
Впрочем, я уже реализовал через диаппазоны. Не очень оптимально по скорости, но коротко и читаемо. Следующий этап — добавить "заполненность", чтобы допустимо было выдавать куски заполненные не на 100%.
newbie
Re[5]: Сборка мозаики
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.11.23 16:43
Оценка:
Здравствуйте, pva, Вы писали:
pva>Нет ограничения на порядок отправки, равно как и требования фиксированного шага. Выше я уже показал как для размера 4 получить кусок, размером 8 не по границе "окна".
pva>Впрочем, я уже реализовал через диаппазоны. Не очень оптимально по скорости, но коротко и читаемо. Следующий этап — добавить "заполненность", чтобы допустимо было выдавать куски заполненные не на 100%.
По-видимому, я неверно понял задачу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.