Поиск дублей номенклатуры в 1С: как перестать заводить одинаковые товары

Оператор вбивает «Болт М16 оцинк.», система молчит, он сохраняет — и в базе появляется дубль: «Болт М16х60 оцинкованный ГОСТ 7798-70» уже существовал три года. Остатки разъезжаются, цены путаются, бухгалтерия нервничает. Знакомая боль?

Так работает штатный поиск 1С: он ищет точное вхождение подстроки. Другая форма слова, сокращение, опечатка, латинская «M» вместо кириллической «М» — и товара «нет». sku-search решает эту задачу: строит поисковый индекс и находит похожие товары даже с ошибками и сокращениями.

Что такое sku-search

Это внешний сервис полнотекстового поиска, который работает рядом с 1С: принимает JSON, отдает JSON. Вы загружаете товары, марки, документы — любые записи с любым набором полей. Сервис строит индекс и за миллисекунды находит нужное по:

  • наименованию — с опечатками и разными формами слов;
  • артикулу, штрихкоду, коду, GUID;
  • бренду, поставщику, ТН ВЭД, цвету, размеру, ГОСТу, материалу;
  • любым другим реквизитам, которые вы решите передать.

Один бинарник. Без Java, Python, Docker и GPU. Работает на слабом железе и не требует правки конфигурации 1С.

Что умеет поиск

  • Опечатки и словоформы. «блот м16 цынк», «болты», «болтом» — находит «Болт М16 оцинкованный».
  • Синонимы. «цинк» = «оцинкованный» — добавляются через API или CLI, перезапуск не нужен.
  • Неправильная раскладка и транслит. «ljvbr d lthtdyt» и «domik v derevne» находят «Домик в деревне».
  • Артикул внутри наименования. Запрос «ART-000002 болт м16» находит точное совпадение по артикулу мгновенно.
  • Любые реквизиты. Ищите по бренду, размеру, ГОСТу — с названием или без него.
  • Поиск с учетом регистра. Критично для акцизных марок, Честного ЗНАКа и серийных номеров, где AL123456789 и al123456789 — разные значения.
  • Пакетный поиск. 200 позиций накладной — один запрос, а не 200 вызовов из 1С.

Сервис прозрачный: в ответе видно score (степень совпадения) и matched_by (по чему именно нашлось). Если результат неверный, оператор нажимает «не то» — сервис записывает reject в лог обратной связи, на основе которого добавляются синонимы.

Чем отличается от штатного поиска 1С

ВозможностьВстроенный поиск 1Сsku-search
Опечаткине ловитловит
Падежи и формы словне ловитловит
Синонимынужно писать самомувстроено
Регистрозависимостьневозможно в запросахнастраивается
Поиск по 10+ реквизитамсложно и медленноиз коробки
Пакетный поискцикл в 1Содин HTTP-запрос
Нагрузка на 1Ссредняяминимальная
Зависимостинетодин бинарник

В отличие от Elasticsearch, sku-search не требует Java, отдельного сервера и администрирования: скопировали бинарник — запустили.

Как это работает под капотом

Внутри — поисковый движок Tantivy (аналог Lucene на Rust). Вместо перебора всех товаров циклом строится инвертированный индекс: по слову сразу список товаров, в которых оно есть. Отсюда миллисекунды.

Ключевые механизмы: стемминг (приведение слов к основе), fuzzy-расстояние (расстояние Левенштейна — «блот» = «болт»), edge n-граммы (поиск по началу слова), синонимы, веса полей и хранение индекса на диске — данные не теряются при перезапуске.

Скорость на реальных данных

Полный HTTP-цикл включая сериализацию JSON, 50 000 позиций:

Тип поискаСреднееp95
Точный по ID / штрихкоду~0,76 мс0,88 мс
Точный по реквизиту (brand)~0,99 мс1,19 мс
Название + реквизит~2,8 мс4,16 мс
Fuzzy по названию (2 слова)~15,9 мс45,7 мс
Fuzzy с опечаткой~18,5 мс46,8 мс

Индекс на 50 000 товаров занимает около 5 МБ. Под нагрузкой сервис выдает 242 запроса/с в конфигурации по умолчанию и до 664 запросов/с после тюнинга (отключение дорогих настроек поиска и свернутое логирование).

Как подключить

Вызов — обычный HTTP-запрос. Минимальный код в 1С:

&НаСервере
Функция НайтиПохожиеТовары(Название)
    Соединение = Новый HTTPСоединение("localhost", 8080);
    Запрос = Новый HTTPЗапрос("/find");
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    Запрос.УстановитьТелоИзСтроки(
        "{ ""items"": [ { ""name"": """ + Название + """ } ] }");
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    Возврат Ответ.ПолучитьТелоКакСтроку();
КонецФункции

Ответ — JSON с найденными товарами, score и matched_by. Если не хочется писать интеграцию с нуля — в архиве идет готовое расширение СКУПоиск.cfe для УТ 11, ERP, БП и КА (тестировалось на платформе 8.3.27).

Типичные сценарии

  1. Создание номенклатуры. Оператор вводит «болт м16 цинк» — сервис находит существующий товар, дубль не создается.
  2. Загрузка прайса поставщика. Сверка по артикулу: matched_by: exact_art вместо ручного перебора.
  3. Подбор по штрихкоду. Сканер считал код — товар найден без fuzzy и ложных совпадений.
  4. Поиск по характеристикам. «Телевизор Samsung, 55 дюймов» — name + brand + diagonal одним запросом.
  5. Пакетная сверка накладной. 200 позиций одним POST /find.
  6. Марки Честного ЗНАКа. Поиск с учетом регистра там, где 1С дала бы лишние результаты.

Быстрый старт

  1. Скачайте архив Free-версии и распакуйте.
  2. Запустите setup.sh (Linux) или setup.cmd (Windows).
  3. Запустите sku-service и откройте http://localhost:8080.
  4. Импортируйте демо-данные: sku-cli import --csv data/demo-data.csv.
  5. Введите в поиск «болт м16» или «молоко».

Развертывание — одним бинарником, в Docker или службой systemd. Данные работают полностью локально, интернет не нужен.