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

Программист 1С v8.3 (Обычные формы)
← На главную

При работе с большими справочниками, такими как Номенклатура или Основные средства в конфигурации "Управление производственным предприятием" (УПП), часто возникает задача поиска элементов по конкретному слову. Стандартное использование оператора ПОДОБНО с маской %Слово% часто приводит к избыточности: например, при поиске слова "Компьютер" система находит "Компьютерный стол", "Компьютерная мышь" и другие позиции, которые не являются целевыми. В этой статье мы разберем несколько стратегий решения этой задачи, проанализируем их влияние на производительность и выберем оптимальный вариант.

Проблема использования оператора ПОДОБНО

Рассмотрим ситуацию, описанную в вопросе. Автор пытается использовать конструкцию:


|ГДЕ
|    ОсновныеСредства.Наименование ПОДОБНО "%Компьютер%"

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

Решение 1. Сложное условие с учетом пробелов и границ строки

Проанализируем ситуацию: слово "Компьютер" может находиться в четырех разных позициях в строке наименования:

  1. Наименование состоит только из одного этого слова.
  2. Слово стоит в самом начале (после него идет пробел).
  3. Слово стоит в середине (пробелы с обеих сторон).
  4. Слово стоит в самом конце (перед ним идет пробел).

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    (Номенклатура.Наименование = "Компьютер"
        ИЛИ Номенклатура.Наименование ПОДОБНО "Компьютер %"
        ИЛИ Номенклатура.Наименование ПОДОБНО "% Компьютер %"
        ИЛИ Номенклатура.Наименование ПОДОБНО "% Компьютер")

Важный нюанс: Такой подход позволяет добиться точности, но он крайне негативно сказывается на производительности. Использование символа % в начале строки поиска (как в третьем и четвертом условиях) делает невозможным использование индексов SQL-сервера. Это приводит к полному сканированию таблицы (Full Scan), что на больших базах УПП может занимать значительное время.

Решение 2. Использование Полнотекстового поиска (ППС)

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

Выясним преимущества ППС: он работает по заранее подготовленному индексу и поддерживает специальные операторы поиска. Для поиска точного слова (без учета окончаний и склонений) используется оператор "!" (восклицательный знак).

Рассмотрим пошагово алгоритм реализации через Полнотекстовый поиск:

  1. Сначала мы выполняем поиск по индексу и получаем массив найденных ссылок.
  2. Передаем этот массив в основной запрос через параметр.

Пример программного кода:


// 1. Создаем список полнотекстового поиска
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок("!Компьютер", 100);
СписокПоиска.ОбластьПоиска = Метаданные.Справочники.Номенклатура;
СписокПоиска.ПерваяЧасть();

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

// 2. Используем массив в запросе
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка В (&МассивСсылок)";

Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();

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

Решение 3. Трюк с обрамлением пробелами (Space Trick)

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


ГДЕ
    " " + Номенклатура.Наименование + " " ПОДОБНО "% Компьютер %"

В этом случае мы искусственно добавляем пробел в начало и конец проверяемой строки. Теперь слово "Компьютер" всегда будет окружено пробелами, даже если оно стояло в самом начале или конце реального наименования. Это позволяет использовать всего одну маску "% Компьютер %". Однако помните, что конкатенация строк в условии ГДЕ окончательно "убивает" производительность, так как СУБД вынуждена вычислять новое значение для каждой строки таблицы перед сравнением.

Решение 4. Постобработка результата с помощью Регулярных выражений

Иногда проще выбрать все похожие элементы запросом, а затем отфильтровать их программно, используя объект VBScript.RegExp. Этот метод особенно полезен, если нужно найти сложные паттерны слов.

Разберем пример функции для фильтрации таблицы значений:


Функция ОтфильтроватьПоТочномуСлову(ТаблицаРезультатов, ИскомоеСлово)
    
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина; // Игнорировать регистр
    RegExp.Global = Истина;
    
    // Шаблон \b означает границу слова
    RegExp.Pattern = "\b" + ИскомоеСлово + "\b";
    
    ИндексСтроки = ТаблицаРезультатов.Количество() - 1;
    Пока ИндексСтроки >= 0 Цикл
        ТекСтрока = ТаблицаРезультатов[ИндексСтроки];
        Если НЕ RegExp.Test(ТекСтрока.Наименование) Тогда
            ТаблицаРезультатов.Удалить(ТекСтрока);
        КонецЕсли;
        ИндексСтроки = ИндексСтроки - 1;
    КонецЦикла;
    
    Возврат ТаблицаРезультатов;
КонецФункции

Здесь мы используем метасимвол \b, который в регулярных выражениях обозначает границу слова (пробел, начало строки, точка, запятая и т.д.). Это самый точный способ отделения "Компьютер" от "Компьютерный".

Сравнительный анализ и рекомендации

Проанализировав все способы, мы можем сделать следующие выводы:

  1. Для небольших справочников: Можно использовать простое условие ПОДОБНО с перебором вариантов через ИЛИ. Это быстро реализуется и не требует настройки дополнительных механизмов.
  2. Для высоконагруженных систем (УПП, ERP): Единственным верным решением будет использование Полнотекстового поиска. Он обеспечивает высокую скорость работы и минимальную нагрузку на SQL-сервер.
  3. Для сложной логики (отчеты): Оптимально использовать запрос для первичного отбора "похожих" записей, а затем применять Регулярные выражения для окончательной очистки данных.

Выясним также архитектурный аспект: если поиск по конкретному виду оборудования (например, "Компьютер") требуется постоянно, рекомендуем завести в справочнике Номенклатура дополнительный реквизит (или использовать механизм "Свойства" в УПП). Заполнение свойства "Тип товара" значением "Компьютер" позволит выполнять мгновенный отбор по ссылке, что является эталоном производительности в 1С.

← На главную