Как эффективно реализовать нечеткий поиск и сопоставление номенклатуры при загрузке прайсов в 1С

Программист Управленческий учет Торговля и дистрибуция
← На главную

Загрузка прайс-листов сторонних поставщиков в систему 1С — это классическая задача, с которой сталкивается практически каждый программист в сфере торговли. Основная сложность заключается в том, что наименования одних и тех же товаров у разных поставщиков могут значительно отличаться. Использование стандартного полнотекстового поиска 1С не всегда дает нужный результат, а специализированные компоненты вроде FuzzySearch (или StrMatch.dll) при больших объемах данных начинают демонстрировать низкую производительность. Рассмотрим подробнее, как оптимизировать этот процесс, внедрив современные алгоритмы и правильную архитектуру данных.

Анализ проблемы производительности FuzzySearch

Стандартные компоненты нечеткого поиска часто работают по принципу прямого перебора. Если подать на вход строку, содержащую тысячи наименований номенклатуры, алгоритм будет строить матрицы сравнения для каждой пары, что приведет к квадратичному росту нагрузки. Проанализируем ситуацию: передача «громадной строки» со всеми наименованиями в COM-объект или внешнюю компоненту может вызвать не только задержки, но и критическое потребление оперативной памяти. Выясним причину замедления — чаще всего она кроется в отсутствии предварительной фильтрации и избыточности сравниваемых данных.

Решение 1: Глубокая нормализация данных (Data Cleaning)

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

  1. Удаление незначащих символов: Исключим все знаки препинания, кавычки, скобки и спецсимволы. Оставим только буквы и цифры.
  2. Приведение к нижнему регистру: Сделаем поиск нечувствительным к регистру.
  3. Обработка единиц измерения: Создадим таблицу правил замен. Например, «0.4кг» превращаем в «400г», «0,5 л» в «500мл». Это критично для сопоставления технических характеристик.
  4. Сортировка слов: Это один из самых эффективных приемов. Если в прайсе написано «Шина Nokian 17», а в базе «17 Шина Nokian», после сортировки слов по алфавиту обе строки станут идентичными: «17 Nokian Шина». Это позволит найти 100% соответствие без использования ресурсоемких алгоритмов Левенштейна.
  5. Удаление стоп-слов: Слова типа «артикул», «наличие», «акция», «шт» только мешают сравнению. Их следует вырезать программно.

Рассмотрим пример функции нормализации на языке 1С:


Функция НормализоватьСтроку(Знач ВходнаяСтрока)
    // Убираем лишние символы
    ДопустимыеСимволы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя0123456789abcdefghijklmnopqrstuvwxyz";
    Результат = "";
    ВходнаяСтрока = НРег(ВходнаяСтрока);
    
    Для Индекс = 1 По СтрДлина(ВходнаяСтрока) Цикл
        Символ = Сред(ВходнаяСтрока, Индекс, 1);
        Если Найти(ДопустимыеСимволы, Символ) > 0 Тогда
            Результат = Результат + Символ;
        Иначе
            Результат = Результат + " ";
        КонецЕсли;
    КонецЦикла;
    
    // Удаляем двойные пробелы и сортируем слова (упрощенно)
    СписокСлов = СтрРазделить(Результат, " ", Ложь);
    СписокСлов.Сортировать();
    Возврат СтрСоединить(СписокСлов, " ");
КонецФункции

Решение 2: Алгоритмическая оптимизация через хеширование (SimHash)

Вместо того чтобы сравнивать каждую строку прайса с каждой строкой справочника Номенклатура, используем идею хеширования. Посмотрим на алгоритм Charikar (SimHash). Его особенность в том, что у похожих строк получаются похожие хеши. Разберем принцип работы:

