Как мы стали создавать карточки товаров автоматически

    image

    В своей прошлой статье я рассказал, как мы научились автоматически сопоставлять товары по наименованиям.То есть, понимать, например, что
    Гарнитура A4Tech Bloody G501 черный
    и
    A4 G501, черно(красные) {Наушники с микрофоном, 2.2м}

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

    Это логичное продолжение развития продукта, учитывая надежную работу автоматического сопоставления товаров по наименованию. Проект по автоматизации мы выделили в отдельную компанию, а я рассказываю о проекте на примере одного из наших клиентов, и делюсь некоторыми данными клиента с его разрешения. Дальше будет небольшая вводная, а потом поговорим про алгоритмы, которые мы использовали.

    С чего мы начинали


    Исходное состояние год назад было таким: каталог на 120 тысяч товаров, из них 70 тысяч есть в наличии. После запуска автоматического сопоставления и создания товаров (о чем прошлая статья), каталог довольно быстро вырос до миллиона с небольшим товаров, из них 600-650 тысяч товаров в наличии. Но для покупки в розницу были доступны только 350 тысяч позиций, потому что у остальных не были заполнены характеристики. В зависимости от категории, чтобы товар появился в продаже, должен быть заполнен определенный процент характеристик. В некоторых категориях обязательно должно быть фото. Из 350 тысяч товаров в продаже у 120 тысяч не было изображений. Поясню, товары которые есть в наличии, но не продаются в рознице, могут продаваться в опте, там принято рассылать excel-файлы с наименованиями и ценами. Но b2b портал с карточками, несомненно, плюс. Ещё они могут размещаться на агрегаторах, где уже есть более подробная информация о товаре.

    Изображения и характеристики заполнялись в полуавтоматическом режиме. За этот год у нас появились и другие клиенты, и теперь я знаю, как построен процесс в десятке-другом относительно крупных магазинов, он более-менее стандартный. Программист, который занимается поддержкой сайта, время от времени пишет парсеры сайтов по тематике магазина. Дальше отдел контента в админке сопоставляет распаршенные товары и товары из каталога, а также категории в источнике и категории в каталоге. Потом в каждой категории для каждого свойства настраиваются соответствия, замены, конвертация единиц измерения. Карточки некоторых товаров заполняются полностью вручную. Небольшая часть товаров отдается внешнему подрядчику. Так было и у нашего клиента.

    За месяц устаревает примерно 6% от каталога, то есть, чтобы продавать на сайте 500 тысяч товаров, нужно создавать 30 тысяч карточек в месяц просто для поддержания количества на том же уровне.

    Мы решили к вопросу подойти максимально системно и максимально автоматизировать процесс создания карточек товаров.

    Где мы берем данные


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

    • файлы и API поставщиков
    • те данные, которые мы нашли в интернете

    Второй пункт подразумевает парсинг сайтов. Мы сделали инфраструктуру для создания парсеров, которая позволяет настроить парсинг сайта примерно за полчаса. Потом на этой инфраструктуре сделали около сотни парсеров, на данный момент они уже собрали информацию о 16 миллионах товаров и скачали и загрузили на CDN 35 миллионов изображений и документов (инструкций, datasheet). В качестве CDN мы используем Bunny CDN. Во время сохранения изображений мы считаем их перцептивные хэши, чтобы потом быстро находить дубликаты, ниже поговорим об этом подробнее. Идеально, если парсер сам без подсказок и настроек сможет собирать информацию о товарах на любом сайте, но это далекие планы.

    Как мы заполняем карточку товара изображениями


    Это самая простая и очевидная часть. У нас уже есть механизм сопоставления товаров по наименованию, работает быстро и точно В данном случае нас интересуют false positive срабатывания, которых около 0.1%. False negative практически не влияет на результат, потому что нет большой разницы, работаем мы в итоге с 10 или 11 источниками. Сопоставление работает со скоростью 5-6 тысяч товаров в секунду, и все наши 15 миллионов товаров сопоставляются любому каталогу меньше, чем за час. На этом можно было бы и закончить, так как после сопоставления нам известны все изображения товара. Но на практике они дублируются на разных сайтах в разных сочетаниях, и правильно будет из набора похожих картинок выбрать лучшую по качеству, а остальные оставить в качестве вариантов на случай последующего ручного редактирования карточки товара.

    Определение похожих картинок происходит в два этапа. На первом этапе, при скачивании файла, для каждого нашего изображения мы считаем перцептивный хэш. Сначала убираем однотонный фон, обрезаем поля. Потом к получившемуся изображению применяем DCT хэширование. Об этом алгоритме когда-то была статья на Хабре.

    После сопоставления для каждого товара у нас есть набор изображений с уже подсчитанными хэшами, и нам нужно разбить его на кластеры, а потом из каждого кластера выделить самое качественное изображение. Размер такого набора может изменяться от нескольких единиц до нескольких сотен единиц, типичное значение — 10 — 40. На таком размере можно применить алгоритм квадратичной сложности, основная операция — вычисление расстояния Хэмминга — производится очень быстро.

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

    1. первое изображение из набора образует первый кластер
    2. каждое следующее изображение сравнивается с первым изображением из каждого кластера
    3. если наибольший коэффициент сходства больше порогового значения, добавляем изображение в существующий кластер
    4. иначе создаем новый кластер из одного изображения

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

    Дальше есть еще один нюанс. Картинки для товара мы нашли автоматически, но, все-таки, пока что человек главнее. И если человек решил изменить очередность изображений, у него должна быть такая возможность. Но при этом идея “заморозить” карточку после ручного редактирования нам не нравится, мы хотим совершенствовать алгоритмы, находить новые изображения и автоматически улучшать карточку в дальнейшем.

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

    Как мы заполняем карточку товара свойствами


    Со свойствами дела обстоят немного сложнее, чем с картинками. В разных источниках одно и то же свойство может называться по-разному, может быть выражено в разных единицах измерения, может не иметь явного соответствия (например, HDMI: да и Интерфейсы: HDMI, USB).

    Начали с определения свойств и придумали следующие типы:

    • да / нет
    • число + единица измерения
    • единичный выбор
    • множественный выбор
    • строка

    Далее я буду использовать термины “размерность” и “единица измерения”, у них разный смысл.

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

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

    1. сопоставляем товару товары из источников по наименованию (у нас это сложный процесс, детально он описан в прошлой статье)
    2. формируем список определений свойств, которые нужно заполнить
    3. формируем список свойств из всех сопоставленных товаров
    4. сопоставляем каждому определению из пункта 2 список значений из пункта 3
    5. преобразуем список в одно значение

    Рассмотрим подробнее на примере два последних пункта. Предположим, у нас есть такое определение свойства:
    Название: “Мощность”
    Тип: число(6, 0)
    Единица измерения: Ватт
    и такой список значений (на самом деле он намного больше):
    Длина (мм): 220
    Длина: 0.22 м
    Мощность (кВт): 1,8
    Мощность: 1.8 кВт
    Номинальная мощность: 1800 Вт
    Мощность: 2 кВт
    Мощность: 1800
    Для начала, нам нужно понять, какие значения в принципе стоит рассматривать. Рабочий, но не окончательный вариант выглядит так:

    • совпадают названия (без предлогов и единиц измерения) с точностью до перестановок и окончаний
    • одно из названий включает другое (порядок слов и окончания не учитываем)
    • совпадение с учетом синонимов
    • совпадает размерность единиц измерения или значение совпадает с одним или несколькими вариантами в случае свойств с выбором.

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

    После этой операции у нас останется такой набор значений:
    Мощность (кВт): 1,8
    Мощность: 1.8 кВт
    Номинальная мощность: 1800 Вт
    Мощность: 2 кВт
    Мощность: 1800
    Мы знаем, что этот набор нужно привести к числу определенной размерности. Для каждого типа у нас независимый алгоритм. В случае с числом и единицей измерения мы делаем следующее:

    для каждого значения пытаемся определить единицу измерения. Если это не удалось, или ее размерность не совпадает с размерностью свойства, игнорируем это значение в дальнейшем. У нас останется такой набор значений:
    Мощность (кВт): 1,8
    Мощность: 1.8 кВт
    Номинальная мощность: 1800 Вт
    Мощность: 2 кВт
    Каждое из значений пытаемся конвертировать в число и привести к нужной единице измерений. Тут стараемся учесть все возможные форматы: с запятой и точкой для разделения целой и дробной части, с запятыми и пробелами для отделения тысяч, сокращения вроде тыс. и так далее. Получается следующее:
    1800 Вт
    1800 Вт
    1800 Вт
    2000 Вт
    Этот набор нужно привести к единственному значению. В случае единственного значения в наборе, используем его. Если значений больше одного и они совпадают, так даже лучше. Если значений больше одного и они не совпадают, берем наиболее часто встречающееся. Если такого нет, не заполняем свойство автоматически.

    Это был пример для свойства числового типа, для других типов последние шаги отличаются и учитывают их особенности.

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

    Как мы тестируем проект


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

    Архитектура проекта устроена таким образом, что сложные алгоритмы, насколько это возможно, разбиты на простые шаги. Для каждого шага есть критерий оптимизации и набор тестов. Упор на точность, но и скорость учитываем. По крайней мере, смотрим было-стало после каждого изменения. Каждый такой шаг напоминает задачу спортивного программирования, и у нас есть возможность сравнить результаты после каждого изменения.

    Результаты


    Более точно оценить результаты можно будет через пару месяцев работы в продакшене. На данный момент прошло меньше недели. За это время мы смогли добавить на сайт примерно 110 тысяч товаров, которые раньше не продавались из-за отсутствия свойств или изображений.
    Цель на перспективу — полностью отказаться от ручной работы для наполнения каталога. На первом этапе хорошим результатом будет уменьшить ее объем на 70%. Думаю, по результатам нескольких месяцев мы этого достигнем.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 1

      0
      на словах
      Потом описали единицы измерения и способы их конвертации. На данный момент их уже больше ста, от метров до децибел. Все они распределены по группам в зависимости от размерности, и внутри группы могут быть приведены друг к другу. Например, лошадиные силы можно конвертировать в ватты, а люмены в ньютон-метры — нельзя.

      вспомнил про библиотеку github.com/typelevel/squants

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое