Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис

Краткая вводная: проблемы реальные, решения уже в продакшене и автоматизировали 80% ручной работы. Демо автоматического сопоставления товаров с поставщиками и конкурентами, а также создания карточек товаров можно посмотреть на https://minsk.catalog.app

Проблема первая: не знаем, у кого купить

Точнее, поставщиков порядка пяти сотен, но у каждого свой формат файла и способ его доставки — кто-то на почту шлет, кто-то на Гугл диск выкладывает, кто-то со своего сайта раздает. Еще одна проблема — товары у всех называются по-разному. Например «Гарнитура A4Tech Bloody G501 черный” и “A4 G501, черно(красные) {Наушники с микрофоном, 2.2м}» — это одно и то же.

Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис

Разберемся с разными способами доставки. Мы автоматизировали загрузку файлов с почты, по ссылке, с гугл / яндекс диска, дропбокса и некоторых других облачных сервисов, сделали несколько интеграций с API крупных поставщиков. Это закрыло 95% вариантов получения прайса. Файлы, которые присылают в условный скайп, можно загрузить вручную, мы предусмотрели интерфейс для этого.

Итак, файл получили. Теперь нужно разобраться, что в нем и чей он. И тут тот факт, что у всех разные форматы, играет нам на руку — мы можем узнать поставщика по содержимому файла. Как-то так: «ага, в шапке указан емейл victoria@worldofplastic.com — значит это ООО «Моя Оборона»». В общем, это сработало. Один раз настроили — и больше не нужно указывать поставщика при загрузке файла.

Поставщика узнали, файл разобрали, получили список товаров с ценами, временем доставки и прочими атрибутами. Отфильтровали, если нужно (например, убрали поврежденные товары).

Нужно найти товарам из прайса поставщика соответствие в каталоге. И тут все сложно, но не в том смысле, что мы это не решили, а в том смысле, что описание этого решения с упрощениями и допущениями заняло несколько страниц. Если вам интересны технические подробности, то они есть в статье на хабре https://habr.com/ru/post/456604/.

Кратко результат: работает быстро, обрабатывает 20-40 тысяч товаров в секунду. Ошибок примерно 0.1%, автоматически обрабатывается 80%. Результат зависит от входных данных и на некоторых категориях товаров хуже, на некоторых лучше.

Автоматические сопоставления можно выборочно контролировать вручную, для этого мы сделали удобный интерфейс, где есть релевантные варианты с фотографиями.

Итог: все цены поставщиков доступны на карточке товара.

А если товара нет в каталоге, но на него появился заказ? На этот случай сделали поиск по всем сырым данным поставщиков. На 3 миллионах предложений работает меньше секунды.

Проблема вторая: не знаем цены конкурентов

У нас уже есть алгоритм сопоставления. Осталось дать ему данные. Цены парсим в интернете, берем на площадках (тот же Озон дает минимальные и рекомендованные цены), покупаем у ребят, которые специализируются на парсинге. Тут стоит оговориться, что то, что мы парсим сами — доступно всем, то, что конкретный магазин берет у сторонних сервисов — доступно только ему.

Итог: все цены конкурентов доступны на карточке товара.

Проблема третья: поставщики ошибаются

Бывает так, что цена на ноутбук в прайсе поставщика равна условным 500 рублям. Но ноутбук не может стоить 500 рублей, и если пропустить эту цену, это чревато сбоем во всем процессе формирования цен и обработки заказов. И последствия тем больше, чем позднее ошибка найдена. Отменить оплаченный онлайн заказ клиента и вернуть ему деньги — гораздо дороже в совокупности, чем найти ошибку на этапе обработки прайса.

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

Итог: несколько сотен предложений находятся на карантине. Примерно треть из них — явно неадекватные (ноутбук не может стоить 500 рублей). Про остальные сложно сказать, например, может стоить блокнот 5 рублей или нет — непонятно. Вручную карантинные цены просматриваются редко, false positive ошибки практически не оказывают влияния на процесс работы. Но зато стало значительно меньше отмен заказов из-за ошибок поставщика.

