Как реализовать точный и быстрый нечеткий поиск ФИО в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с базами данных одной из самых частых и сложных задач является сопоставление личных данных, в частности, фамилий, имен и отчеств. Ситуация осложняется тем, что пользователи могут вводить данные с ошибками, опечатками, лишними пробелами или в разной последовательности (например, сначала имя, потом фамилия). Если перед нами стоит задача сопоставить реестр из десятков тысяч строк (например, выборку в 60 000 строк) с уже существующей базой клиентов или физических лиц, стандартное точное сравнение строк окажется абсолютно бесполезным. В этой статье мы подробно и по шагам разберем, как реализовать эффективный, производительный и точный нечеткий поиск ФИО на встроенном языке 1С:Предприятие.

Методология решения проблемы нечеткого поиска

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

  1. Нормализация и предварительная очистка данных: удаление лишних символов, приведение регистра к единому стандарту, удаление дублирующихся пробелов.
  2. Сортировка токенов (слов): приведение ФИО к единому порядку следования слов (например, всегда "Фамилия Имя Отчество").
  3. Применение алгоритмов нечеткого сравнения: вычисление коэффициентов сходства с использованием метода N-грамм, расстояния Левенштейна или Яро-Винклера.
  4. Использование встроенных механизмов платформы: оптимизация процесса за счет штатного полнотекстового поиска 1С.

Шаг 1. Нормализация и очистка строк

Прежде чем приступать к сложным математическим алгоритмам сравнения, мы должны максимально упростить исходные строки. Разберем ситуацию: у нас есть строки с разным количеством пробелов между словами («Иванов Петр Иванович» и «Иванов Петр Иванович»). Чтобы привести их к одному виду, нам нужно убрать все лишние пробелы по краям и заменить множественные пробелы внутри строки на один.

Если мы используем платформу 1С:Предприятие версии 8.3.23 и выше, мы можем задействовать новый встроенный объект РегулярноеВыражение для быстрой очистки текста. Посмотрим на пример реализации такой функции:


Функция НормализоватьСтрокуФИО(Знач ВходнаяСтрока) Экспорт
    // Приводим к верхнему регистру для исключения разницы в регистре букв
    Результат = Врег(СокрЛП(ВходнаяСтрока));
    
    // Используем регулярные выражения для удаления множественных пробелов
    РегЭксп = Новый РегулярноеВыражение("\s+", "g");
    Результат = РегЭксп.Заменить(Результат, " ");
    
    Возврат Результат;
КонецФункции

Если же ваша конфигурация работает на более ранних версиях платформы 1С, где объекта РегулярноеВыражение еще нет, мы можем написать классический цикл очистки с использованием функции СтрЗаменить. Проанализируем этот вариант:


Функция НормализоватьСтрокуСтарыйМетод(Знач ВходнаяСтрока) Экспорт
    Результат = Врег(СокрЛП(ВходнаяСтрока));
    
    // Заменяем двойные пробелы на одинарные, пока они не исчезнут
    Пока СтрНайти(Результат, "  ") > 0 Цикл
        Результат = СтрЗаменить(Результат, "  ", " ");
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Шаг 2. Борьба с перестановкой слов (Сортировка токенов)

Очень часто одни и те же люди записываются в базу по-разному: «Иванов Петр Иванович» и «Петр Иванович Иванов». С точки зрения обычного посимвольного сравнения или даже расстояния Левенштейна, эти строки будут иметь критически низкий процент сходства. Чтобы решить эту проблему, мы применим метод сортировки токенов. Мы разобьем строку на отдельные слова, отсортируем их по алфавиту и соберем обратно. Таким образом, любая комбинация слов превратится в строго одинаковую последовательность «ИВАНОВ ИВАНОВИЧ ПЕТР».

Давайте посмотрим, как реализовать данный алгоритм на встроенном языке 1С:


Функция ПолучитьОтсортированныеТокены(Знач ВходнаяСтрока) Экспорт
    СтрокаОчищенная = НормализоватьСтрокуФИО(ВходнаяСтрока);
    
    // Разделяем строку на массив слов
    МассивСлов = СтрРазделить(СтрокаОчищенная, " ", Ложь);
    
    // Сортируем массив слов по алфавиту с помощью СпискаЗначений
    СписокСлов = Новый СписокЗначений;
    Для Каждого Слово Из МассивСлов Цикл
        СписокСлов.Добавить(Слово);
    КонецЦикла;
    СписокСлов.СортироватьПоЗначению();
    
    // Собираем строку обратно
    МассивОтсортированныхСлов = Новый Массив;
    Для Каждого Элемент Из СписокСлов Цикл
        МассивОтсортированныхСлов.Добавить(Элемент.Значение);
    КонецЦикла;
    
    Возврат СтрСоединить(МассивОтсортированныхСлов, " ");
