Представим типичную задачу: необходимо загрузить данные из внешнего файла, где артикул товара «спрятан» внутри строки с наименованием без каких-либо разделителей. При этом в базе данных 400 000 артикулов, а во входящем файле 100 000 строк. Обычный перебор с использованием функции СтрНайти() потребует 40 миллиардов итераций, что приведет к катастрофическим затратам времени. В этой статье мы разберем наиболее эффективные алгоритмические подходы для решения данной проблемы.
Стандартный подход Цикл по СтрокамФайла -> Цикл по АртикуламБазы -> СтрНайти(Наименование, Артикул) имеет сложность O(N * M). На больших объемах это означает, что выполнение задачи может занять десятки часов. Нам необходимо сократить количество сравнений или использовать структуры данных, которые позволяют выполнять поиск за константное или логарифмическое время.
Если ваша платформа поддерживает регулярные выражения на уровне встроенного языка, мы можем скомпилировать «мега-запрос», объединяющий множество артикулов через оператор «ИЛИ» (символ |). Рассмотрим логику этого процесса: мы разбиваем массив артикулов на группы (например, по 500-1000 штук) и для каждой группы создаем паттерн.
Проанализируем пример реализации на языке Python, который легко переносится на встроенный язык 1С с использованием новых объектов РегулярноеВыражение:
// Пример логики формирования регулярного выражения
ТекстРегулярки = "(артикул1)|(артикул2)|(артикул3)...";
РегВыражение = Новый РегулярноеВыражение(ТекстРегулярки, ПараметрыРегулярногоВыражения.Многострочный);
Для Каждого СтрокаТекста Из СписокНаименований Цикл
Результат = РегВыражение.Найти(СтрокаТекста);
Если Результат <> Неопределено Тогда
// Артикул найден
КонецЕсли;
КонецЦикла;
Важный нюанс: при использовании регулярных выражений крайне важно предварительно отсортировать артикулы по длине (от самых длинных к самым коротким), чтобы избежать ложных срабатываний (например, чтобы артикул "A123" не «перехватил» поиск артикула "A12345").
Разберем более продвинутый метод, который часто используется в поисковых движках. Суть заключается в том, чтобы разбить каждый артикул на мелкие части по 3 символа (триграммы). Рассмотрим этапы реализации:
Это позволяет мгновенно отсеять 99% артикулов, которые заведомо не могут содержаться в данной строке, и проводить детальную проверку СтрНайти() только для узкого круга кандидатов.
Проанализируем ситуацию, если данные уже загружены в СУБД. Можно использовать возможности SQL-сервера для быстрого сопоставления. Основная хитрость заключается в индексации. Поскольку стандартный индекс по LIKE '%Артикул%' не работает, мы можем создать таблицу «всех возможных подстрок» для наименований товаров.
Выясним причину эффективности этого метода: если мы разобьем каждое наименование на все возможные варианты (отрезая по одному символу слева), мы получим огромную таблицу, но по ней можно будет искать артикулы с использованием индекса по началу строки. Рассмотрим схему:
// Логика формирования таблицы подстрок
Наименование: "Арт-12345"
Подстроки:
"Арт-12345"
"рт-12345"
"т-12345"
"-12345"
"12345" // Совпадение!
При использовании INNER JOIN по условию Подстрока LIKE Артикул + '%' SQL-сервер задействует индекс, что даст колоссальный прирост скорости.
Это наиболее мощный алгоритм для одновременного поиска множества подстрок. Он строит дерево (бор) из всех ваших 400 000 артикулов. После построения дерева вы один раз проходите по строке наименования, и алгоритм «автоматически» сообщает о всех найденных артикулах.
Преимущество: скорость поиска не зависит от количества артикулов, а зависит только от общей длины текста в файле. Реализовать полноценный автомат Ахо-Корасик на 1С сложно из-за отсутствия низкоуровневой работы с памятью, но можно использовать объект Соответствие для эмуляции узлов дерева.
Прежде чем приступать к поиску любым из методов, обязательно выполним нормализацию данных. Зачастую поиск не срабатывает из-за лишних пробелов, дефисов или разного регистра. Рассмотрим шаги подготовки:
Посмотрим на рекомендации, которые помогут ускорить процесс даже при использовании простых циклов:
Соответствие работает гораздо быстрее, чем поиск в массиве или таблице значений.Подводя итог, можно сказать, что для объемов в 400 000 артикулов оптимальным решением будет либо использование внешнего скрипта на Python (библиотека flashtext или re), либо реализация триграммного фильтра внутри 1С для предварительного отсева кандидатов.