Как реализовать поиск по нескольким словам в произвольном порядке с помощью условия ПОДОБНО в запросе 1С?

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

При разработке механизмов поиска по наименованию номенклатуры, контрагентов или других справочников разработчики часто сталкиваются с ситуацией, когда шаблон вида %квас%благ% успешно находит позицию «Квас благодей», но при изменении порядка слов пользователем на %благ%квас% запрос не возвращает ни одной записи. Выясним причину такого поведения и подробно разберем все способы решения этой задачи в платформе 1С:Предприятие.

Почему оператор ПОДОБНО чувствителен к порядку слов

Оператор ПОДОБНО в языке запросов 1С при выполнении напрямую транслируется в конструкцию LIKE используемой СУБД. Этот оператор производит строго последовательное сопоставление символов в строке слева направо. Шаблон %благ%квас% предписывает СУБД сначала найти подстроку «благ», а затем строго после нее искать подстроку «квас». Оператор не производит синтаксический анализ текста и не воспринимает введенные пользователем слова как отдельные независимые лексемы.

Решение 1. Разбиение строки и объединение условий ПОДОБНО через логическое «И»

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

Рассмотрим, как выглядит результирующее условие в запросе:


ГДЕ
    Номенклатура.Наименование ПОДОБНО &Слово1
    И Номенклатура.Наименование ПОДОБНО &Слово2

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

  1. Разбиваем входную строку пользователя на массив отдельных слов с помощью функции СтрРазделить, игнорируя лишние пробелы.
  2. Формируем динамическую часть условия ГДЕ, обходя полученный массив в цикле.
  3. Устанавливаем параметры запроса, обрамляя каждое слово символами маски "%".

Посмотрим на пример программной реализации:


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

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

МассивУсловий = Новый Массив;
НомерСлова = 0;

Для Каждого Слово Из МассивСлов Цикл
    ТекущееСлово = СокрЛП(Слово);
    Если ПустаяСтрока(ТекущееСлово) Тогда
        Продолжить;
    КонецЕсли;
    
    НомерСлова = НомерСлова + 1;
    ИмяПараметра = "Слово" + Формат(НомерСлова, "ЧГ=0");
    
    МассивУсловий.Добавить("Номенклатура.Наименование ПОДОБНО &" + ИмяПараметра);
    Запрос.УстановитьПараметр(ИмяПараметра, "%" + ТекущееСлово + "%");
КонецЦикла;

Если МассивУсловий.Количество() > 0 Тогда
    ТекстЗапроса = ТекстЗапроса + " ГДЕ " + СтрСоединить(МассивУсловий, " И ");
КонецЕсли;

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

Ограничения производительности и индексации при использовании ПОДОБНО

Проанализируем технические нюансы работы запросов с маской процента в начале подстроки:

  1. Невозможность использования индексов: Если шаблон начинается с символа % (например, %квас%), СУБД принципиально не способна использовать стандартные B-Tree индексы по полю. Происходит полное сканирование таблицы (Table Scan или Index Scan).
  2. Нагрузка на процессор: Каждое дополнительное условие ПОДОБНО через И увеличивает время проверки каждой строки таблицы на стороне сервера базы данных. В справочниках с сотнями тысяч элементов такой запрос может вызывать ощутимые задержки и блокировки.
  3. Особенности СУБД: В зависимости от используемой платформы СУБД (MS SQL или PostgreSQL) и настроек сопоставления (collation) поиск может вести себя по-разному в плане учета регистра букв. На PostgreSQL для длинных строковых полей может потребоваться явное приведение типов с помощью ВЫРАЗИТЬ к строке ограниченной длины.

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

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

В объекте ПолнотекстовыйПоиск пробел между словами по умолчанию воспринимается как логический оператор И. Таким образом, выражения «квас благодей» и «благодей квас» найдут одни и те же элементы без ручного разбора строки.

Посмотрим на пример использования механизма:


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

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

Обратим внимание на важные особенности и требования при работе с полнотекстовым поиском:

  1. Настройка метаданных: Для справочника и его реквизитов свойство «Полнотекстовый поиск» должно находиться в значении Использовать.
  2. Асинхронность индекса: Индекс полнотекстового поиска формируется не моментально. Для его актуализации в базе должны быть настроены регламентные задания Обновление индекса ППД и Слияние индексов ППД. Элементы, созданные сразу перед поиском, не будут найдены до завершения фонового обновления.
  3. Поиск по неполным словам: В отличие от ПОДОБНО %слово%, полнотекстовый поиск по умолчанию ищет точные словоформы. Чтобы найти строку по части слова (например, «благ»), необходимо явно добавлять символ маски * в конце подстроки.

Решение 3. Штатные интерфейсные механизмы

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

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