Главная » Хабрахабр » Эволюция поиска — как купить пианино в три клика

Эволюция поиска — как купить пианино в три клика

Этот способ, хоть и казался привычным, был не всегда удобен — чтобы найти товар или услугу, нужно было сделать большое количество кликов. Раньше на Авито можно было найти нужный товар, используя фильтрацию по ключевым словам или навигацию по дереву категорий. С этим нововведением в выдачу перестали попадать неподходящие, откровенно «мусорные» товары. Более года назад у нас появилась релевантность, благодаря которой поиск стал лучше, и найти товар или услугу теперь проще и удобнее даже на главной странице. Мы постепенно изменяем инфраструктуру, что позволяет нам работать над качеством поиска более интенсивно, быстрее улучшать его и выкатывать новые фичи, приносящие пользу продавцам и покупателям на Авито. И это только один из шагов, чтобы сделать поиск лучше.

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

У нас каждый день размещается более 450 тысяч объявлений, а ежемесячное количество уникальных посетителей достигает 35 миллионов, которые каждый день совершают более 140 миллионов поисковых запросов. Немного вводных: Авито — самый популярный сервис объявлений в России.

Предположим, что вам нужно пианино (ну, а почему нет?). Рассмотрим простой пример, как работал поиск более года назад. Заходим на главную страницу, набираем «пианино».

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

Это происходит, потому что у нас будет сортировка по дате размещения — а эти услуги размещают чаще всего.

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


И только после этого видим пианино, которое искали.

Получается, чтобы найти нужное объявление, были следующие возможности:

  • уточнение категории при поиске по ключевым словам,
  • сортировка по свежести и цене,
  • фильтры,
  • поиск только по названию.

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

В топе вы видите самое свежее из релевантных.

И с введением релевантности платные поднятия работают эффективнее. На Авито за дополнительную плату вы можете поднять свое объявление. Они сработают, прежде всего, если ваше объявление релевантно текстовому запросу.

Просто для большинства случаев мы сократили количество кликов до нужного объявления при поиске с главной страницы. Введение релевантности не означает, что мы полностью отказались от переходов по дереву категорий. Поиск также стал работать эффективнее и внутри категории, например, «Личные вещи» и «Бытовая техника». Если вам всё-таки нужны услуги по перевозке, хотя вы в поиске набрали просто «пианино», — переходите по дереву категорий и вы найдёте эти объявления.

Есть и другие способы его улучшить. Поиск становится удобнее для пользователей не только благодаря качеству выдачи. Например, мы ищем Ламборгини Гаярдо (да, вы любите играть на пианино и хотите ездить на Ламборгини). Один из них — проброс в категорию. С релевантностью, скорее всего, вы получите, что хотите. Чтобы добраться в категорию автомобиля определенной модели, нужно совершить два лишних клика.

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


Например, когда вы вводите слово «куртка», у вас появляются подсказки. Ещё один способ — расширяющие теги.

Если вы нажмёте «Для девочек», то сразу попадёте в категорию, где будут выбраны соответствующие фильтры. На скриншоте выше показаны подсказки: тип курток — женская, мужская, для девочек, для мальчиков. Если же спускаться по дереву категорий вручную до нужного товара, то надо совершать больше действий. Также тут появится набор дополнительных расширяющих тегов: зимняя куртка, кожаная, новая и так далее.

Всё достаточно просто. Когда я выступал с докладом на РИТ++, у слушателей был вопрос: в чем же разница между поиском по тексту и фильтрами? В этом случае поиск все равно будет находить товары и услуги, но не по заданному тексту, а по набору параметров, переданному из соответствующих фильтров выбранной категории. Найти нужное объявление можно и без текстового запроса, спустившись по дереву категорий.

Например, в категории «Автомобили» — одни фильтры, в категории «Личные вещи» — другие фильтры. Каждой категории соответствует собственный набор фильтров. То есть фильтры жестко привязаны к категории.

