Как программно настроить полнотекстовый поиск в динамическом списке 1С?

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

При разработке интерфейсов на платформе 1С программисты часто сталкиваются с задачей фильтрации данных в динамических списках. Ситуация существенно усложняется, когда поиск необходимо выполнить по текстовым полям с «нестабильным» форматом данных. Типичный пример — чертежные номера или артикулы (например, 254.587.57, 254. 587. 57, 254.587.57. Шайба), которые пользователи могут вводить с произвольным количеством пробелов, точек и спецсимволов.

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

Способ 1. Установка стандартного отбора с видом сравнения «Содержит»

Самый простой и очевидный способ, к которому часто прибегают разработчики — это программное добавление элемента отбора в настройки компоновки данных динамического списка. В данном случае мы используем вид сравнения Содержит. При необходимости можно использовать материал с глубоким разбором системы настроек компоновки данных динамического списка.

Рассмотрим пример реализации этого метода на практике:


&НаСервере
Процедура УстановитьОтборПоНаименованиюНаСервере()
    
    // Очищаем существующие отборы по данному полю, чтобы избежать зацикливания и дублирования
    ПолеОтбора = Новый ПолеКомпоновкиДанных("НаименованиеЧертежа");
    
    Для Каждого Элемент Из Список.Отбор.Элементы Цикл
        Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") И Элемент.ЛевоеЗначение = ПолеОтбора Тогда
            Список.Отбор.Элементы.Удалить(Элемент);
        КонецЕсли;
    КонецЦикла;

    // Добавляем новый элемент отбора
    НовыйЭлемент = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    НовыйЭлемент.ЛевоеЗначение = ПолеОтбора;
    НовыйЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Содержит;
    НовыйЭлемент.Использование = Истина;
    
    // Делаем отбор скрытым от пользователя, чтобы он не мог случайно его сломать
    НовыйЭлемент.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
    НовыйЭлемент.ПравоеЗначение = Объект.ЧертежныйНомер;

КонецПроцедуры

Преимущества метода: простота реализации, не требует предварительной подготовки данных или индексации базы данных.

Недостатки метода: критически низкая скорость работы на больших базах данных. При использовании условия Содержит платформа транслирует запрос к СУБД с оператором LIKE '%СтрокаПоиска%'. СУБД в этом случае не может использовать стандартные индексы, что приводит к полному сканированию таблицы (Full Table Scan). Даже на относительно небольших таблицах (от нескольких десятков тысяч записей) этот метод вызовет заметные задержки интерфейса.

Способ 2. Программное заполнение свойства «СтрокаПоиска» динамического списка

Начиная с версии платформы 1С 8.3.10 у разработчиков появилась возможность программно управлять стандартным полем поиска динамического списка. Свойство СтрокаПоиска (или SearchString в англоязычной нотации) позволяет симулировать ручной ввод текста пользователем в строку поиска формы.

Разберем, как применить это свойство при открытии формы:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    // Передаем искомую строку напрямую в элемент управления списком
    Элементы.Список.СтрокаПоиска = Объект.ЧертежныйНомер;
    
КонецПроцедуры

Для того чтобы данный механизм работал корректно и быстро, необходимо соблюдать важные условия:

  1. В свойствах динамического списка на форме должно быть включено использование полнотекстового поиска. Установите свойство «Использовать полнотекстовый поиск» в значение Авто или Использовать.
  2. Для динамического списка обязательно должно быть заполнено свойство «Основная таблица». Без указания основной таблицы платформа не сможет корректно построить полнотекстовый индекс для поиска.

При использовании этого свойства платформа самостоятельно анализирует доступные проиндексированные поля и мгновенно выводит результат без генерации тяжелых SQL-запросов с оператором LIKE.

Способ 3. Гибридный метод: программный полнотекстовый поиск + отбор в ДС

Если стандартного поведения строки поиска недостаточно (например, требуется тонкая предварительная обработка поискового запроса или поиск по сложным правилам), мы можем объединить возможности глобального полнотекстового поиска системы 1С и динамического списка. Для таких случаев также подойдёт инструмент для семантического поиска по справочникам 1С.

Идея метода заключается в следующем: мы программно выполняем быстрый полнотекстовый поиск по нужному регистру или справочнику, получаем массив подходящих ключей записей или ссылок, а затем накладываем на динамический список легкий отбор с видом сравнения В списке.

Реализуем данный алгоритм по шагам:


