При разработке механизмов поиска по наименованию номенклатуры, контрагентов или других справочников разработчики часто сталкиваются с ситуацией, когда шаблон вида %квас%благ% успешно находит позицию «Квас благодей», но при изменении порядка слов пользователем на %благ%квас% запрос не возвращает ни одной записи. Выясним причину такого поведения и подробно разберем все способы решения этой задачи в платформе 1С:Предприятие.
Оператор ПОДОБНО в языке запросов 1С при выполнении напрямую транслируется в конструкцию LIKE используемой СУБД. Этот оператор производит строго последовательное сопоставление символов в строке слева направо. Шаблон %благ%квас% предписывает СУБД сначала найти подстроку «благ», а затем строго после нее искать подстроку «квас». Оператор не производит синтаксический анализ текста и не воспринимает введенные пользователем слова как отдельные независимые лексемы.
Наиболее прямолинейный и универсальный способ для языка запросов — это проверка каждого слова отдельным оператором ПОДОБНО, связанным логическим оператором И. При таком подходе расположение слов в исходной строке не имеет значения.
Рассмотрим, как выглядит результирующее условие в запросе:
ГДЕ
Номенклатура.Наименование ПОДОБНО &Слово1
И Номенклатура.Наименование ПОДОБНО &Слово2
Поскольку пользователь может ввести произвольное количество слов через пробел, текст запроса и его параметры необходимо формировать динамически. Разберем по шагам типовой программный алгоритм подготовки такого запроса:
СтрРазделить, игнорируя лишние пробелы.ГДЕ, обходя полученный массив в цикле."%".Посмотрим на пример программной реализации:
ВходнаяСтрока = "благ квас";
МассивСлов = СтрРазделить(СокрЛП(ВходнаяСтрока), " ", Ложь);
Запрос = Новый Запрос;
ТекстЗапроса =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
МассивУсловий = Новый Массив;
НомерСлова = 0;
Для Каждого Слово Из МассивСлов Цикл
ТекущееСлово = СокрЛП(Слово);
Если ПустаяСтрока(ТекущееСлово) Тогда
Продолжить;
КонецЕсли;
НомерСлова = НомерСлова + 1;
ИмяПараметра = "Слово" + Формат(НомерСлова, "ЧГ=0");
МассивУсловий.Добавить("Номенклатура.Наименование ПОДОБНО &" + ИмяПараметра);
Запрос.УстановитьПараметр(ИмяПараметра, "%" + ТекущееСлово + "%");
КонецЦикла;
Если МассивУсловий.Количество() > 0 Тогда
ТекстЗапроса = ТекстЗапроса + " ГДЕ " + СтрСоединить(МассивУсловий, " И ");
КонецЕсли;
Запрос.Текст = ТекстЗапроса;
РезультатЗапроса = Запрос.Выполнить();
Проанализируем технические нюансы работы запросов с маской процента в начале подстроки:
% (например, %квас%), СУБД принципиально не способна использовать стандартные B-Tree индексы по полю. Происходит полное сканирование таблицы (Table Scan или Index Scan).ПОДОБНО через И увеличивает время проверки каждой строки таблицы на стороне сервера базы данных. В справочниках с сотнями тысяч элементов такой запрос может вызывать ощутимые задержки и блокировки.ВЫРАЗИТЬ к строке ограниченной длины.Если требуется выполнять поиск по большим массивам данных с учетом морфологии, синонимов и в произвольном порядке слов, рекомендуется использовать полнотекстовый поиск платформы 1С.
В объекте ПолнотекстовыйПоиск пробел между словами по умолчанию воспринимается как логический оператор И. Таким образом, выражения «квас благодей» и «благодей квас» найдут одни и те же элементы без ручного разбора строки.
Посмотрим на пример использования механизма:
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок("квас благ*");
СписокПоиска.ОбластьПоиска.Добавить(Метаданные.Справочники.Номенклатура);
СписокПоиска.ПерваяЧасть();
Для Каждого ЭлементРезультата Из СписокПоиска Цикл
НайденнаяСсылка = ЭлементРезультата.Значение;
КонецЦикла;
Обратим внимание на важные особенности и требования при работе с полнотекстовым поиском:
Использовать.Обновление индекса ППД и Слияние индексов ППД. Элементы, созданные сразу перед поиском, не будут найдены до завершения фонового обновления.ПОДОБНО %слово%, полнотекстовый поиск по умолчанию ищет точные словоформы. Чтобы найти строку по части слова (например, «благ»), необходимо явно добавлять символ маски * в конце подстроки.Если поиск реализуется в интерактивном интерфейсе пользователя, часто нет необходимости писать собственный запрос:
Ввод по строке, а в свойствах элементов формы переопределить режим автоподбора, указав поиск по любой части строки.