Всем привет! Меня зовут Аня Власова. Я работаю ML-инженером в команде Поиска СберМаркета. В этой статье я расскажу, как устроены наши процессы: с момента, когда пользователь вводит запрос, до получения поисковой выдачи. Если вы разрабатываете поиск или просто интересуетесь темой, то наверняка сможете найти интересные инсайты для своей работы.

Коротко о том, что вас ждет:

  • Зоны ответственности команды Поиска;

  • Как мы отбираем кандидатов для отображения их в поисковой выдаче;

  • Финальное ранжирование товаров ml моделью.

7 из 10 товаров в СберМаркете добавляются в корзину из разделов, за которые отвечает отдел Поиска, так что даже маленькие изменения в наших продуктах оказывают большой и видимый эффект на бизнес. Именно поэтому мы уделяем много внимания постоянному улучшению наших решений и уже добились хороших результатов. Надеюсь, что вы почерпнете что-то новое из нашего кейса и сможете применить это в своей работе. Поехали!

Перед отправкой запроса

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

После того, как пользователь начнет вводить запрос, перед ним появятся подсказки с релевантными категориями и предложениями — ими тоже занимается наша команда.

Итак, запрос введен. Например, покупатель ищет «перец» и получает такую выдачу.

Что произошло между этими двумя событиями? Скоро узнаем, но обо всем по порядку.

Отбор кандидатов

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

Индексация

Вся информация о товарах находятся в индексе —  хранилище документов (товаров) в поисковом движке. Индекс состоит из нескольких шардов — маленьких подиндексов, которые структурируют хранилище и помогают быстрее находить нужные документы. 

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

Пример применения синонимов
Пример применения синонимов

Допустим, название нужного товара — «сок вишневый “Добрый”». Синоним слова сок – нектар. В дальнейшем, если пользователь введет в поисковик слово «нектар», система предложит покупателю и товар «сок вишневый “Добрый”», так как мы расширили поле поиска синонимом. 

Мы расширяем синонимами не только наименования товаров, но и другие поля — например, названия брендов. В их случае это в основном транслитерация, то есть русскоязычный вариант написания англоязычного бренда. Например, бренд bombbar мы также расширяем с помощью синонимов бомбар, bomb bar, бомб бар. Группы синонимов могут быть одинаковыми для всех полей, а могут применяться только в конкретном поле. 

Итак, данные готовы: название товара, нормализованная версия наименования, расширение синонимами. Далее создается обратный индекс и данные разбиваются на подиндексы для более эффективного поиска. Теперь самое время перейти к этапу получения запроса от пользователя.

Поступает запрос

Начало пайпайна — предварительное ранжирование
Начало пайпайна — предварительное ранжирование

Здесь начинается процесс выбора релевантных товаров и предварительного ранжирования, который состоит из нескольких частей:

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

  2. Затем мы осуществляем процесс текстовой обработки, который я описывала выше, но уже не для товара, а для запроса пользователя — удаляем стоп-слова, производим морфологическую нормализацию, расширяем синонимами. Причем синонимы для поисковых запросов могут отличаться от тех, которые мы применяем для названия товаров. В Elasticsearch есть два параметра: Index time — для названий на этапе индексации, и query time —  для запросов.

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

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

  5. Если и это не помогло, ослабляем запрос и снова проверяем на совпадения поисковый запрос и название товара. 

Поясню, что означает ослабление запроса. Например, пользователь ищет «кока-колу банан», а у нас такого товара — кока-колы со вкусом банана — нет. Тогда мы запускаем поиск отдельно по каждому из этих слов. Ответом на запрос покупателя будет странная смесь из кока-колы, бананов и бананосодержащих продуктов. Но нам очень важно не допускать пустой выдачи, потому что пустая выдача для поиска — самая неприятная ситуация. Нам хочется всегда показать пользователю хоть что-то, пусть и не со 100% попаданием в запрос. На момент выхода статьи этот функционал выключен, но мы находимся в поисках оптимального решения и проводим эксперименты.

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

Текстовая близость и кликбейт

Для оценки релевантности и предварительного ранжирования используем два параметра:

  •  текстовую близость — совпадение текста поискового запроса с названием товара или другими полями, которые мы также используем для поиска (чаще это бренд или категория товара). Иногда приходится использовать специфические поля, например, для аптек — поле «активное вещество». 

  • кликбейт — считаем, как часто товар по данному поисковому запросу покупали. 

Чем выше значения текстовой близости и кликбейта, тем выше товар окажется в предварительном ранжировании. Для оценки текстовой близости мы используем функцию score BM25 – более совершенную версию распространенной алгоритма TF-IDF, основное его отличие в том, что BM25 учитывает больше параметров, добавляет к ним коэффициенты и сглаживание, давая более точные результаты.