EndФункции

Шаг 3. Реализация метода N-грамм (N-Gram)

Метод N-грамм является одним из самых надежных и простых в реализации способов нечеткого сравнения коротких текстовых строк, таких как ФИО. Идея заключается в том, чтобы разбить сравниваемые строки на перекрывающиеся подстроки длиной N (обычно используются биграммы, где N=2, или триграммы, где N=3). Например, для слова «ПЕТР» биграммами будут: «ПЕ», «ЕТ», «ТР».

Для оценки сходства двух строк используется коэффициент Сёренсена-Диса, который рассчитывается по формуле: 2 * (Количество общих N-грамм) / (Общее количество N-грамм в первой строке + Общее количество N-грамм во второй строке).

Рассмотрим по шагам реализацию этого механизма в 1С:


Функция ПолучитьБиграммыСтроки(Знач Строка)
    МассивБиграмм = Новый Массив;
    ДлинаСтроки = СтрДлина(Строка);
    
    Для Индекс = 1 По ДлинаСтроки - 1 Цикл
        Биграмма = Сред(Строка, Индекс, 2);
        МассивБиграмм.Добавить(Биграмма);
    КонецЦикла;
    
    Возврат МассивБиграмм;
КонецФункции

Функция РассчитатьКоэффициентСходстваНГрамм(Знач Строка1, Знач Строка2) Экспорт
    С1 = НормализоватьСтрокуФИО(Строка1);
    С2 = НормализоватьСтрокуФИО(Строка2);
    
    Если С1 = С2 Тогда
        Возврат 1.0; // Полное совпадение
    КонецЕсли;
    
    Биграммы1 = ПолучитьБиграммыСтроки(С1);
    Биграммы2 = ПолучитьБиграммыСтроки(С2);
    
    Если Биграммы1.Количество() = 0 Или Биграммы2.Количество() = 0 Тогда
        Возврат 0.0;
    КонецЕсли;
    
    // Подсчитываем количество совпадений биграмм
    КоличествоСовпадений = 0;
    // Копируем второй массив, чтобы удалять найденные биграммы для точности
    ВременныеБиграммы2 = Новый Массив;
    Для Каждого Биграмма Из Биграммы2 Цикл
        ВременныеБиграммы2.Добавить(Биграмма);
    КонецЦикла;
    
    Для Каждого Биграмма Из Биграммы1 Цикл
        ИндексНахождения = ВременныеБиграммы2.Найти(Биграмма);
        Если ИндексНахождения <> Неопределено Тогда
            КоличествоСовпадений = КоличествоСовпадений + 1;
            ВременныеБиграммы2.Удалить(ИндексНахождения);
        КонецЕсли;
    КонецЦикла;
    
    // Вычисляем коэффициент Сёренсена-Диса
    Знаменатель = Биграммы1.Количество() + Биграммы2.Количество();
    Результат = (2 * КоличествоСовпадений) / Знаменатель;
    
    Возврат Результат;
КонецФункции

Этот алгоритм работает чрезвычайно быстро и показывает превосходные результаты при наличии опечаток. Он легко находит соответствие между «Иванов Петр» и «Иванов Пётр» или «Иваноф Петр».

Шаг 4. Фонетический поиск: Решение проблемы произношения («Евгеньевич» и «Евгеньич»)

Классические текстовые расстояния бессильны, когда одно и то же имя или отчество записывается в разговорной форме или с грубыми фонетическими заменами. Хрестоматийный пример: «Евгеньевич» и «Евгеньич», «Васильевич» и «Васильич», «Ильинична» и «Ильинишна». Буквенный состав этих слов существенно отличается, но звучат они практически идентично.

Для решения этой проблемы мы можем использовать упрощенную версию алгоритма Metaphone для русского языка. Основная идея заключается в преобразовании исходного слова в фонетический код по следующим правилам:

  1. Исключить все гласные буквы, кроме первой (или заменить их на единые гласные звуки).
  2. Оглушить звонкие согласные на конце слов (Б в П, В в Ф, Г в К, Д в Т, Ж в Ш, З в С).
  3. Заменить буквосочетания, которые звучат одинаково (например, «ТЬСЯ» и «ТСЯ» заменить на «Ц», «ЧН» и «ШН» привести к единому виду).
  4. Схлопнуть идущие подряд одинаковые согласные в одну букву.

