Частина 1 залишила конвеєр з потоком канонічних трекових спостережень, що тече на шину повідомлень. Кожне спостереження — ізольований атом: «джерело X доповідає про об'єкт у позиції Y зі швидкістю Z о моменті T». Завдання рушія злиття — вирішити, які спостереження стосуються того самого фізичного об'єкта, акумулювати їх у стабільні треки зі зростаючою впевненістю ідентичності, керувати життєвим циклом, коли спостереження припиняються або з'являються нові, та виставити запитуваний вид світу для COP і подальших споживачів. Частина 2 — про побудову цього рушія.
Концептуальний орієнтир — Військове злиття даних простими словами для огляду дисципліни, Модель злиття даних JDL для прив'язки до рівнів та опорна стаття Повний посібник зі злиття оборонних даних для ширшого архітектурного контексту.
Крок 1: двостадійний фільтр кореляції
Ключове рішення рушія злиття — чи є вхідне спостереження оновленням наявного треку, чи народженням нового — не потребує одного-єдиного алгоритму. Патерн, що масштабується в продакшні, використовує дві стадії: дешевий фільтр на правилах, що обробляє прості випадки, і ймовірнісний рушій асоціації, який викликається лише тоді, коли шар правил неоднозначний.
Стадія на правилах обробляє 90% спостережень, які є однозначними. Для кожного вхідного спостереження вона обчислює множину кандидатних наявних треків у межах кінематичної досяжності — позиційно-часові ворота. Апріорі ідентичності фільтрує далі: спостереження з тегом «судно» не може збігтися з треком «літак». Сумісність джерел теж фільтрує: спостереження з наземного радара не може збігтися з повітряним треком підводної платформи. Якщо ворота дають рівно одного кандидата, що проходить правила ідентичності та джерела, спостереження оновлює цього кандидата напряму. Якщо ворота дають нуль кандидатів, спостереження ініціює тентативний новий трек. Дешево, швидко, пояснювано.
Ймовірнісна стадія викликається, коли шар правил повертає кілька кандидатів або коли щільність треків достатньо висока, щоб впевнений гейтинг був неможливим. Joint Probabilistic Data Association (JPDA) обчислює правдоподібність того, що спостереження належить кожному кандидатному треку, та оновлює кожен зі зважуванням за правдоподібністю. Multiple Hypothesis Tracking (MHT) підтримує множинні гіпотези треків між спостереженнями, відкладаючи рішення про асоціацію, доки не накопичиться достатньо доказів. Обидва алгоритми обчислювально важчі та складніші для налаштування; обидва є коректними лише для тих випадків, де шар правил помилково взяв на себе зобов'язання.
Конкретна пастка, варта згадки: MHT генерує експоненційну кількість гіпотез без обрізки. Політика обрізки — скільки гіпотез утримувати, коли зливати, коли видаляти — важливіша за сам базовий алгоритм. За замовчуванням — агресивна обрізка; розширюйте її тільки тоді, коли цього вимагають оперативні докази.
Крок 2: налаштування шару правил
Шар правил — це місце, де осідає більшість інженерних зусиль зі злиття. Алгоритм простий; налаштування — це ремесло.
Параметри воріт, які мають значення:
- Розмір кінематичних воріт — наскільки далеко спостереження може бути від прогнозованої позиції треку, щоб все ще збігтися. Замалі ворота пропускають реальні оновлення після сенсорного шуму; завеликі — продукують хибні кореляції в щільних сценах.
- Ворота ідентичності — які атрибути ідентичності мають збігтися (завжди: таксономія типу; іноді: підтип, бортовий номер, позивний).
- Правила набору джерел — які джерела можуть оновлювати які типи треків. Доменно-специфічні (морський радар не повинен оновлювати підводний трек) і платформенно-специфічні (контакт SIGINT лише за пеленгом може не асоціюватися з кінематичним треком без зіставлення пеленга).
- Толерантність часу від останнього оновлення — спостереження проти треків, що мовчали занадто довго, продукують новий тентативний трек, а не реасоціюються зі старим.
Значення за замовчуванням приходять із профілів точності та затримки в каталозі джерел. Операційне налаштування приходить із повторного програвання зафіксованих даних із метриками частоти хибних кореляцій та частоти пропущених асоціацій. У рушіях злиття замовницького рівня ці ручки налаштування виставлені для операційної команди, щоб коригувати їх per deployment; в індивідуальних програмах часто жорстко зашивають значення і шкодують про це, коли контекст розгортання змінюється.
Крок 3: коли і як викликати ймовірнісну асоціацію
Ймовірнісна асоціація — правильний інструмент, коли гейтинг на правилах не може видати впевнений єдиний збіг. Сигнал, що ймовірнісна асоціація потрібна: ворота повертають більше одного кандидата зі швидкістю вище (скажімо) 5% у операційній сцені.
Прагматичний патерн виклику:
JPDA для помірної щільності. Коли ворота повертають 2–4 кандидати на неоднозначне спостереження, JPDA обчислює правдоподібності асоціації, використовуючи кінематичні апріорі (відстань Махаланобіса від прогнозованої позиції) та апріорі ідентичності. Оновлення треків зважуються за правдоподібністю; жоден окремий трек не отримує «остаточного» оновлення, але найімовірніші кандидати швидше накопичують докази.
MHT для найскладніших випадків. Коли ворота повертають багато кандидатів, а неоднозначність асоціації зберігається між спостереженнями, MHT відкладає рішення. Він підтримує гіпотези (альтернативні інтерпретації того, яке спостереження належить якому треку) і обрізає за правдоподібністю. Після кількох спостережень домінуюча гіпотеза проявляється, а інші видаляються.
Об'єднаний вихід. Обидва алгоритми продукують оновлення, що повертаються до того самого сховища треків, що й оновлення на правилах. З точки зору подальших споживачів усі оновлення виглядають однаково; різниця в метаданих впевненості та провенансу, що додаються.
Реальність впровадження: для JPDA і MHT існують добре протестовані open-source бібліотеки (Stone Soup, FilterPy і суміжні інструменти). Більшість операційних рушіїв злиття обгортають перевірену бібліотеку, а не реалізують з нуля. Інженерні зусилля — в інтеграції, налаштуванні та операційній обкатці, а не в самому алгоритмі.
Крок 4: скінченний автомат життєвого циклу треку
Треки мають життєві цикли. Скінченний автомат, що ними керує, — одне з найбільш операційно вагомих рішень платформи: оператори толерують відсутні треки, але не толерують впевнено відображених застарілих треків. Життєвий цикл — це межа між довірливим і недовірливим відображенням.
Скінченний автомат для прикладу, що ми розглядаємо:
- Tentative (тентативний). Перше спостереження; очікує підтвердження. Не відображається в операційному COP, якщо оператор явно не запитує видимість низької впевненості. Розпадається до видаленого, якщо немає продовження впродовж конфігурованого вікна.
- Confirmed (підтверджений). Два або більше скорельованих спостережень у вікні кінематичної консистентності. Підвищений з тентативного. Стан за замовчуванням для відображених треків.
- Mature (зрілий). Підтверджений і стійкий упродовж щонайменше N хвилин з консистентними оновленнями. Використовується подальшою аналітикою, що потребує стабільної ідентичності для аналізу патернів поведінки чи поведінкового аналізу.
- Fading (згасаючий). Немає оновлень у межах очікуваного інтервалу повторного відвідування для цього класу джерел. Відображення позначається як застаріле (тьмяніший символ, індикатор віку). Конфігурується для кожного класу джерел — 30-секундний морський трек — це нормально; 30-секундний повітряний трек — згасає.
- Lost (втрачений). Немає оновлень упродовж тривалого періоду. Видаляється з активного відображення, але зберігається у сховищі треків для аудиту та історичного аналізу.
Переходи базуються на часі та оновленнях, причому обидва живлять одне дерево рішень. Кожен перехід логується разом із подією-тригером (оновлення спостережень, спрацювання таймауту, ручне втручання оператора). Журнал переходів живить аудит-слід на event sourcing, описаний у Event Sourcing для оборонних аудит-слідів.
Практична деталь: сервіс життєвого циклу — окремий процес від рушія кореляції. Він підписується на події оновлення треків від кореляції, обчислює переходи життєвого циклу та публікує їх як окремий потік на шині. Декаплінг дозволяє політиці життєвого циклу еволюціонувати, не торкаючись рушія кореляції.
Ключова теза: керування життєвим циклом — це шар, що відокремлює демо-рівень злиття від операційного. Платформа, що видає коректні треки, але ніколи не повідомляє операторам, що трек застарів, — це платформа, якій оператори перестають довіряти. Будуйте сервіс життєвого циклу до того, як алгоритм злиття буде повністю налаштований — він окуповується щоразу, коли падає лінк датчика.
Крок 5: сховище треків як read-модель на event sourcing
Злиття видає потік оновлень треків і переходів життєвого циклу. Сховище треків — це матеріалізований вид: поточний стан кожного активного треку, запитуваний з COP, з аналітики та через зовнішні API. Архітектурне рішення, варте прийняття на ранньому етапі, — те, що сховище треків є read-моделлю, а не авторитативним джерелом. Авторитативне джерело — це лог подій на шині повідомлень. Сховище треків відбудовується з логу на вимогу.
Переваги цього патерну:
Стерти й перебудувати. Сховище можна очистити й перебудувати з логу без втрати даних. Міграції схем, налаштування продуктивності та відновлення зіпсованих даних стають рутиною, а не ризиком.
Множинні read-моделі. Оптимізована для COP read-модель (геопросторово індексована, кеш гарячих треків, низьколатентні читання) співіснує з аналітично-оптимізованою моделлю (денормалізована, дружня до батчів) та зовнішньою API-моделлю (фільтрована, класифікована per consumer). Усі — проєкції того самого підлежного потоку подій.
Запити з подорожжю в часі. «Що платформа вважала о 14:32?» стає тривіальним: програти лог до 14:32 проти свіжої проєкції. Розбір післядії, навчання та акредитаційний аудит — усі виграють.
Реалізація: PostgreSQL з розширенням PostGIS для геопросторових запитів (за замовчуванням для прикладу, що ми розглядаємо). Шар Redis перед ним для субмілісекундних читань гарячих треків на критичному шляху COP. Реляційне сховище обробляє запити довгого хвоста та гарантії персистентності. Детальний інженерний погляд, включно зі стратегіями індексування, що масштабуються до мільярдів точок, — у PostGIS для оборонних геопросторових даних.
Крок 6: чиніть опір графовій базі (поки що)
Передбачувана спокуса в дизайні злиття — додати графову базу даних «для відношень». Виявлення конвоїв, розпізнавання формувань, контактні мережі — усе це звучить графоподібно. Спокуса — змоделювати їх у Neo4j чи еквіваленті та отримати «природні» запити відношень.
Прагматичний контраргумент: відношення між треками — це злиття Рівня 2 JDL, окрема турбота від обслуговування треків Рівня 1. Збудуйте спершу Рівень 1, проганяйте його в експлуатації рік, і лише потім поверніться до Рівня 2 з операційними доказами в руках. Відношення Рівня 2 часто потребують іншої форми, ніж передбачала інтуїція графової бази, — темпорально-реляційної, а не суто топологічної, класифікаційно-обізнаної, а не відкритої, вираженої на вищому рівні абстракції, ніж per-track ребра.
Платформи, що мають успіх, починають з PostGIS + Redis для read-моделі, доводять злиття на Рівні 1 та додають можливості Рівня 2 як окремі сервіси, що споживають той самий потік подій. Платформи, що зазнають невдачі, додають графову базу на першому тижні й проводять два роки, налагоджуючи невідповідну абстракцію.
Крок 7: тестуйте рушій злиття проти реальності
Рушій злиття, тестований тільки на іграшковому навантаженні, проходить інтеграційні тести й провалюється в експлуатації. Дисципліни, що ловлять проблеми до розгортання:
Стенди повторного програвання. Захоплені сенсорні траси з реальних операцій, програні на повній швидкості та в прискореному режимі проти рушія злиття. Траси — це регресійний тестовий набір: будь-яка зміна алгоритму чи схеми має давати еквівалентні або кращі результати, причому не лише на синтетичному навантаженні.
Метрики якості треків у CI. Частота хибних кореляцій, частота пропущених асоціацій, частота фрагментації треків, тайминг переходів життєвого циклу. Кожна метрика відстежується в часі; регресії блокують реліз. Метрики оцінюються проти трас повторного програвання, а не проти синтетичного навантаження.
Тестування ворожих сценаріїв. Підроблені AIS-повідомлення з неправдоподібною кінематикою. Радарні відмітки, що порушують фізику. Випадання джерел у критичні моменти. Рушій злиття має деградувати плавно під поганим вхідним матеріалом — не падати, не продукувати впевнено-але-хибні треки. Ширший інженерний патерн ворожої стійкості в обороні — в Тестування критично важливих C2-систем.
Тестування навантаження та пікового сплеску. 95-й перцентиль латентності злиття під 500 мс при 10 000 спостережень/с; 99-й перцентиль під 1,5 с. Підтримується впродовж тривалості операційної ротації, а не лише для маркетингового бенчмарку. Платформа має мати запас CPU в одну цифру відсотків для обробки сплесків.
Що далі
Частина 2 збудувала рушій. Двостадійна кореляція обробляє прості й складні випадки. Скінченний автомат життєвого циклу виносить свіжість на поверхню для операторів. Сховище треків як read-модель на event sourcing підтримує запити, не стаючи авторитативним джерелом. Дисципліни тестування валідують цей шар проти реальності.
Частина 3 заглиблюється в мульти-INT випадок — поєднання SIGINT, IMINT, ELINT, OSINT, HUMINT, GEOINT, MASINT у той самий потік злиття зі збереженням їхніх семантичних відмінностей — і береться за поширення класифікації та releasability, якого оборонне злиття унікально вимагає.