← Блог
4 мільйони записів за 200 мс: як ми побудували санкційний скринінг у Panoptic
OpenSanctions, Elasticsearch, fuzzy matching — як ми інтегрували 100+ санкційних списків світу в єдиний API і чому це змінює правила Due Diligence для українського бізнесу.
OSINT · 2026-04-07T14:00:00
OFAC, EU, UN, РНБО, Interpol, PEP-реєстри 200+ країн — усе в одному API. 4 мільйони сутностей. Fuzzy matching, що знаходить "Володимир Путін" навіть якщо ви написали "Vladimir Poutin". Ось як це працює.
Вступ: чому санкційна перевірка — це не "галочка" у чеклісті
Уявіть: ваша компанія підписує контракт з іноземним партнером. Юристи перевірили ЄДРПОУ, судовий реєстр — все чисто. Через три місяці приходить лист від комплаєнс-відділу банку: один із бенефіціарів контрагента — під санкціями OFAC. Контракт заморожено. Рахунки під ризиком блокування. Репутаційні та фінансові збитки — колосальні.
Це не гіпотетика. За даними Державної служби фінансового моніторингу, у 2025 році кількість порушень санкційного законодавства в Україні зросла на 40%. Причина не в злому намірі, а в неповноті перевірок.
Більшість компаній перевіряють контрагентів по одному-двох списках — зазвичай РНБО та, можливо, OFAC. Але санкційних списків у світі — понад сто. І підсанкційна особа може бути в списку Австралії, Швейцарії чи Японії, але не в українському реєстрі.
Ми побудували санкційний скринінг Panoptic, щоб закрити цю прогалину. Один запит — 100+ списків. 4 мільйони сутностей. Відповідь за мілісекунди.
Що таке OpenSanctions і чому це стандарт індустрії
OpenSanctions — це відкрита база даних, що агрегує санкційні списки, PEP-реєстри (Politically Exposed Persons) та дані правоохоронних органів з усього світу в єдиний стандартизований формат.
Що включено
| Категорія | Приклади джерел | Кількість записів | |-----------|----------------|-------------------| | Міжнародні санкції | OFAC (США), EU Consolidated List, UN Security Council | ~50,000 | | Національні санкції | РНБО (Україна), DFAT (Австралія), SECO (Швейцарія), METI (Японія) | ~30,000 | | PEP-реєстри | Глави держав, міністри, депутати, судді 200+ країн | ~3,500,000 | | Правоохоронні | Interpol Red Notices, FBI Most Wanted, EU Most Wanted | ~10,000 | | Корпоративні зв'язки | Підсанкційні компанії, їхні дочірні структури, бенефіціари | ~400,000 |
Загалом: 4,000,000+ сутностей — осіб, компаній, суден, літаків та інших об'єктів.
Чому не просто парсити списки самостійно?
Кожен санкційний список має свій формат: XML у OFAC, CSV у EU, JSON у РНБО, PDF у деяких азійських юрисдикціях. Імена записані різними мовами, в різній транслітерації, з різним порядком прізвище/ім'я.
OpenSanctions вирішує цю проблему, стандартизуючи всі дані у формат FollowTheMoney — граф сутностей з уніфікованими полями. Це означає, що "Путін Володимир Володимирович", "Vladimir Putin" та "بوتين فلاديمير" — це один і той самий запис.
Архітектура: Elasticsearch + yente
Для пошуку і матчингу по 4 мільйонах записів потрібен швидкий і гнучкий пошуковий рушій. Ми обрали зв'язку Elasticsearch 8.18 + yente — офіційний API-сервер OpenSanctions.
Як це працює
~~~ ┌──────────────────────────────────────────────────────┐ │ Panoptic Backend │ │ (FastAPI) │ │ │ │ │ ┌──────────┴──────────┐ │ │ ▼ ▼ │ │ /sanctions/search /sanctions/match │ │ (повнотекстовий) (fuzzy matching) │ │ │ │ │ │ └──────────┬──────────┘ │ │ ▼ │ │ OpenSanctions Adapter │ │ (backend/app/adapters/ │ │ opensanctions.py) │ │ │ │ │ ▼ │ │ yente API Server │ │ (FollowTheMoney API) │ │ │ │ │ ▼ │ │ Elasticsearch 8.18 │ │ (4,000,000+ documents) │ │ │ │ Datasets: civic manifest (free) │ │ Sources: OFAC, EU, UN, РНБО, Interpol, │ │ PEP registries, corporate data │ └──────────────────────────────────────────────────────┘ ~~~
Elasticsearch: чому саме він
Для задачі санкційного скринінгу критичні три речі:
1. Fuzzy search — пошук з толерантністю до помилок у написанні. Elasticsearch підтримує Levenshtein distance, фонетичний пошук і n-gram токенізацію.
2. Мультимовний пошук — людина може шукати "Путін", "Putin", "Poutine" або навіть "Pootin". Elasticsearch з правильними аналізаторами знаходить усі варіанти.
3. Швидкість на великих обсягах — 4 мільйони документів з десятками полів кожен. Full-text search за <200 мс.
yente: API для FollowTheMoney
yente — це офіційний API-сервер OpenSanctions. Він:
Індексує дані OpenSanctions в Elasticsearch
Надає REST API для пошуку та матчингу
Підтримує scoring — числову оцінку відповідності
Автоматично оновлює дані при виході нових версій датасету
Ми використовуємо civic manifest — безкоштовну версію даних, яка включає всі санкційні списки та PEP-реєстри.
Три API-ендпоінти: пошук, матчинг, здоров'я
1. POST /api/v1/sanctions/search — повнотекстовий пошук
Класичний пошук за ім'ям або назвою організації. Ідеальний для швидкої перевірки "чи є хтось у санкціях".
~~~python
Запит
POST /api/v1/sanctions/search { "query": "putin", "limit": 10 }
Відповідь (спрощено)
{
"total": 1549,
"results": [
{
"id": "Q7747",
"name": "Vladimir Vladimirovich Putin",
"schema": "Person",
"datasets": ["us_ofac_sdn", "eu_fsf", "un_sc_sanctions", "ua_nsdc_sanctions"],
"properties": {
"nationality": ["Russia"],
"position": ["President of Russia"],
"birthDate": ["1952-10-07"]
},
"score": 0.99
}
]
}
~~~
1549 результатів за запитом "putin" — це не лише сам Путін, а й пов'язані особи, компанії, судна і літаки.
2. POST /api/v1/sanctions/match — fuzzy matching
Ключова функція для Due Diligence. Матчинг порівнює ваші дані з базою, використовуючи нечіткий пошук, і повертає ступінь впевненості.
~~~python
Запит
POST /api/v1/sanctions/match { "name": "Petro Poroshenko", "birth_date": "1965-09-26", "schema": "Person" }
Відповідь
{
"match_found": true,
"is_sanctioned": false,
"is_pep": true,
"best_match": {
"name": "Petro Oleksiyovych Poroshenko",
"score": 0.95,
"datasets": ["ua_nsdc_pep", "everypolitician"],
"properties": {
"position": ["President of Ukraine (2014-2019)"],
"nationality": ["Ukraine"]
}
}
}
~~~
Зверніть увагу: Порошенко — не під санкціями, але визначений як PEP (Politically Exposed Person). Це критична різниця для комплаєнсу: PEP не заборонені, але вимагають посиленої перевірки (Enhanced Due Diligence).
3. GET /api/v1/sanctions/health — перевірка системи
~~~python GET /api/v1/sanctions/health
{ "status": "healthy", "yente_available": true, "elasticsearch_status": "green", "indexed_entities": 4012847, "last_update": "2026-04-06T03:00:00Z" } ~~~
Fuzzy Matching: як знайти того, хто ховається за транслітерацією
Найскладніша частина санкційного скринінгу — це не технічна інтеграція, а якість матчингу. Підсанкційні особи активно використовують варіації імен:
Проблема транслітерації
~~~ Одна людина — десятки написань:
Кирилиця: Путін Володимир Володимирович Латиниця: Putin Vladimir Vladimirovich Французька: Poutine Vladimir Арабська: بوتين فلاديمير Варіації: V. Putin, Vlad Putin, Wladimir Putin Помилки: Putn, Putiin, Vladmir Putin ~~~
Як працює наш матчинг
Ми використовуємо багаторівневий підхід:
1. Точний матч — пряме співпадіння імені (score 1.0) 2. Фонетичний матч — Metaphone/Soundex алгоритми, що групують схожі за звучанням імена 3. Levenshtein distance — толерантність до 2 помилок у написанні 4. Cross-language matching — зіставлення через транслітераційні таблиці 5. Partial matching — "V. Putin" знаходить "Vladimir Putin" 6. Contextual boosting — додавання дати народження або країни підвищує точність
Scoring
Кожен результат отримує score від 0 до 1:
| Score | Інтерпретація | Рекомендована дія | |-------|--------------|------------------| | 0.95-1.0 | Майже точне співпадіння | Негайний review | | 0.80-0.94 | Високий збіг | Ручна перевірка обов'язкова | | 0.60-0.79 | Можливий збіг | Рекомендована перевірка | | < 0.60 | Малоймовірний збіг | Зазвичай false positive |
Реальні кейси: що знаходить Panoptic
Кейс 1: Перевірка контрагента перед контрактом
Компанія перевіряє потенційного партнера — юридичну особу з Кіпру.
Запит: \
Запустити OSINT-розвідку компанії →
Теги: #Sanctions, #Due Diligence, #OpenSanctions, #PEP, #Compliance, #OFAC, #РНБО
Схожі статті
Повернутися до блогу | Panoptic