После анализа текстовой близости мы понимаем, что, например, у «Молоко “Простоквашино”» нет никакого текстового совпадения с поисковым запросом «перец», следовательно, это нерелевантный товар.  А вот названия продуктов «Перец красный», «Перец чёрный молотый» и «Перец болгарский» совпадают с поисковым запросом. Поэтому по текстовой близости мы считаем их релевантными, скор этих товаров будет сильно выше, чем у остальных остальных. 

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

Ранжирование ML-моделью

Полный пайплайн Поиска в СберМаркете
Полный пайплайн Поиска в СберМаркете

Мы используем модель градиентного бустинга XGBRanker. В него мы передаем товары с их ключевыми признаками: 

  1. Взаимодействие пользователя с товаром.

  2. Наличие и размер скидки. 

  3. Популярность (покупаемость) товара. 

Как известно, в модель ранжирования, помимо признаков и целевых меток (то есть таргета) нужно также передавать дополнительный параметр — qid. Именно по этому параметру все входные данные разбиваются на группы, в рамках которых и происходит ранжирование. Мы для обучения модели разбиваем данные по поисковым сессиям. Одна сессия — это один запрос в выбранном пользователем магазине в определенный момент времени. 

Подготовка таргета

Начнем с таргета или, другими словами, целевой метки. Мы присваиваем ему значения от 0 до 4 по следующему принципу:

  • 4 — если товар был добавлен в корзину пользователем и выкуплен. 

  • 3 — если товар был добавлен в корзину, но покупка по каким-то причинам не завершилась.

  • 2 – если товар был добавлен в корзину, но затем удален.

  • 1 — если пользователь открыл карточку товара, но не добавил его в корзину.

  • 0 —  если товар был в поисковой выдаче, а пользователь его проигнорировал, но здесь все немного сложнее.

Помимо событийных данных мы берем те товары, которые могли бы показаться пользователю по запросу, но на самом деле он их не видел. Мы отправляем в наш движок поисковый запрос, а на выходе получаем список товаров. Количество этих «нерелевантных» товаров подбираем таким образом, чтобы каждая выдача содержала 100 товаров. Такой подход был выбран, потому что он положительно сказывался на метриках качества, т.к. делал модель более устойчивой к различным входным данным.

Сбор признаков

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

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

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

Очень часто пользователи приходят к нам за выгодой, поэтому признаки, посчитанные на основе цены — наличие и размер скидки, сравнение текущей цены с исторической, также сильно влияют на качество, эти признаки рассчитываются online, то есть в режиме реального времени.

Обучение модели

После того, как таргет и признаки подготовлены, все данные отправляются в модель. Для оффлайн-тестирования используем метрики качества ранжирования NDCG@k и MAP@k.

Рейтинг важных признаков

Теперь перейдем к самым значимым признакам и обсудим первую десятку.

Целых три позиции среди первых топ-10 занимает признак — отношение добавлений товара к показам в поисковой выдаче в рамках ритейлера/региона/всего СберМаркета. Допустим, пользователь искал перцы в Metro. Смотрим, как часто определенный товар, например, перец красный добавлялся в корзину по запросу “перец” и делим его на число показов показов этого товара в других выдачах. 

Вторая группа значимых признаков — это скидки: их наличие и размер в рублях. 

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

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

Выводы

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

И пусть всегда находится именно то, что вы ищите!

Product&data команда СберМаркета ведет соцсети с новостями и анонсами. Если хочешь узнать, что под капотом высоконагруженного e-commerce, следи за нами в Telegram и на YouTube. А также слушай подкаст «Для tech и этих» от наших it-менеджеров.