Если ваше объявление не содержит какой-то «запрещенки» или не является дубликатом — обычное хорошее объявление — вы его увидите в выдаче практически сразу. Для продавцов появилось важное нововведение, которое они ощущают при подаче своего объявления. Раньше же объявление всегда появлялось на сайте только через полчаса. Реально эта задержка длится около двух минут, но в редких случаях может продлеваться до 30 минут.

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

Пилим монолит

Год назад весь поисковый функционал, который работает в Авито, был в этом монолите. В Авито есть монолит на PHP. Чтобы отдать выдачу, внутри этого кода формировались соответствующие SQL-запросы в Sphinx, шла обработка, и выдача отправлялась в формате JSON или HTML. Поиск в монолите работал с четырьмя платформами: Android, iOS, мобильная версия в браузере и десктоп. Тогда пользователи видели то, что они искали.

Что у нас сейчас

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

Причины создания поискового сервиса

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

Это преимущество достаточно очевидно и в зависимости от реализации можно достигнуть тех или иных успехов. Асинхронное выполнение запросов. Наш сервис реализован на Golang, и существовал функционал, который можно было распараллелить — три запроса в Sphinx, из-за чего получились хорошие результаты.

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

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

На этой схеме уже отображен случай, когда есть монолит, сервис «Искало» и сторонний сервис «Авито Помощник».

Как работает поисковый сервис

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

Планировщик по критерию запроса с точки зрения его параметров (или если в самом запросе указан нужный агрегатор) выбирает агрегатор. Запрос поступает на планировщик. Получив от Sphinx ответ, он формирует выдачу и отдаёт ответ клиенту. Агрегатор идет в Sphinx.

Но возможен и другой вариант: какой-то другой наш сервис, внутри облака, например, «Авито Помощник», обращается в поисковый сервис. В данном случае запрос был снаружи, не из облака, в котором работает наш поисковый сервис. Вот как это работает: Этот запрос идёт уже в другой агрегатор — там другая бизнес-логика.

Как работает асинхронное выполнение запросов на агрегаторе

Профиль — это, грубо говоря, сущность, в которой можно получить объявление какого-либо типа или каким-то определенным способом. Агрегатор состоит из нескольких профилей. Агрегатор получает запрос от планировщика, при этом для известного в агрегаторе набора профилей выполняются параллельные запросы. Например, это можно объяснить через аналогию: на Авито есть «Премиум», «VIP» и обычные объявления. Профиль имеет внутри себя драйвер, который физически обращается на нижележащий уровень, в данном случае в Sphinx, но это может быть любой другой источник данных

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

Хранение поискового индекса

Нет, у нас Sphinx живёт на физических машинах. В связи с тем, что в архитектуре мы используем Kubernetes, на РИТ++ мне задали вопрос про хранение поискового индекса — хранится ли он в Kubernetes? В облаке также лежит семпл поискового индекса для среды разработки, на котором запускаются тесты, но боевой индекс туда класть нежелательно, потому что сервисы, которые работают в Kubernetes, это, прежде всего, stateless-сервисы. В Kubernetes у нас разворачивается поисковый сервис, который обрабатывает логику поиска.

Нагрузка на поисковый сервис

Нагрузка, которую он держит — это примерно 200 krpm. Сейчас этот сервис в бою, он обслуживает 100% нагрузки за небольшим исключением. Задержка: медиана — до 17 мс, 95 процентиль — до 120 мс, 99 процентиль — до 320 мс.


Итого по поисковому сервису

Профиль работает с заданным драйвером, драйвер обращается к заданному источнику данных, например, Sphinx. Поисковый сервис написан на Golang, разворачивается в Kubernetes, агрегатор асинхронно работает с несколькими профилями. Задержка: медиана — до 17 мс, 95 процентиль — до 120 мс, 99 процентиль — до 320 мс. Количество запросов, которые обслуживает наш сервис, до 200 krpm в данный момент.