Мы заранее вычисляем хеш для всей нашей номенклатуры и храним его в отдельном реквизите или регистре. При загрузке прайса вычисляем хеш для строки поставщика. Теперь вместо тяжелого нечеткого поиска мы можем использовать быстрый поиск по диапазону хешей или вычислять «расстояние Хэмминга» между битами хеша, что выполняется на порядок быстрее, чем сравнение строк. Также хорошие результаты показывает метод N-gram (разбиение строки на фрагменты по N символов), который позволяет быстро отсеять заведомо неподходящие варианты.

Решение 3: Архитектурный подход и конвейерная обработка

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

  1. Регистр привязок: Все успешно сделанные сопоставления должны сохраняться в регистр сведений (например, НоменклатураПоставщиков). При повторной загрузке система сначала ищет точное совпадение в этом регистре.
  2. Порог схожести: Установим коэффициент (например, от 0 до 1). При значении выше 0.9 привязка происходит автоматически. От 0.7 до 0.9 — отправляется на валидацию оператору. Ниже 0.7 — считается новой позицией или требует ручного поиска.
  3. Конвейер: Организуем работу так, чтобы один оператор только подтверждал верные связки (это происходит очень быстро), а другой занимался сложными случаями поиска.

Решение 4: Использование внешних микросервисов и современных библиотек

Если производительность внутри 1С все еще не устраивает, рассмотрим вариант выноса логики вовне. Напишем небольшой HTTP-сервис на Python, используя библиотеки RapidFuzz или TheFuzz. Эти библиотеки реализованы на C++ и работают в десятки раз быстрее любой компоненты 1С. Процесс будет выглядеть так:

  1. 1С выгружает список номенклатуры (или его изменения) во внешнюю базу (например, в ElasticSearch или простую SQL-таблицу с индексами).
  2. При загрузке прайса 1С отправляет запрос к сервису.
  3. Сервис мгновенно возвращает массив наиболее вероятных кандидатов с процентом совпадения.

Посмотрим на пример использования расстояния Левенштейна (алгоритм Вагнера-Фишера), который можно реализовать даже средствами 1С для небольших списков:


Функция РасстояниеЛевенштейна(Стр1, Стр2)
    н = СтрДлина(Стр1);
    м = СтрДлина(Стр2);
    Если н = 0 Тогда Возврат м; КонецЕсли;
    Если м = 0 Тогда Возврат н; КонецЕсли;
    
    Матрица = Новый Массив(н + 1, м + 1);
    Для и = 0 По н Цикл Матрица[и][0] = и; КонецЦикла;
    Для й = 0 По м Цикл Матрица[0][й] = й; КонецЦикла;
    
    Для и = 1 По н Цикл
        Для й = 1 По м Цикл
            Стоимость = ?(Сред(Стр1, и, 1) = Сред(Стр2, й, 1), 0, 1);
            Матрица[и][й] = Мин(Матрица[и-1][й] + 1, 
                               Матрица[и][й-1] + 1, 
                               Матрица[и-1][й-1] + Стоимость);
        КонецЦикла;
    КонецЦикла;
    Возврат Матрица[н][м];
КонецФункции

Решение 5: Фонетический поиск и стемминг

Для русского языка крайне эффективны фонетические алгоритмы. Разберем ситуацию: поставщик написал «карова», а у нас «корова». Обычный поиск по подстроке не сработает. Фонетический алгоритм (адаптированный Metaphone) преобразует оба слова в одну и ту же маску «КАРАВА». Сравнение таких масок позволяет нивелировать ошибки в написании гласных и созвучных согласных. Дополнительно применим стемминг — отсечение окончаний, чтобы слова «красный», «красная», «красного» превратились в основу «красн».

Важный совет: Для ускорения работы в 1С 8.3 активно используйте ФоновыеЗадания. Разбейте прайс на несколько частей (например, по 500 строк) и запустите их обработку параллельно. Это позволит задействовать все ядра процессора сервера и сократить время ожидания в несколько раз.

Таким образом, комбинируя предварительную нормализацию, предварительный расчет хешей и кэширование результатов в регистрах 1С, можно добиться высокой скорости сопоставления даже на прайсах в десятки тысяч строк, не полагаясь только на возможности внешних компонент.

← На главную