Проблема четветрая: важна не только цена, но и время поставки

Ситуация: у поставщика из другого города товар станет доступным 24 числа. Машина забирает товары с его склада по вторникам. Когда магазин сможет доставить товар клиенту?

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

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

Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис

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

Проблема пятая: редко и непрозрачно формируем цены

До того, как мы начали что-то делать, цены формировались один раз в сутки (один раз розничные и один раз оптовые), занималась этим 1С, и занимало это до восьми часов. Второй неприятный момент — что происходило это по одной ей известным правилам, т.е. эти правила были вшиты в код, и не было возможности их хоть как-то визуализировать.

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

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

Пришли к тому, что пользователи сами создают профили ценообразования. В профиле у нас есть возможность настроить разные диапазоны наценок в зависимости от цены товара у поставщика, категории, производителя, поставщика. Еще есть возможность указать, с какими поставщиками по какой категории или производителю работаем, а с какими — нет, кого из конкурентов учитываем. Учитываем и время доставки, и приоритет складских товаров, и МРЦ — есть возможность все это настроить.

Итог: То, что 1С считала восемь часов, мы считаем две минуты. Потом, конечно, данных прибавилось. Профилей ценообразования стало три десятка вместо двух. У менеджеров появился инструмент, и они нашли ему применение.

Проблема шестая: товар есть, карточки товара нет

Такой товар можно продавать оптом, и то базовые характеристики неплохо знать. А для продажи в розницу нужны описание, фото, характеристики.

Но у нас уже есть алгоритм сопоставления и парсеры — полдела сделано. Теперь нужно парсить не только цены, но еще и характеристики и фото. И сделать сопоставление свойств. И фото на CDN загрузить. Интерфейс для проверки и исправлений сделать. Фильтр по характеристикам ещё. Оказалось, очень много всего нужно.

На этот пункт у нас ушло полгода.

Парсеры — относительно простая и понятная часть. Сделали парсеры для двух сотен сайтов, собираем характеристики, фото без водяных знаков, описания. Товары складываем в базу, для фото делаем превью, считаем перцептивные хэши (они нам еще понадобятся), загружаем на CDN.

Дальше сопоставление. У нас есть 30 миллионов товаров, их нужно сопоставить каталогу. Это мы тоже можем, алгоритм работает быстро и на сопоставление нужно минут сорок.

После этого этапа мы знаем, что товар из каталога есть, предположим, на 11 других сайтах. По сути, есть условно 11 словарей, название характеристики — значение, 3 текстовых описания товара и 8 списков с фото. Такие числа получаются потому что не везде есть все сразу. Теперь из этого нужно собрать карточку товара.

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

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

Со свойствами дела обстоят намного сложнее, чем с картинками. Для начала, нам нужна модель, в соответствии с которой мы будем делать карточку товара. Эта модель распространяется на всю категорию. При этом свойства наследуются по иерархии. То есть, «вес” можно создать на верхнем уровне, и он применится к вообще всем товарам, а «количество упаковок» можно создать на уровне “мебель».

Есть возможность задать значения по-умолчанию, например, НДС 20% на верхнем уровне и 10% на уровне медицинской техники. Есть возможность ограничивать эти значения по брендам.

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

«Итак, на сайте-источнике у 80% газонокосилок есть свойство мощность. Все значения содержат число и строку кВт. Значит, это свойство числового типа, размерность — мощность, единица измерения — киловатт. У 85% газонокосилок есть свойство тип. Вариантов значения всего два — электрическая или бензиновая. Значит, это свойство-перечисление с двумя допустимыми вариантами».

Естественно, все эти определения можно создавать и редактировать вручную. Бывает, что мы ошибаемся, и, например, «л/с» принимаем за литры в секунду. В бойлерах это правильно, а в принтерах — это листы в секунду.

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

Мы научились искать синонимичные свойства, понимать и конвертировать единицы измерений, принимать решения в случае противоречий в источниках. О том, как это работает на уровне алгоритмов, я писал на хабр https://habr.com/ru/post/499684/. Сделали фильтры по значениям.

Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис

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

Проблема седьмая: товар пропадает из наличия

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

