Реализация автоматического маппинга характеристик товаров с фильтрами сайта

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация автоматического маппинга характеристик товаров с фильтрами сайта
Сложная
~5 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация автоматического маппинга характеристик товаров с фильтрами сайта

Поставщики называют одни и те же характеристики по-разному: «цвет», «Цвет изделия», «color», «Colour», «RAL». На сайте — один фильтр «Цвет». Ручное приведение характеристик от десятков поставщиков к фильтрам сайта — это сотни часов работы, которые нужно автоматизировать.

Архитектура системы маппинга

Три уровня абстракции:

Характеристика поставщика  →  Атрибут сайта  →  Значение фильтра
"Цвет изделия: Красный"   →  color           →  "Красный"
"color: Red"               →  color           →  "Красный"  (с нормализацией значения)
"RAL 3020"                 →  color           →  "Красный"  (через справочник RAL)

Таблица маппинга имён атрибутов:

CREATE TABLE attribute_name_mapping (
    id               serial PRIMARY KEY,
    supplier_id      int,          -- NULL = универсальный маппинг
    supplier_name    varchar(200), -- как называет поставщик
    site_attribute   varchar(100), -- внутренний ключ атрибута
    created_at       timestamptz DEFAULT now(),
    UNIQUE (supplier_id, supplier_name)
);

Таблица маппинга значений атрибутов:

CREATE TABLE attribute_value_mapping (
    id               serial PRIMARY KEY,
    site_attribute   varchar(100),
    supplier_value   varchar(500),
    site_value       varchar(500),  -- нормализованное значение
    supplier_id      int,           -- NULL = для всех
    UNIQUE (site_attribute, supplier_value, supplier_id)
);

Алгоритм маппинга

class AttributeMapper
{
    public function mapAttribute(
        string $supplierName,
        string $supplierValue,
        ?int   $supplierId = null
    ): ?MappedAttribute {
        // Шаг 1: найти маппинг имени атрибута
        $siteAttribute = $this->resolveAttributeName($supplierName, $supplierId);
        if (!$siteAttribute) {
            $this->logUnknownAttribute($supplierName, $supplierId);
            return null;
        }

        // Шаг 2: найти маппинг значения
        $siteValue = $this->resolveAttributeValue($siteAttribute, $supplierValue, $supplierId);
        if (!$siteValue) {
            // Пробуем нормализовать без маппинга
            $siteValue = $this->autoNormalizeValue($siteAttribute, $supplierValue);
        }

        return new MappedAttribute($siteAttribute, $siteValue);
    }

    private function resolveAttributeName(string $name, ?int $supplierId): ?string
    {
        $normalized = mb_strtolower(trim($name));

        // Сначала специфичный маппинг для поставщика
        if ($supplierId) {
            $mapping = AttributeNameMapping::where([
                'supplier_id'   => $supplierId,
                'supplier_name' => $normalized,
            ])->value('site_attribute');
            if ($mapping) return $mapping;
        }

        // Затем универсальный
        return AttributeNameMapping::whereNull('supplier_id')
            ->where('supplier_name', $normalized)
            ->value('site_attribute');
    }
}

Автонормализация значений

Часть значений не требует словарного маппинга — их можно привести к стандарту автоматически:

private function autoNormalizeValue(string $attribute, string $raw): string
{
    return match ($attribute) {
        'spec_weight_kg' => $this->parseWeight($raw),
        'spec_dimensions' => $this->parseDimensions($raw),
        'spec_voltage'  => $this->parseVoltage($raw),
        default         => $this->capitalizeFirst($raw),
    };
}

private function parseWeight(string $raw): string
{
    // "2,5 кг" | "2500 г" | "2.5kg" → "2.5"
    if (preg_match('/(\d+[.,]\d+|\d+)\s*г(?:рамм)?/iu', $raw, $m)) {
        return (string) (((float) str_replace(',', '.', $m[1])) / 1000);
    }
    if (preg_match('/(\d+[.,]\d+|\d+)\s*кг/iu', $raw, $m)) {
        return str_replace(',', '.', $m[1]);
    }
    return $raw;
}

Fuzzy-маппинг новых значений

Для новых значений, которых ещё нет в маппинге, используем pg_trgm схожесть:

public function suggestValueMapping(string $attribute, string $supplierValue): array
{
    $normalized = mb_strtolower(trim($supplierValue));

    return DB::select(
        "SELECT site_value,
                similarity(lower(supplier_value), ?) AS score
         FROM attribute_value_mapping
         WHERE site_attribute = ?
           AND similarity(lower(supplier_value), ?) > 0.6
         ORDER BY score DESC
         LIMIT 5",
        [$normalized, $attribute, $normalized]
    );
}

Предлагать оператору: «Похоже, "Красн." = "Красный" (score 0.82). Создать маппинг?»

Автообучение из подтверждённых маппингов

Когда оператор принимает предложенный маппинг — он попадает в attribute_value_mapping. При следующем импорте от этого поставщика значение маппится автоматически.

public function confirmMapping(
    string $attribute,
    string $supplierValue,
    string $siteValue,
    ?int   $supplierId
): void {
    AttributeValueMapping::updateOrCreate(
        [
            'site_attribute'  => $attribute,
            'supplier_value'  => mb_strtolower(trim($supplierValue)),
            'supplier_id'     => $supplierId,
        ],
        ['site_value' => $siteValue]
    );
}

Управление фильтрами: свзяь атрибутов и фасетов

Каждый сопоставленный атрибут привязан к фильтру сайта:

CREATE TABLE filter_attributes (
    filter_id    int REFERENCES filters(id),
    attribute    varchar(100),
    display_name varchar(200),
    sort         smallint,
    PRIMARY KEY (filter_id, attribute)
);

После маппинга значения пишутся в денормализованную таблицу product_filter_values — именно по ней работает поиск с фасетной фильтрацией:

CREATE TABLE product_filter_values (
    product_id   int,
    filter_id    int,
    value        varchar(500),
    value_slug   varchar(500),
    PRIMARY KEY (product_id, filter_id, value)
);
CREATE INDEX pfv_filter_value_idx ON product_filter_values (filter_id, value_slug);

Нераспознанные атрибуты: очередь обработки

Все атрибуты, для которых не нашлось маппинга, копятся в очереди:

CREATE TABLE unmapped_attributes (
    id             serial PRIMARY KEY,
    supplier_id    int,
    attribute_name varchar(200),
    sample_values  text[],       -- до 10 примеров значений
    occurrences    int DEFAULT 1,
    first_seen_at  timestamptz DEFAULT now()
);

В админке — таблица с частотой встречаемости. Атрибуты, встречающиеся чаще всего, — первые кандидаты для создания маппинга.

Сроки реализации

  • Базовый маппинг имён атрибутов (словарь + запрос) + запись в product_filter_values3 дня
  • Автонормализация числовых значений (вес, размеры, напряжение) — +1 день
  • Fuzzy-предложения + очередь нераспознанных + admin UI — +2–3 дня
  • Полная интеграция с фасетным поиском и пересчёт при изменении маппинга — +1–2 дня