После такого преобразования «Евгеньевич» и «Евгеньич» получат одинаковый фонетический хэш-код. Сохраняя эти коды в базе данных в качестве индексируемых полей, мы сможем мгновенно сопоставлять фонетически похожие имена простым запросом, минуя сложные переборы строк.

Шаг 5. Алгоритм Яро-Винклера (Jaro-Winkler) как альтернатива Левенштейну

Хотя расстояние Левенштейна является стандартом де-факто для нечеткого сравнения строк, при работе с ФИО алгоритм Яро-Винклера показывает гораздо более качественные результаты. Разберем причину этого явления.

В именах и фамилиях людей наиболее важной является начальная часть слова (корень), так как именно в ней реже всего совершаются опечатки. Ошибки обычно концентрируются ближе к концу слова (неправильные окончания, суффиксы). Алгоритм Яро-Винклера специально разработан с учетом этого фактора: он увеличивает итоговую оценку сходства, если у двух строк совпадают первые символы (префикс). Коэффициент сходства варьируется от 0 (полное различие) до 1 (полное совпадение).

Если вам требуется максимальная точность при поиске дубликатов в базе физических лиц, обязательно используйте алгоритм Яро-Винклера для финального взвешивания результатов потенциальных совпадений.

Шаг 6. Использование встроенного полнотекстового поиска (ПТС) 1С

При обработке выборки из 60 000 строк последовательное сравнение каждой строки с каждой в цикле на встроенном языке 1С займет огромное количество времени (это алгоритмическая сложность O(N²), что потребует миллиардов итераций!). Чтобы оптимизировать этот процесс и сделать его мгновенным, мы можем задействовать штатный Полнотекстовый поиск (ПТС) платформы 1С.

ПТС работает на уровне платформы чрезвычайно эффективно и поддерживает нечеткий поиск с помощью оператора #. Мы можем настроить поиск так, чтобы платформа допускала определенное количество ошибок в словах. Рассмотрим пример поискового запроса:


ПоисковаяСтрока = "Иванов#1 Петр#1 Иванович#1";
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок(ПоисковаяСтрока, 10);
СписокПоиска.ПерваяЧасть();

Для Каждого Результат Из СписокПоиска Цикл
    // Обработка найденных объектов
    НайденныйОбъект = Результат.Значение;
    // ...
КонецЦикла;

В данном примере оператор #1 указывает системе, что при поиске каждого слова допускается ровно одна опечатка. Это позволяет быстро отсеять заведомо не подходящие записи прямо на уровне поискового индекса платформы, не нагружая процессор выполнением сложных циклов на встроенном языке.

Шаг 7. Готовые инструменты БСП (FuzzySearch)

Не стоит забывать, что в типовых конфигурациях 1С (ERP, УТ, КА, БП), построенных на базе Библиотеки Стандартных Подсистем (БСП), уже есть готовые механизмы нечеткого поиска и поиска дублей. В модулях БСП реализованы оптимизированные функции нечеткого сравнения строк.

Перед тем как писать собственное решение с нуля, проанализируйте вашу конфигурацию на наличие функции FuzzySearch или специализированных модулей поиска дубликатов (например, обработка ПоискИУдалениеДублей). Использование встроенного в БСП функционала гарантирует стабильную работу, оптимизацию под СУБД и отсутствие проблем при последующих обновлениях конфигурации.

Заключение

Мы детально проанализировали различные методы нечеткого поиска ФИО в 1С. Для достижения максимальной производительности и точности на больших объемах данных (от 60 000 строк и более) мы рекомендуем использовать гибридный подход:

  1. Проведите предварительную очистку (нормализацию) и сортировку токенов обеих сравниваемых строк.
  2. Используйте полнотекстовый поиск платформы 1С для быстрого первичного отбора потенциальных кандидатов на совпадение.
  3. К полученному узкому списку кандидатов примените алгоритм N-грамм или расстояние Яро-Винклера для окончательного расчета коэффициента сходства.

Такой подход позволит вам обрабатывать огромные массивы персональных данных за считанные секунды с гарантированно высокой точностью сопоставления.

← На главную