Так мы пришли к алгоритму поиска похожих товаров. По идее, все данные у нас уже есть: цены знаем, характеристики заполнили.

Для подбора похожих товаров нам нужно решить следующие задачи:

  • Назначить характеристикам веса. Для телевизора размер диагонали очень важен, количество USB-портов — менее важно.
  • Определить область значений каждой характеристики, а на ней задать функцию расстояния между значениями.
  • Определиться со стратегией обработки случаев, когда для одного товара характеристика известна, а для другого — нет.
  • Имея расстояния между значениями всех характеристик, вычислить расстояние между товарами.
  • Подумать над производительностью, вычисление всех пар расстояний имеет квадратичную сложность. И если вычисление 50 миллионов расстояний для 10 тысяч товаров не кажется большой проблемой, то 50 миллиардов для 300 тысяч — уже много.

О том, как это сделать алгоритмически, я писал на хабр https://habr.com/ru/post/530170/. Что удивительно, это сработало.

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

Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис
Решаем проблемы интернет-магазина, получаем 700 заказов с Яндекса в сутки, делаем публичный сервис

Проблема восьмая: не знаем, что продвигать

Мы сформировали цены на 500 тысяч позиций. В продвижение каких товаров стоит вкладываться и на каких условиях, а в каких — нет?

Что же, у нас есть все исходные данные, чтобы это оценить, осталось определиться со стратегией такой оценки.

Выбрали такую стратегию: позволим менеджерам сегментировать товары, в зависимости от цены, маржинальности, времени доставки, разнице в цене с конкурентами. Условно так: товары, которые есть на складе, цена которых превышает 5 тысяч рублей и меньше 50 тысяч рублей, маржинальность которых больше 30% и которые не дороже, чем у конкурентов — продвигаем в первую очередь. Товары, которые под заказ от 20 дней и дороже, чем у конкурентов — продвигать не нужно.

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

Итог: продвижение делается не вслепую, продвигаются только те предложения, для которых это выгодно.

Проблема девятая: маркетплейсы наносят ответный удар

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

В общем, нужно эффективно управлять карточками, ценами, остатками на площадках Яндекс Маркет, Озон и некоторых других. Эта проблема еще в процессе решения, мы уже научились автоматически создавать карточки на Яндекс Маркете, управлять ценами и остатками на Яндекс Маркете и Озоне. Автоматическое создание карточек на Озоне — в процессе разработки.

Итог: количество заказов с Яндекса увеличилось в разы. С Озона — мы еще посмотрим.

Некоторые выводы

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

К сожалению, пустой аккаунт не даст никакой информации о возможностях сервиса, нужны данные, и желательно, чем больше, тем лучше. И желательно, чтобы случайный пользователь не мог испортить демо-данные. К тому же интерфейс нашего инструмента пока не проходит коридорный тест. Поэтому для демонстрации возможностей сервиса мы сделали небольшой демо-сайт, он работает в автоматическом режиме. То есть, карточки товаров создаются автоматически, товары с разных сайтов тоже сопоставляются автоматически. Сайт не показывает всех возможностей, но дает возможность оценить качество создания карточек и сопоставления товаров. Посмотреть можно на https://minsk.catalog.app (хостинг стоит 3 евро в месяц, интересно, с какой нагрузкой сайт справится).

99
4 комментария

Красава. Почти решил всю гемора интернет магазина.

1

Ох, как приятно, что эту задачу кто-то адекватно решил. 
Как-то раз (лет 5 назад) мы с коллегами застряли на уровне "автоматизируй обработку сотен прайсов, которые приходят в почту и каждый раз отличаются". Поняли что своими тогдашними силами (2 программиста) - не справимся и, в итоге, пошли по пути аренды похожего решения. 
Успехов! Полезное дело делаете :)

1

Статью не читал (уж простите). Но мне очень понравился заголовок. Надо добавить: "Боремся по ночам с преступнсотью" ) Не из-за того, что я считаю вас плохими специалистами. Просто забавно сформулирован заголовок

1

Есть у нас что-то общее с бэтмэном, да.