Прогнозная модель принимала решения на основе рядов примерно от 10 000 внешних источников в разных форматах (XML, Excel, CSV), где данные приходили с пропусками, выбросами и без контекста происхождения, а счёт записей шёл на миллиарды.
Построили конвейер из независимых микросервисов-разборщиков на Python, которые параллельно приводят разнородные форматы к общему виду, без дублей загружают их в хранилище временных рядов вместе с паспортом объекта и из очищенных рядов собирают датасеты для модели.
Разбор перестал быть последовательным узким местом - источники обрабатываются параллельно, а прогноз возвращается в систему готовой машиночитаемой заявкой, отчётами и графиками вместо ручной сводки файлов.
Решение на завтра начинается далеко от модели
Каждый день организация решает, купить или продать актив на ближайшие сутки-двое. Ошибка в прогнозе быстро превращается в реальные деньги, поэтому результат модели должен опираться на данные, которым можно доверять.
До модели эти данные проходят длинный путь. Они приходят примерно от 10 000 внешних источников, и счёт записей с самого начала идёт на миллиарды. Один объект отдаёт XML, другой - Excel или CSV. Частота измерений различается, в рядах встречаются пропуски и выбросы, а само число без контекста не объясняет, где и что измерили.
Наша часть проекта находилась именно здесь: между сырой выгрузкой и готовым датасетом. Нужно было собрать десятки гигабайт разнородной истории, привести её к общему виду и не потерять смысл по дороге.
Возьмём одно измерение и проведём через весь конвейер
На вход приходит очередной файл или порция данных от внешнего объекта. Сначала специализированный разборщик понимает формат, извлекает временной ряд и связывает его с источником. Затем данные проходят чистку, попадают в хранилище временных рядов и превращаются в векторы, над которыми можно считать формулы. Из готовых векторов специалист собирает датасет для модели.
После расчёта путь продолжается: прогноз возвращается в систему, появляется в отчётах и графиках, а затем превращается в структурированный файл заявки для внешней системы-приёмника. Ценность возникает только тогда, когда число доходит до конкретного действия.
Десять тысяч источников нельзя разбирать последовательно
Последовательная обработка такого объёма занимала бы часы, поэтому разбор разделён на независимые микросервисы на Python и распределён по разным серверам. Источники обрабатываются параллельно, а сбой одного разборщика не требует останавливать весь поток.
Каждый формат изолирован от остальной системы. Если один поставщик меняет структуру файла, корректируется его разборщик; хранилище, чистка, векторный слой и модели продолжают работать с прежним внутренним представлением.
Загрузка идемпотентна. Повторно присланный файл или повторный запуск не создают вторую копию тех же записей. Перед загрузкой система сверяет, что уже обработано, и не тянет разобранные данные в базу заново. Это позволяет безопасно перезапускать задачи после сбоя, не очищая результат вручную.
Число получает паспорт объекта
Временной ряд хранит последовательность значений, но смысл находится рядом. Для каждого объекта есть паспорт: название, координаты и атрибуты, которые объясняют происхождение измерения и его место в общей структуре.
Без такого паспорта два одинаковых числа могут относиться к разным объектам и описывать разные процессы. Поэтому хранилище соединяет историю измерений со справочными таблицами, а не складывает всё в одну широкую таблицу без контекста.
Специализированная база временных рядов держит годы истории с посуточными чанками и компрессией. Агрегаты для графиков строятся по запросу, поэтому ради каждого нового периода не нужно заранее создавать ещё одну копию данных.
| Слой | Что он сохраняет | Зачем это следующему этапу |
|---|---|---|
| Паспорт объекта | Название, координаты и атрибуты | Ряд не теряет происхождение и смысл |
| Временной ряд | Значения по времени | Можно анализировать историю и строить агрегаты |
| Чистый вектор | Сопоставимый ряд без технического мусора | Формулы и модели получают единое представление |
| Датасет | Выбранные исходные и производные признаки | Модель обучается на наборе под конкретную задачу |
Чистка должна отличить ошибку от важного всплеска
В измерениях неизбежны пропуски и значения, выбивающиеся из общего ряда. Перед расчётами конвейер заполняет пробелы и убирает выбросы, чтобы случайный провал или технический скачок не исказил обучение.
Но агрессивная чистка опасна не меньше грязных данных. Реальный всплеск может быть как раз тем событием, которое влияет на прогноз. Поэтому подготовка ряда должна убрать технический мусор и одновременно сохранить значимые изменения исходного процесса.
Чистый ряд не означает идеально гладкий. Если выровнять все резкие изменения, вместе с ошибками исчезнут события, ради которых строится прогноз.
Эта работа происходит до того, как данные увидит модель. В результате специалист сравнивает сопоставимые ряды, а не объясняет алгоритму, почему в одном источнике пропущен час, а в другом случайно появилась невозможная величина.
Формула собирает новый ряд без ручной выгрузки
Очищенные ряды приводятся к единому векторному представлению. Над векторами можно выполнять арифметику: складывать, вычитать, умножать и делить один ряд на другой. Так из исходных измерений появляются производные признаки.
Калькулятор хранит формулу и выполняет её над рядами прямо в контуре данных. Аналитику не приходится выгружать десятки файлов, сводить столбцы вручную и повторять ту же работу для следующего периода. Он выбирает нужные исходные и производные векторы и собирает датасет под конкретную модель.
Слой машинного обучения вёл отдельный специалист. Конвейер передавал ему подготовленные датасеты и принимал прогноз обратно. Такое разделение важно: качество подготовки можно развивать независимо от конкретной модели, а модель не должна каждый раз заново решать задачу сбора и очистки.
Прогноз возвращается как готовая заявка
Результат расчёта используется в отчётах и графиках, но на этом процесс не заканчивается. Система формирует машиночитаемую заявку - структурированный файл, который принимает внешняя система. Прогноз не остаётся ячейкой, которую человек должен вручную перенести и заново истолковать.
Ручная цепочка "собрать файлы, разобрать, почистить, свести, посчитать" превращается в повторяемый конвейер. Специалист работает с библиотекой рядов и формул, модель получает подготовленный датасет, а итог доходит до контура принятия решений.
Дальше суток-двух неопределённость растёт
Рабочий горизонт прогноза - ближайшие сутки-двое. Система может рассчитать и более далёкий период, но точность закономерно снижается вместе с горизонтом. Это свойство исходной задачи, а не дефект хранилища или конвейера.
Сам конвейер также не делает плохой источник хорошим автоматически. Его результат зависит от полноты данных, корректности паспортов и правил чистки. Он показывает и подготавливает доступную историю, но не может восстановить смысл, которого источник изначально не передал.
Архитектура при этом допускает рост без замены основы: подключение новых источников и форматов, расширение библиотеки формул, новые датасеты и более плотную связь с моделями и внешними системами. Каждый новый формат получает собственный разборщик, а уже очищенные ряды продолжают проходить общий путь.
Это реальный проект, поданный обезличенно. Узнаваемые детали - отрасль, конкретику, всё, по чему можно вычислить заказчика, - мы намеренно меняем; имя и коммерческие тайны заказчика не раскрываем. Неизменной остаётся суть: какую задачу решали и каким инженерным подходом. Кейс написан, чтобы показать проблему и её решение - что и как мы делаем.

