При интерактивном вводе данных в поле формы часто требуется реализовать подсказку и автоподбор наиболее подходящих и похожих значений из справочника. Однако в крупных базах данных штатный полнотекстовый поиск платформы 1С нередко отключают глобально ради снижения нагрузки на сервер СУБД и оптимизации регламентных заданий. Рассмотрим, какими способами и программными инструментами можно решить задачу нечеткого и контекстного поиска похожих элементов.
Проанализируем базовый вариант решения задачи штатными средствами встроенного языка без использования сторонних сервисов. Для этого переопределим обработку автоподбора данных в модуле менеджера справочника и сформируем параметризованный запрос с условием ПОДОБНО.
Разберем по шагам, как настроить данный механизм:
Справочник.Номенклатура или Справочник.Контрагенты).ОбработкаПолученияДанныхВыбора.СтандартнаяОбработка = Ложь, чтобы перехватить формирование выпадающего списка.Посмотрим на пример реализации в коде модуля менеджера:
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка) Экспорт
// Отключаем стандартный механизм выборки
СтандартнаяОбработка = Ложь;
СтрокаПоиска = СокрЛП(Параметры.СтрокаПоиска);
Если ПустаяСтрока(СтрокаПоиска) Тогда
Возврат;
КонецЕсли;
// Инициализируем список значений для результатов
ДанныеВыбора = Новый СписокЗначений;
// Формируем шаблон: заменяем пробелы на знак процента для поиска нескольких слов
ШаблонПоиска = "%" + СтрЗаменить(СтрокаПоиска, " ", "%") + "%";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 20
| Спр.Ссылка КАК Ссылка,
| Спр.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Спр
|ГДЕ
| НЕ Спр.ЭтоГруппа
| И НЕ Спр.ПометкаУдаления
| И Спр.Наименование ПОДОБНО &ШаблонПоиска
|АВТОУПОРЯДОЧИВАНИЕ";
Запрос.УстановитьПараметр("ШаблонПоиска", ШаблонПоиска);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ДанныеВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
КонецЦикла;
КонецПроцедуры
Важный момент: использование условия ПОДОБНО '%текст%' с процентом в начале шаблона приводит к полному сканированию таблицы в СУБД (Index Scan / Full Table Scan). Чтобы не перегружать базу, обязательно ограничивайте количество возвращаемых записей конструкцией ПЕРВЫЕ и устанавливайте минимальную длину строки поиска (например, начинайте поиск только при вводе от 3 символов).
Выясним причину, по которой полнотекстовый поиск часто отключают в целом по конфигурации. Обычно это связано с размером служебных файлов индекса и тяжелыми регламентными заданиями по слиянию индексов для всех документов и регистров. Однако платформа 1С позволяет выборочно управлять полнотекстовым поиском на уровне каждого объекта метаданных.
Рассмотрим порядок настройки выборочного индексирования:
Полнотекстовый поиск и установим его в значение Использовать.Не использовать.Наименование, Артикул, ДополнительноеОписание) также проверим флаг полнотекстового поиска.ОбновлениеИндексаППД с небольшой периодичностью (например, раз в 5–10 минут) и СлияниеИндексаППД раз в сутки.В этом случае размер индекса останется минимальным, нагрузка на сервер будет незначительной, а поиск будет учитывать морфологию и основы слов.
Если похожесть должна учитывать опечатки, пропущенные буквы или перестановки символов, простого оператора ПОДОБНО будет недостаточно. В таких ситуациях разберем применение программных алгоритмов оценки расстояния между строками.
Наиболее популярным подходом является вычисление расстояния Левенштейна (минимального числа односимвольных операций вставки, удаления и замены, необходимых для превращения одной строки в другую).
Посмотрим на пример функции расчета расстояния Левенштейна на встроенном языке 1С:
Функция РасстояниеЛевенштейна(Знач Строка1, Знач Строка2) Экспорт
Длина1 = СтрДлина(Строка1);
Длина2 = СтрДлина(Строка2);
Если Длина1 = 0 Тогда
Возврат Длина2;
КонецЕсли;
Если Длина2 = 0 Тогда
Возврат Длина1;
КонецЕсли;
// Инициализируем матрицу расстояний
Матрица = Новый Массив;
Для Индекс1 = 0 По Длина1 Цикл
СтрокаМатрицы = Новый Массив;
Для Индекс2 = 0 По Длина2 Цикл
СтрокаМатрицы.Добавить(0);
КонецЦикла;
Матрица.Добавить(СтрокаМатрицы);
КонецЦикла;
Для Индекс1 = 0 По Длина1 Цикл
Матрица[Индекс1][0] = Индекс1;
КонецЦикла;
Для Индекс2 = 0 По Длина2 Цикл
Матрица[0][Индекс2] = Индекс2;
КонецЦикла;
Для Индекс1 = 1 По Длина1 Цикл
Символ1 = Сред(Строка1, Индекс1, 1);
Для Индекс2 = 1 По Длина2 Цикл
Символ2 = Сред(Строка2, Индекс2, 1);
ЦенаЗамены = ?(ВРег(Символ1) = ВРег(Символ2), 0, 1);
Матрица[Индекс1][Индекс2] = Мин(
Матрица[Индекс1 - 1][Индекс2] + 1, // Удаление
Матрица[Индекс1][Индекс2 - 1] + 1, // Вставка
Матрица[Индекс1 - 1][Индекс2 - 1] + ЦенаЗамены // Замена
);
КонецЦикла;
КонецЦикла;
Возврат Матрица[Длина1][Длина2];
КонецФункции
Для ускорения работы такого алгоритма сначала выполняют грубую фильтрацию по первым буквам через запрос 1С, а затем для полученной выборки (до 100–200 элементов) вычисляют коэффициент схожести и сортируют результаты по возрастанию расстояния.
Для мгновенного поиска по подстрокам без замедления запросов часто создают собственный индекс на триграммах внутри конфигурации:
ИндексПоискаНоменклатуры с измерениями Триграмма (Строка 3) и Ссылка (СправочникСсылка.Номенклатура).ПриЗаписи разбиваем наименование на трехбуквенные сочетания: например, для слова «Кабель» триграммами будут «каб», «абе», «бел», «ель».КОЛИЧЕСТВО(Триграмма).Подобная архитектура обеспечивает моментальный отклик базы данных даже на объемах в сотни тысяч записей, так как поиск идет по точному равенству индексированного строкового поля фиксированной длины.
Когда требуется промышленная производительность, учет морфологии, автоисправление раскладки клавиатуры и опечаток на миллионных каталогах, наиболее эффективным решением становится подключение внешнего поискового движка.
Проанализируем архитектуру интеграции:
HTTPСоединение во внешний индекс.ОбработкаПолученияДанныхВыбора платформа 1С выполняет быстрый HTTP-запрос к API поискового сервера с введенным текстом.Такой подход полностью снимает поисковую нагрузку с основной СУБД 1С и гарантирует максимально точный и быстрый результат автоподбора.