Комментарии (10)


  1. freestyler8
    25.12.2023 12:19

    Сбером не пользуюсь, но вот на Маркете и в Озоне безумно не хватает точного поиска. Без всех этих изысков, а как было раньше, когда слово в кавычках просто искалось и всё. Предполагаю, что на Сбере то же самое.

    Например, я знаю артикул товара. Я его вбиваю в поиск и получаю выборку из 1000 позиций, 5 из которых содержат искомый артикул, а остальные 995 подобраны какими-то странными алгоритмами, типа "этот товар тоже красненький", "этот товар тоже начинается с буквы А" или "этот товар тоже из категории оргтехника". Иногда вообще непонятно откуда оно берется.

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

    UPD: недавно заказывал модули к фильтру, сейчас решил на их примере на всех трех площадках поискать комплект с артикулом РР5-В510-04-02.

    Сбер выдал три позиции, из них только одну верно и все три отсутствуют в продаже.

    Маркет выдал свыше 50 очень отдаленно похожих предложений, точно в соответствии с вышеприведенным описанием проблемы.

    А вот Озон приятно удивил. Выдал три позиции и все правильно. Зачет!


    1. starik-2005
      25.12.2023 12:19

      "Неистово плюсую" (с)

      Ищешь, например, карту RTX3060. Без сортировки по цене все нормусик, но как только нажал по этой самой цене - в топе что? Правильно,

      Видеокарта AGP Super S3 Trio 3D/2X 4MB

      И где связь?


    1. Sbermarket
      25.12.2023 12:19

      СберМаркет — это преимущественно про продкты питания (e-grocery), поэтому вопрос артикулов для нас менее остро стоит, чем у колег из e-com. Вероято, вы модули к фильтру искали на МегаМаркете.

      Мы как раз экспериментируем с «ослабленными запросами» (сейчас ни и вовсе отключены), чтобы много лишнего не опопадало в выдачу :)


      1. freestyler8
        25.12.2023 12:19

        Ну на мой взгляд с брендированием у Сбера беда. Вы как пару лет назад выкатили два маркетплейса с одинаковыми названиями, только один мега а другой обычный, так я до сих пор не выучил какой возит еду, а какой - барахло :-)


      1. pMalice
        25.12.2023 12:19

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

        • Если поиск по артикулу вернул 1 товар - это то что надо;

        • Ищем по началу строки (первое слово дороже второго. Если совпадение, то дальше стоп, и так на каждом шаге);

        • Ищем в первых 5 словах наименования (иначе например "Скобы для степлера" - у вас находится и степлер, т.к. в конце наименования есть приписка про размер скоб. А не должно, очевидно нужны только скобы);

        • Только в наименовании (иначе мусор из описания и т.д.);

        • Во всех полях;

        • Пробуем чинить раскладку, исправлять опечатки;

        • Еще ослабляем поиск - выкидываем слова из запроса. Сначала одно слово по очереди каждое, потом два, потом три, пока не найдем что-то. На каждом уровне смотрим максимум и минимум найденных sku. Вот тут дилемма - если оставить минимум - вроде бы более точный поиск, если максимум - вроде бы остались в запросе слова, результатов по которым много. Как лучше - не ясно, в разных ситуациях выглядит по разному, пока оставил минимум - для артикулов лучше. Жалобы на поиск всё равно есть.. Синонимы вводим постепенно, становится получше..


  1. 6095959
    25.12.2023 12:19

    Уж не знаю, "мегамаркет" вы же делаете или нет, но там многие товары только по ссылке с яндекса найти и можно. Например, долгое время был уверен, что наполнителя "Everclean" там нет, а оказалось, что есть, если "Ever clean" написать))


    1. Sbermarket
      25.12.2023 12:19

      Мы только СберМаркет делаем :)


      1. Dmitry_Dor
        25.12.2023 12:19

        Вы просто наступили на больной мозоль, и поэтому отдуваетесь за всех

        Допустим, название нужного товара — «сок вишневый “Добрый”». Синоним слова сок – нектар

        Не допустим, потому что это ни разу не синонимы, поскольку "химический состав" разный - первый 100% сок, второй - от 25% до 50% собственно сока (остальное лучше не знать).

        “Сок" - это сок, а не "нектар", и не (прости Господи) "соксодержащий напиток".

        А "Вишнёвый" - это вишнёвый, а не "вишнёво-яблочный" или "со вкусом вишни"


    1. Dmitry_Dor
      25.12.2023 12:19

      был уверен, что наполнителя "Everclean" там нет, а оказалось, что есть, если "Ever clean" написать

      Это вы еще поделиями aliexpress_russia не пользовались, вот уж где - "мы лучше знаем, что вы ищете".

      Например провести поиск mini pc intel n100 в принципе невозможно, потому что они считают, что "В запросе «mini pc intel n100» исправлена опечатка" и выдаётся результат по "mini pc intel n 100" (т.е. условно говоря все mini pc с любыми процессорами intel)

      многие товары только по ссылке с яндекса найти и можно

      Угу, но в поиске yandex/google невозможно провести сортировку по цене и(ли) количеству заказов

      ¯_(ツ)_/¯


      1. lzakharov
        25.12.2023 12:19

        По поводу невозможности выполнить поиск по запросу «mini pc intel n100» - возможность поиска по оригинальному запросу все-таки есть, достаточно нажать на ссылку в появившемся тексте «В запросе «mini pc intel n100» исправлена опечатка». Кажется обычные поисковики предоставляют аналогичный функционал.