Как программно реализовать поиск и сопоставление номенклатуры по совпадающим словам в 1С?

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

В процессе автоматизации часто возникает задача сопоставления двух перечней номенклатуры, где наименования одних и тех же позиций записаны по-разному. Например, одна строка выглядит как «Колбаса вареная Русская 200г», а в базе данных она заведена как «Колбаса "Русская", вареная 200г». Обычное прямое сравнение строк здесь не поможет. В данной статье мы разберем несколько эффективных способов решения этой задачи: от простых запросов до сложных алгоритмов нечеткого поиска.

Метод 1. Использование оператора ПОДОБНО в запросах

Самый простой, но не всегда самый быстрый способ — это использование оператора ПОДОБНО в языке запросов 1С. Если нам заранее известны ключевые слова, мы можем составить условие, которое проверит наличие каждого слова в строке наименования.

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


ТекстПоиска = "Колбаса Русская вареная";
МассивСлов = СтрРазделить(ТекстПоиска, " ", Ложь);

Запрос = Новый Запрос;
ТекстЗапроса = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ГДЕ ";

Для Индекс = 0 По МассивСлов.Количество() - 1 Цикл
    ПараметрИмя = "Слово" + Индекс;
    ТекстЗапроса = ТекстЗапроса + "Наименование ПОДОБНО &" + ПараметрИмя;
    Запрос.УстановитьПараметр(ПараметрИмя, "%" + МассивСлов[Индекс] + "%");
    
    Если Индекс < МассивСлов.Количество() - 1 Тогда
        ТекстЗапроса = ТекстЗапроса + " И ";
    КонецЕсли;
КонецЦикла;

Запрос.Текст = ТекстЗапроса;
Результат = Запрос.Выполнить();

Этот метод хорошо работает на небольших справочниках (до нескольких тысяч записей). Однако стоит помнить, что использование конструкции ПОДОБНО "%Текст%" (с процентом в начале шаблона) лишает SQL-сервер возможности использовать индексы, что приведет к полному сканированию таблицы (Table Scan) и замедлению работы при больших объемах данных.

Метод 2. Полнотекстовый поиск — профессиональный подход

Для баз данных с десятками и сотнями тысяч записей оптимальным решением является встроенный механизм полнотекстового поиска (ПП). Он работает значительно быстрее, так как использует заранее подготовленные индексы.

Проанализируем программную реализацию через объект ПолнотекстовыйПоиск. Этот механизм позволяет использовать оператор РЯДОМ, который идеально подходит для нашей задачи. Посмотрим на пример реализации:


// Формируем поисковую строку: "слово1 РЯДОМ слово2 РЯДОМ слово3"
ТекстДляПоиска = "колбаса РЯДОМ русская РЯДОМ вареная";

СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок(ТекстДляПоиска);
СписокПоиска.ОбластьПоиска.Добавить(Метаданные.Справочники.Номенклатура);
СписокПоиска.ПорогНечеткости = 15; // Позволяет учитывать небольшие опечатки

// Получаем первую порцию результатов
СписокПоиска.ПерваяЧасть();

Если СписокПоиска.Количество() > 0 Тогда
    Для Каждого ЭлементРезультата Из СписокПоиска Цикл
        Сообщить("Найден объект: " + ЭлементРезультата.Значение);
    КонецЦикла;
КонецЕсли;

Важный момент: чтобы этот код работал эффективно, в системе должно быть включено полнотекстовое индексирование, а индексы должны регулярно обновляться регламентным заданием. Если индексы не актуальны, поиск не даст результатов или найдет устаревшие данные.

Метод 3. Алгоритмическое сравнение слов (Разложение в массив)

Если мы работаем с таблицей значений в памяти или нам нужно вычислить "коэффициент схожести" двух строк, мы можем применить метод сравнения массивов слов. Выясним, как это реализовать:

  1. Очищаем обе строки от знаков препинания и лишних пробелов.
  2. Приводим обе строки к верхнему регистру.
  3. Разбиваем строки в массивы слов.
  4. Подсчитываем, сколько слов из первой строки присутствуют во второй.

Рассмотрим пример функции для вычисления процента совпадения:


Функция РассчитатьПроцентСовпадения(Строка1, Строка2)
    
    Массив1 = СтрРазделить(ВРег(Строка1), " ,.""()/", Ложь);
    Массив2 = СтрРазделить(ВРег(Строка2), " ,.""()/", Ложь);
    
    Совпадений = 0;
    Для Каждого Слово1 Из Массив1 Цикл
        Если Слово1.Длина() < 3 Тогда Продолжить; КонецЕсли; // Игнорируем предлоги
        Для Каждого Слово2 Из Массив2 Цикл
            Если Слово1 = Слово2 Тогда
                Совпадений = Совпадений + 1;
                Прервать;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    
    Возврат (Совпадений / Массив1.Количество()) * 100;
    
КонецФункции

Метод 4. Продвинутые техники и нечеткий поиск

Когда простого совпадения слов недостаточно (например, из-за опечаток "вареная" vs "варенная"), стоит рассмотреть более сложные алгоритмы:

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

2. Канонизация данных. Профессиональный подход подразумевает создание "поискового ключа". Перед сохранением номенклатуры мы можем программно создавать скрытый реквизит, в котором слова отсортированы по алфавиту и очищены от "шума" (кг, шт, грамм). Тогда строки "Колбаса Русская" и "Русская Колбаса" превратятся в идентичный ключ "КОЛБАСА РУССКАЯ", и поиск станет мгновенным через простое равенство ГДЕ ПоисковыйКлюч = &Значение.

3. Использование БСП. Не забываем, что в «Библиотеке стандартных подсистем» уже есть мощные инструменты. Например, функция СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов() или механизмы подсистемы «Поиск и удаление дублей», которые можно вызвать программно для оценки схожести объектов.

Выводы и рекомендации

Выбор метода зависит от объема данных и требований к точности:

Помните, что ни один алгоритм не гарантирует 100% точности при плохом качестве входящих данных, поэтому всегда рекомендуется выводить пользователю коэффициент схожести для окончательного подтверждения сопоставления.

← На главную