Внедрение сервиса в рабочую систему

Нам нужен fallback. Проблема двойного функционала достаточно очевидна, нам приходится поддерживать две кодобазы, которые должны выполнять одну и ту же задачу. Кроме того, нам нужно управление трафиком, желательно чтобы оно было быстрым, через дашборд. Мы назвали его «Соломка» — вспомнили про «подстелить соломку».

Как работает «Соломка»

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

Тогда мы обязательно залогируем такой запрос — «Соломка» выполнит его в старом поиске. Бывают ситуации, когда какой-нибудь запрос к поисковому сервису сфейлился: например, и пока не реализован какой-то функционал внутри поискового сервиса. Клиент ничего не почувствует. Старый поиск из монолита обратится в Sphinx, и ответ уйдет клиенту.

Отдел архитектуры Авито постоянно совершенствует наше облако, тюнит, делает более надежным и производительным. Достаточно надёжная схема, и всегда интересно посмотреть, что случается на практике. На каком-то этапе были проблемы, что при обслуживании одной из нод, с достаточно большой интенсивностью из монолита шли ошибки (100 ошибок в секунду).

При этом у нас резко поднялась задержка на сервисе — на картинке ниже видно пики.

Наши посетители ничего не заметили. «Соломка» замечательно отрабатывала эту ситуацию, и итоговые HTTP ошибки были на прежнем уровне — единица ошибок на весь Авито.

Автоматизация экспериментов

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

В исходном состоянии, когда не запущено ни одного эксперимента, все посетители видят привычный поисковый функционал.

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

При анализе экспериментов мы сравниваем поведение посетителей в контрольной группе с тестовыми и на основе этого делаем выводы об успешности эксперимента.

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

  1. В поисковом сервисе выкатить соответствующий агрегатор (пусть это будет «Агрегатор 2»).
  2. Через дашборд создать эксперимент и связать одну из групп в этом эксперименте с этим агрегатором.
  3. Теперь если в поиск приходит запрос, попадающий в тестовую группу, он уходит в поисковый сервис на «Агрегатор 2».

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

Он держит 13 krps SphinxQL запросов, и на нем более 45 миллионов активных объявлений. Есть кластер серверов Sphinx 3.

0 стабилен и радует своей производительностью. Sphinx 3. Кроме того, благодаря Авито в Sphinx 3 запиливаются новые фичи, например, операция скалярного произведения векторов, а найденные баги фиксятся. Кстати, бинарники в открытом доступе.

У нас есть поисковый сервис «Искало» и сервис «Авито Помощник». Мы применяем сервисную архитектуру. Часть функционала пока осталась в монолите, но мы продолжаем работы по его распилу.

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

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

С удовольствием отвечу. Если у вас есть вопросы про работу нашего поиска, хотели бы узнать больше технических подробностей, пишите в комментариях. Кстати, недавно Андрей Дроздов выступал на Highload++ 2018 с докладом про многокритериальную оптимизацию поисковой выдачи, вот его презентация.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Перевод] IntelliCode теперь и в TypeScript/JavaScript

На Build 2018 мы анонсировали Visual Studio IntelliCode: набор AI-инструментов, которые способствуют более качественной разработке. В сотрудничестве с командой IntelliCode мы рады сообщить, что теперь IntelliCode доступен пользователям TypeScript/JavaScript через расширение IntelliCode для VS Code. Что такое IntelliCode? IntelliCode дополняет ...

Анонимный Дед Мороз 2018-2019: пост хвастовства новогодними подарками

Анонимный Дед Мороз 2018-2019 набирает обороты: каждый пятый участник отметил подарок отправленным, а несколько человек даже нашли в себе силы встать из-за компьютера и забрать посылку на почте. Давайте зайдем в комментарии и все у них разузнаем! Что же именно ...