&НаСервере
Процедура ВыполнитьБыстрыйПоискНаСервере(СтрокаПоиска)
    
    // Очищаем предыдущие отборы по ключам записей
    ПолеКлючЗаписи = Новый ПолеКомпоновкиДанных("КлючЗаписи");
    Для Каждого Элемент Из Список.Отбор.Элементы Цикл
        Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") И Элемент.ЛевоеЗначение = ПолеКлючЗаписи Тогда
            Список.Отбор.Элементы.Удалить(Элемент);
        КонецЕсли;
    КонецЦикла;
    
    Если ПустаяСтрока(СтрокаПоиска) Тогда
        Возврат;
    КонецЕсли;

    РазмерПорции = 100; // Ограничим выборку разумным количеством релевантных записей
    СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок(СтрокаПоиска, РазмерПорции);
    СписокПоиска.ОбластьПоиска.Добавить(Метаданные.РегистрыСведений.БазаЧертежей);
    
    // Выполняем поиск по индексу
    СписокПоиска.ПерваяЧасть();
    
    Если СписокПоиска.ПолноеКоличество() = 0 Тогда
        // Если ничего не найдено, устанавливаем заведомо невыполнимый отбор
        НовыйЭлемент = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        НовыйЭлемент.ЛевоеЗначение = ПолеКлючЗаписи;
        НовыйЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
        НовыйЭлемент.ПравоеЗначение = Неопределено;
        Возврат;
    КонецЕсли;
    
    // Собираем ключи найденных записей регистра
    МассивКлючей = Новый Массив;
    Для Каждого Результат Из СписокПоиска Цикл
        // Для регистра сведений значением будет КлючЗаписи, для справочника - Ссылка
        МассивКлючей.Добавить(Результат.Значение);
    КонецЦикла;
    
    // Устанавливаем быстрый отбор по индексу СУБД
    НовыйЭлемент = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    НовыйЭлемент.ЛевоеЗначение = ПолеКлючЗаписи;
    НовыйЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
    НовыйЭлемент.ПравоеЗначение = МассивКлючей;
    НовыйЭлемент.Использование = Истина;

КонецПроцедуры

Этот метод работает чрезвычайно быстро, так как полнотекстовый индекс 1С оптимизирован под подобные задачи, а результирующий SQL-запрос от динамического списка выполняет выборку по конкретным ключевым полям, что занимает доли миллисекунд.

Способ 4. Предварительная нормализация данных для поиска

Если номера деталей содержат точки, дефисы и пробелы в произвольных местах (например, 12.34.56 и 12 34 56), стандартный полнотекстовый поиск может не найти совпадения из-за разницы в спецсимволах. В таких случаях лучшей практикой является нормализация данных.

Проанализируем шаги по реализации этого подхода:

  1. Создаем в регистре сведений или справочнике скрытый служебный реквизит НаименованиеДляПоиска (тип Строка).
  2. В модуле объекта при записи преобразуем исходную строку, удаляя все лишние символы.

Пример функции очистки строки:


Функция ОчиститьСтрокуДляПоиска(ИсходнаяСтрока) Экспорт
    
    // Оставляем только буквы и цифры
    ДопустимыеСимволы = "0123456789АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯabcdefghijklmnopqrstuvwxyz";
    Результат = "";
    
    Для СимволИндекс = 1 По СтрДлина(ИсходнаяСтрока) Цикл
        ТекущийСимвол = Сред(ИсходнаяСтрока, СимволИндекс, 1);
        Если Найти(ДопустимыеСимволы, НРег(ТекущийСимвол)) > 0 Тогда
            Результат = Результат + ТекущийСимвол;
        КонецЕсли;
    КонецЦикла;
    
    Возврат НРег(Результат);
    
КонецФункции

При поиске мы точно так же очищаем поисковый запрос пользователя через эту функцию и выполняем сравнение «Равно» или «Начинается с» по служебному полю НаименованиеДляПоиска. Такой индекс будет работать максимально эффективно.

Важные аспекты администрирования полнотекстового поиска

Если вы выбрали пути оптимизации с использованием полнотекстового поиска (Способ 2 или Способ 3), помните о поддержании актуальности поискового индекса. В самописных конфигурациях без Библиотеки Стандартных Подсистем (БСП) необходимо настроить регламентное задание, которое будет регулярно выполнять обновление индекса:


Процедура РегламентноеОбновлениеИндексаППД() Экспорт
    
    // Обновляем индекс немонопольно (False - частичное обновление, True - разрешить слияние)
    ПолнотекстовыйПоиск.ОбновитьИндекс(Ложь, Истина);
    
КонецПроцедуры

Рекомендуется настроить запуск этого задания с интервалом раз в несколько минут (для динамично меняющихся баз данных) или раз в день (для условно-статичных каталогов файлов и чертежей). При необходимости автоматизировать и другие регламентные задачи, включая регулярное архивирование и тестирование данных по расписанию, применяется программа для технического обслуживания 1С.

← На главную