Разработчики в среде 1С часто сталкиваются с задачей реализации удобного поиска по наименованию номенклатуры, контрагентов или других справочников. Стандартное точное совпадение или простой поиск "в лоб" по началу строки часто не устраивают пользователей. Покупатель или менеджер может ввести слова в произвольном порядке, допустить опечатку или использовать сокращения. Например, при наличии в базе позиции "Тетрациклиновая мазь туба 1% 10 гр. гл. мазь" пользователь хочет находить её по запросу "тетрацик мазь 10".
В этой статье мы подробно разберем, как реализовать нестрогий поиск по нескольким словам в запросе 1С. Мы проанализируем различные подходы — от динамического построения условий в запросе до профессиональных методов оптимизации работы с СУБД.
Самый очевидный и часто используемый способ — это программное разбиение поисковой строки на отдельные слова и последующее динамическое добавление условий ПОДОБНО в текст запроса. Давайте разберем этот процесс по шагам.
Для начала нам необходимо получить массив слов из поисковой строки. Для этого мы можем использовать стандартную функцию СтрРазделить(), указав в качестве разделителя пробел. Затем мы последовательно обходим этот массив и формируем условия для секции ГДЕ нашего запроса.
Давайте посмотрим на пример оптимизированной реализации этой функции. Чтобы избежать лишних проверок на индекс элемента (первый/последний) и не загромождать код условиями добавления союза И, мы применим изящный прием: начнем строку условий с конструкции ГДЕ ИСТИНА, а все последующие условия будем просто добавлять через И.
Рассмотрим код функции формирования условий поиска:
Функция СформироватьСтрокуПоиска(ПолеПоиска)
МассивСлов = СтрРазделить(ПолеПоиска, " ", Ложь);
СтрокаПоиска = "ИСТИНА ";
Для Каждого ТекущееСлово Из МассивСлов Цикл
// Очищаем слово от возможных пробелов по краям
СловоОчищенное = СокрЛП(ТекущееСлово);
Если ЗначениеЗаполнено(СловоОчищенное) Тогда
СтрокаПоиска = СтрокаПоиска + " И Номен.Наименование ПОДОБНО ""%" + СловоОчищенное + "%""";
КонецЕсли;
КонецЦикла;
Возврат СтрокаПоиска;
КонецФункции
Теперь проанализируем, как применить данную функцию при построении основного запроса в процедуре получения данных:
&НаСервере
Процедура ОбновитьТаблицуОстатков()
Запрос = Новый Запрос;
// Формируем базовый текст запроса
БазовыйТекст =
"ВЫБРАТЬ ПЕРВЫЕ 200
| Номен.Ссылка КАК Номенклатура,
| ТоварыНаСкладахОстатки.Характеристика КАК Серия,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток,
| ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
|ИЗ
| Справочник.Номенклатура КАК Номен
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &РозничныйСклад) КАК ТоварыНаСкладахОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ВидЦены = &Розничная) КАК ЦеныНоменклатурыСрезПоследних
| ПО ТоварыНаСкладахОстатки.Характеристика = ЦеныНоменклатурыСрезПоследних.Характеристика
| ПО Номен.Ссылка = ТоварыНаСкладахОстатки.Характеристика.Владелец
|ГДЕ
| ";
// Динамически внедряем наши условия поиска
УсловияПоиска = СформироватьСтрокуПоиска(Объект.ПолеПоиска);
Запрос.Текст = БазовыйТекст + УсловияПоиска + "
|УПОРЯДОЧИТЬ ПО
| Остаток УБЫВ";
Запрос.УстановитьПараметр("Розничная", Объект.ВидЦенПродажи);
Запрос.УстановитьПараметр("РозничныйСклад", Объект.СкладПродажи);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
ОстаткиТоваров.Загрузить(РезультатЗапроса);
КонецПроцедуры
Данный алгоритм превосходно решает задачу, когда порядок слов не важен. Например, если пользователь введет "10 мазь тетрацик", запрос трансформируется в последовательность условий, соединенных через оператор логического умножения И, и целевая позиция будет успешно найдена СУБД.
Хотя первый метод прост в реализации и отлично подходит для небольших и средних баз данных, необходимо понимать его внутреннее устройство и ограничения. Использование конструкции ПОДОБНО "%слово%" (с процентом в начале шаблона) является "тяжелой" операцией для реляционных СУБД (MS SQL Server, PostgreSQL и др.).
Выясним причину падения производительности:
"слово%", СУБД могла бы быстро найти нужные строки с помощью операции поиска по индексу (Index Seek). Однако символ процента в начале "%слово%" заставляет СУБД отказаться от использования обычных индексов.Для преодоления проблем с производительностью на больших объемах данных в платформе 1С реализован механизм Полнотекстового поиска (ФТС). Многие разработчики незаслуженно считают его медленным или сложным, однако при правильной настройке он работает в десятки и сотни раз быстрее классического ПОДОБНО.
ФТС использует специальный инвертированный индекс, оптимизированный для работы с текстами. Давайте посмотрим, как программно реализовать нестрогий поиск по нескольким словам с помощью встроенного объекта ПолнотекстовыйПоиск.
Сначала мы должны убедиться, что полнотекстовый индекс актуален. В файловых базах его обновление запускают программно, в клиент-серверных — это делает регламентное задание на сервере 1С.
Рассмотрим пример функции поиска через ФТС:
Функция НайтиНоменклатуруЧерезФТС(СтрокаПоиска)
МассивСсылок = Новый Массив;
// Преобразуем строку поиска.
// Вместо "тетрацик мазь" сделаем поисковый запрос "тетрацик* И мазь*"
МассивСлов = СтрРазделить(СтрокаПоиска, " ", Ложь);
ФТСЗапрос = "";
Для Каждого Слово Из МассивСлов Цикл
СловоОчищенное = СокрЛП(Слово);
Если ЗначениеЗаполнено(СловоОчищенное) Тогда
Если ЗначениеЗаполнено(ФТСЗапрос) Тогда
ФТСЗапрос = ФТСЗапрос + " И ";
КонецЕсли;
ФТСЗапрос = ФТСЗапрос + СловоОчищенное + "*";
КонецЕсли;
КонецЦикла;
Если Не ЗначениеЗаполнено(ФТСЗапрос) Тогда
Возврат МассивСсылок;
КонецЕсли;
// Создаем список поиска и ограничиваем его выборку только справочником Номенклатура
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок(ФТСЗапрос, 200);
СписокПоиска.ОбластьПоиска.Добавить(Метаданные.Справочники.Номенклатура);
// Устанавливаем порог нечеткости (процент совпадения для поиска с опечатками)
СписокПоиска.ПорогНечеткости = 15;
// Выполняем поиск
СписокПоиска.ПерваяЧасть();
Для Каждого Результат Из СписокПоиска Цикл
МассивСсылок.Добавить(Результат.Значение);
КонецДля;
Возврат МассивСсылок;
КонецФункции
Полученный массив ссылок мы можем легко передать в качестве параметра в классический запрос 1С:
Запрос.Текст =
"ВЫБРАТЬ
| Номен.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК Номен
|ГДЕ
| Номен.Ссылка В (&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", НайденныеСсылки);
Использование полнотекстового поиска гарантирует мгновенный отклик даже на базах объемом в миллионы записей, а также предоставляет встроенные механизмы поиска с учетом синонимов, морфологии русского языка и опечаток.
Если ваша задача заключается в реализации нестрогого поиска в форме списка для интерактивной работы пользователя, то писать собственные алгоритмы разбора строки и динамические запросы чаще всего не требуется.
Начиная с версии платформы 8.3.5, стандартная строка поиска в динамических списках на управляемых формах по умолчанию реализует полнотекстовый поиск по частям слов. Если пользователь вводит в стандартное поле поиска слова через пробел, платформа автоматически разбивает строку и выполняет поиск записей, содержащих все эти фрагменты одновременно в любых индексированных полях.
Чтобы этот механизм работал максимально эффективно и быстро, соблюдайте следующие правила:
Справочник.Номенклатура). Если основная таблица не указана, платформа не сможет задействовать оптимизированные сценарии СУБД и производительность поиска резко снизится.Наименование, Артикул, Код), должно быть включено индексирование в свойствах метаданных (установите значение свойства Индексировать в Индексировать или Индексировать с доп. упорядочиванием).Для продвинутых задач сопоставления строк (например, при загрузке и автоматическом поиске аналогов из неструктурированных прайс-листов поставщиков) разработчики применяют математический подход деления слов на N-граммы (чаще всего триграммы — отрезки по 3 символа).
Рассмотрим этот принцип подробнее:
Данный метод позволяет организовать чрезвычайно толерантный к ошибкам поиск прямо внутри СУБД без использования стандартного полнотекстового индекса 1С, но требует написания дополнительной логики по расщеплению строк и хранению индекса триграмм.
Мы проанализировали основные подходы к созданию нестрогого поиска в 1С. Для небольших баз данных и простых задач отлично подойдет динамическое формирование условий ПОДОБНО, оптимизированное через конструкцию ГДЕ ИСТИНА. Для высоконагруженных систем и больших каталогов товаров единственным верным решением будет использование Полнотекстового поиска (ФТС) платформы 1С или встроенных механизмов оптимизированных Динамических списков.