Проект «РосУзник» – государственная информационная система, предназначенная для учёта, мониторинга и взаимодействия с осуждёнными, находящимися в исправительно‑трудовых лагерях и колониях России. Одной из ключевых функций системы является возможность быстро находить адресата (заключённого) по его фамилии.
Содержание статьи
- Общее описание базы данных
- Требования к поиску
- Подготовка данных (нормализация фамилий)
- Индексация и структуры данных
- Пошаговый алгоритм поиска
- Оптимизации и ускорение запросов
- Безопасность и контроль доступа
- Юридические нюансы (изменения закона от 15 января)
Общее описание базы данных
База проекта «РосУзник» построена на реляционной СУБД (PostgreSQL 15) и состоит из нескольких ключевых таблиц:
- prisoners – основной реестр заключённых;
- addresses – таблица с текущими и историческими адресами;
- cases – сведения о судебных делах;
- documents – сканы документов, в т.ч. «крепостной книги».
Таблица prisoners имеет следующую упрощённую схему:
CREATE TABLE prisoners (
id BIGSERIAL PRIMARY KEY,
surname VARCHAR(150) NOT NULL,
name VARCHAR(150),
patronymic VARCHAR(150),
birth_date DATE,
gender CHAR(1),
registration_id BIGINT REFERENCES addresses(id),
created_at TIMESTAMP DEFAULT now,
updated_at TIMESTAMP DEFAULT now
);
Для быстрого поиска по фамилии в таблице создаётся полнотекстовый индекс и индекс B‑tree на поле surname_norm (нормализованная фамилия).
Требования к поиску
- Точность – поиск должен возвращать только те записи, где фамилия совпадает с запросом, учитывая возможные варианты написания.
- Скорость – время отклика не должно превышать 200 мс при нагрузке до 500 одновременных запросов.
- Устойчивость к ошибкам ввода – поддержка транслитерации, опечаток, разных регистров.
- Контроль доступа – только уполномоченные пользователи (службы МВД, ФСИН) могут выполнять запрос.
Подготовка данных (нормализация фамилий)
Для обеспечения корректного сравнения фамилий применяется несколько этапов предобработки:
- Приведение к единому регистру – все символы переводятся в нижний регистр.
- Удаление диакритических знаков (ё → е, ъ → ъ, ь → ь и т.п.).
- Транслитерация – если запрос введён латиницей, происходит обратная транслитерация в кириллицу.
- Стемминг – удаление суффиксов, характерных для женских фамилий (‑ова, ‑ева) и мужских (‑ов, ‑ев) при необходимости.
Нормализованная фамилия сохраняется в отдельном поле surname_norm:
UPDATE prisoners
SET surname_norm = normalize_surname(surname);
Функция normalize_surname реализована на PL/pgSQL и использует unaccent + пользовательскую таблицу транслитераций.
Индексация и структуры данных
Для ускорения поиска применяются два типа индексов:
- Индекс B‑tree на
surname_norm– обеспечивает быстрый поиск точных совпадений. - GIN‑индекс на
to_tsvector('russian', surname_norm)– позволяет выполнять поиск по частичному совпадению и с учётом морфологии.
Создание индексов:
CREATE INDEX idx_prisoners_surname_norm
ON prisoners USING btree (surname_norm);
CREATE INDEX idx_prisoners_surname_fulltext
ON prisoners USING gin (to_tsvector('russian', surname_norm));
Пошаговый алгоритм поиска
Ниже представлена последовательность действий, которую выполняет серверный модуль при получении запроса «поиск по фамилии».
- Получение входных параметров:
- raw_surname – строка, введённая пользователем;
- search_mode – точный/нечетный (exact / fuzzy).
- Валидация и очистка:
- Удаление лишних пробелов, проверка длины (от 2 до );
- Нормализация фамилии – вызов функции
normalize_surname(raw_surname), результат сохраняется в переменнуюnorm_surname. - Определение режима поиска:
- Если
search_mode = 'exact'→ используется B‑tree‑индекс; - Если
search_mode = 'fuzzy'→ применяется полнотекстовый запрос с триграммами.
- Если
- Формирование SQL‑запроса:
-- Точный поиск SELECT p.id, p.surname, p.name, a.full_address FROM prisoners p JOIN addresses a ON p.registration_id = a.id WHERE p.surname_norm = $1 ORDER BY p.id LIMIT 100;-- Нечёткий поиск (по схожести) SELECT p.id, p.surname, p.name, a.full_address, similarity(p.surname_norm, $1) AS sim FROM prisoners p JOIN addresses a ON p.registration_id = a.id WHERE p.surname_norm % $1 -- оператор «похожести» pg_trgm ORDER BY sim DESC LIMIT 100; - Выполнение запроса через подготовленный
prepared statementдля защиты от инъекций. - Пост‑обработка результата:
- Сокращение полей, если пользователь имеет ограниченный уровень доступа;
- Логирование запроса (ID пользователя, время, количество найденных записей).
- Возврат ответа клиенту в формате JSON:
{ "query": "Иванов", "mode": "exact", "count": 3, "results": [ {"id": 10234, "surname":"Иванов", "name":"Алексей", "address":"ул. Пушкина, 12, г. Москва"}, ... ]}
Оптимизации и ускорение запросов
- Кеширование часто запрашиваемых фамилий – Redis‑кеш с TTL 5 минут. Ключ формируется как
search:{norm_surname}:{mode}. - Параллельная обработка – при большом объёме запросов используется пул соединений (pgBouncer) и асинхронные запросы в Node.js/Python‑FastAPI.
- Партирование таблицы – таблица
prisonersразбита по первой букве фамилии (partition by list (left(surname_norm,1))) для уменьшения сканируемого диапазона. - Триграммный индекс (pg_trgm) – ускоряет fuzzy‑поиск и поиск с опечатками.
Пример создания триграммного индекса:
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX idx_prisoners_trgm
ON prisoners USING gin (surname_norm gin_trgm_ops);
Безопасность и контроль доступа
Система реализует многоуровневый контроль доступа:
- Аутентификация – LDAP + двухфакторная аутентификация (OTP).
- Авторизация – роли
viewer,analyst,admin. Только ролиviewerи выше могут выполнять поиск. - Аудит – каждый запрос записывается в таблицу
audit_logс полями: user_id, ip_address, query_text, execution_time, result_count. - Шифрование – данные в базе зашифрованы с помощью pgcrypto (поле
addressхранится в видеpgp_sym_encrypt).
Пример записи в журнал аудита:
INSERT INTO audit_log (user_id, ip_address, query_text, execution_time, result_count)
VALUES ($uid, $ip, $query, now, $cnt);
Юридические нюансы (изменения закона от 15 января)
С 15 января 2026 г. вступила в силу поправка к Федеральному закону «О системе учёта и контроля осуждённых», согласно которой:
- Запросы по фамилии допускаются только при наличии служебного запроса (documented request) от органов правопорядка.
- Результаты поиска могут включать только анонимизированные данные (ID, фамилия, первая буква имени) без полного адреса, если запрос не сопровождается судебным решением.
- Все операции с базой данных должны вести журнал согласования, который хранится минимум 5 лет.
Для соблюдения новых требований в системе реализованы два режима выдачи:
- Стандартный режим – возвращает только ограниченный набор полей (ID, фамилия, первая буква имени).
- Полный режим – доступен после подтверждения наличия судебного решения (проверка по таблице
court_orders).
Пример проверки прав доступа:
SELECT CASE
WHEN EXISTS (
SELECT 1 FROM court_orders
WHERE user_id = $uid AND prisoner_id = p.id
) THEN 'full'
ELSE 'limited'
END AS access_level
FROM prisoners p
WHERE p.id = $pid;
Алгоритм поиска адресата по фамилии в базе проекта «РосУзник» представляет собой сочетание:
- Тщательной нормализации вводимых фамилий;
- Эффективных индексов (B‑tree, GIN, pg_trgm) для ускорения как точного, так и нечеткого поиска;
- Продуманного потокового процесса с подготовленными запросами и кешированием;
- Строгих механизмов безопасности и соответствия последним юридическим требованиям.
При правильной реализации все требования проекта – быстрота, точность, безопасность и законность – достигаются, а сотрудники правоохранительных органов получают надёжный инструмент для оперативного поиска заключённых.
Если у вас возникли вопросы по внедрению данного алгоритма или требуется адаптация под конкретные задачи, пожалуйста, свяжитесь с технической поддержкой проекта «РосУзник».