Как стать автором
Обновить
804.26
Яндекс
Как мы делаем Яндекс

Как Яндекс перепридумал поиск для разработчиков

Время на прочтение9 мин
Количество просмотров38K

У вас бывало, что открываешь поиск, ищешь что-то по программированию и не находишь ответ? Тогда эта история для вас. 

Меня зовут Алексей Степанов, я руковожу службой исследований машинного обучения поиска Яндекса. Сегодня я расскажу непростую историю. Она про проблему, до решения которой у нас слишком долго не доходили руки. Из поста вы узнаете, почему стандартная метрика качества поиска не учитывала интересы разработчиков и как мы её улучшили. Расскажу про новую нейросеть CS YATI, обученную понимать таких же айтишников, как и мы. Ну и про грабли на нашем пути тоже расскажу, куда без них.

Этот пост основан на моём докладе с Data Fest 2022, но не во всём (мой коллега Максим Хурсанов @Maxim2207 существенно расширил историю).

К нам в команду поиска регулярно прилетают жалобы от коллег на качество ранжирования по тем или иным запросам, специфичным для разработчиков. Например, выдача по запросу [C++ list find] ещё недавно выглядела вот так: 

Слова все нужные, а ответа нет
Слова все нужные, а ответа нет

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

Исправляем метрики 

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

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

В любой непонятной ситуации заказывай пиццу
В любой непонятной ситуации заказывай пиццу

Итак, нам нужно было выяснить, какая из поисковых систем лучше отвечает на специфичные запросы про разработку. Что значит «лучше отвечает»? Предположили, что это означает более полезный документ (так мы называем страницы в интернете) в топ-1 результатов выдачи. Мы взяли около 30 программистских запросов и документы в топ-1 Яндекса и Google. Перемешали, чтобы никто не знал, какие ответы откуда. Участникам нужно было сказать, какой из двух документов лучше решает задачу из запроса, или отметить, что они одинаково полезны. Три десятка попарных оценок показали, что Яндекс как минимум не выигрывает. Статистически значимой такую выборку, конечно, не назвать, но этого было достаточно, чтобы начать копать по-крупному. 

Мы решили отмасштабировать встречу в переговорке с пиццей на всю компанию: писали посты в этушку (это такие внутренние блоги), выступили с призывом на хурале (еженедельной встрече всех сотрудников). Придумали процесс, в котором участники не только выбирали лучший ответ, но ещё и обсуждали свой выбор с другими разработчиками, если их мнения разошлись. Более того, взяли за привычку каждую пятницу созваниваться с разработчиками из других компаний. Так нам удалось за несколько недель собрать уже не 30, а 1500 попарных оценок! К сожалению, выводы остались теми же: мы отвечаем существенно хуже, чем говорят нам метрики. Почему? Чтобы понять причину, нужно немного рассказать, как именно оцениваются результаты поиска. 

С оценкой качества поиска нам помогают асессоры. Это специалисты, которые умеют отвечать на сложные смысловые вопросы и делают это лучше, чем любой ML-алгоритм. В том числе они оценивают, насколько веб-документ полезен по запросу. И наш процесс разметки не гарантировал, что на вопрос, связанный с программированием, будет отвечать асессор с опытом в программировании. Главная причина в том, что мы таких асессоров-программистов просто не наняли в достаточном количестве. 

Представьте, что вас просят оценить пользу от документа на китайском языке. Как вы будете это делать, не зная язык? Правильно, искать иероглифы из запроса в тексте документа. В ряде случаев это нормальная стратегия, но далеко не всегда. К примеру, просим неспециалиста, который никогда не программировал, оценить ответ по запросу [C++ find_if]. Он видит, что в документе вполне себе есть и C++, и find, и даже if. Этот документ будет отмечен как хороший. 

Смотрим на документ глазами неспециалиста
Смотрим на документ глазами неспециалиста

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

Как решить эту проблему? Нанять больше людей с опытом в программировании размечать запросы. Так мы и поступили. Непросто найти специалистов, которые смогут разобраться в специфических запросах и прочитать код на веб-страницах. Для этого мы проверили более тысячи кандидатов и наняли сотню лучших. Но оно того стоило: оценки новых асессоров не только были согласованы друг с другом, но и коррелировали с оценками яндексоидов! Метрика, построенная на новых оценках, на порядок лучше подсвечивала проблемы ранжирования. А это значило, что мы наконец-то починили «компас» и теперь знали, куда двигаться. Дальше наш взор устремился на модель, которая и отвечает за ранжирование документов.

Улучшаем ранжирование

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

Финальное решение о релевантности каждого документа принимает модель на базе нашей опенсорсной технологии градиентного бустинга CatBoost. На вход модели подаются разные факторы о запросе и документе, на выходе получаем предсказание релевантности документов. Факторов исторически очень много. Но с 2020 года можно однозначно выделить самый главный — тот, что выдаёт текстовая нейросеть YATI. Это огромная сеть с архитектурой Transformer, для работы которой требуются наши суперкомпьютеры. Мой коллега Саша Готманов уже подробно рассказывал о ней на Хабре. Самое главное, что тут надо знать: технология YATI стала самым большим прорывом в истории поиска с момента внедрения Матрикснета в 2009-м. Если убрать все-все остальные факторы, то качество поиска хоть и ухудшится, но не фатально. Ни один другой фактор в одиночку удержать качество не сможет.

Упрощённая схема ранжирования в поиске
Упрощённая схема ранжирования в поиске

Итак, у нас есть модели YATI и CatBoost — два ключевых компонента, от которых зависит качество поиска. Давайте улучшим их для нашей задачи! 

Мы решили обучить отдельный трансформер на базе YATI, который будет в первую очередь хорошо решать задачи по программированию. Недолго думая, назвали его CS YATI (Computer Science). Почему отдельный, а не в рамках универсального YATI? Запросов, связанных с программированием, в общем потоке очень мало. Поэтому мы можем позволить себе применять более мощную модель с бóльшим числом параметров. Кроме того, мы можем итеративно обновлять и обучать её без риска что-то поломать в основной модели.

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

Дальше мы собрали поисковые логи программистских запросов и документов, на которые пользователи кликали по этим запросам. И обучили CS YATI именно на них. Правда, не без хитростей. 

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

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

Однако некоторые документы по программированию все равно имеют слишком большой объём. Можно было бы просто брать начало текста, но это слишком грубый способ, снижающий качество. Мы начали выбирать из документов N наиболее релевантных предложений по данному запросу и уже их передавали в трансформер. Причём мера релевантности тоже оптимизировалась под программистские тексты. Финально мы зафайнтюнили CS YATI, ориентируясь на оценки асессоров с опытом в программировании.

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

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

Решили, что и тут без CS YATI не обойтись. Благодаря тем же самым асессорам-программистам мы собрали датасет и с его помощью обучили CS YATI работать ещё и в режиме классификатора запросов — отличать программистские от всех остальных. Но главную проблему это всё равно никак не решало: модель была слишком тяжёлой, чтобы применять её на каждом запросе. 

Мы воспользовались уже хорошо зарекомендовавшим себя способом — дистилляцией. Специалисты сразу поймут, о чём я, но для всех остальных скажу: дистилляция — это обучение более лёгкой нейросети «подражать» поведению более тяжёлой. Мы взяли лёгкую DSSM-подобную сеть и обучили её на результатах работы нашего трансформера CS YATI. Понятно, что качество классификации немного просело, но при этом мы сэкономили огромные вычислительные ресурсы и смогли внедрить модель в продакшен.

Схема стала выглядеть так:

Внимательный читатель в этот момент может спросить: если у нас появилась специальная версия YATI, то, может быть, нужна и специальная версия CatBoost, которая будет учитывать специфику? Мы тоже сначала посчитали это хорошей идеей. Но давайте обо всём по порядку. 

Мы сделали отдельный CS CatBoost, который, подобно CS YATI, будет обучен ранжировать запросы и документы по программированию. А ещё он будет независим от основного компонента CatBoost — значит, мы сможем обновлять и экспериментировать с ним без оглядки на остальную часть поиска. Для его обучения мы использовали уже собранные нами оценки асессоров-программистов. Звучит хорошо, не правда ли?

Но у такого решения были и минусы. Однажды мы на этом попались. В апреле наши коллеги выпустили в опенсорс технологию YDB и очень громко пошумели об этом (в том числе на Хабре). Настолько, что пользователи пошли в поиск и стали вводить там запрос [YDB]. Наша быстрая нейросетка IS CS QUERY DSSM корректно определяла его как программистский. Дальше правильно отрабатывал трансформер CS YATI. А вот CS-версия CatBoost не показывала ни одной новости о событии.

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

Мы проверили, что основная версия CatBoost, которая специально обучается на свежих запросах, хорошо справлялась с запросом [YDB]. А в обучении CS CatBoost свежих запросов не было, это и приводило к проблеме. Решение с отдельной версией CatBoost для CS, которое вначале нам показалось простым, привело к тому, что мы сломали ранжирование свежих программистских запросов. Усложнять ими обучение CS CatBoost мы не хотели, и решили, что самый простой способ — объединить две модели в одну. Сейчас это так и работает в проде.

Окей, у нас есть новые метрики, новый CS YATI, обновлённый CatBoost. Что ещё можно было сделать для улучшения качества ранжирования? Например, убедиться, что в данных для обучения моделей ранжирования есть всё, что нужно. 

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

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

Дообучение сработало. Наш поиск научился находить полезные посты в телеграме. Не просто каналы, а конкретные посты из каналов! 

Итак, мы починили метрики, улучшили ранжирование и долили новые данные. Но на этом мы не остановились.  

Добавляем быстрые ответы и сниппеты

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

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

Расширенным стал не только быстрый ответ, но и сниппет в результатах поиска. 

Ещё один интересный пример: мы доработали сниппет Гитхаба. Теперь прямо в выдаче можно увидеть рейтинг проекта, число форков и даже дату последнего коммита. Это поможет быстрее сделать правильный выбор.

А вот, например, новый сниппет, который помогает быстро найти команду для установки пакетов из npm, brew, pip, Pub и nuget — или сразу получить основную информацию о пакете.

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

Выученные уроки

  • Если метрика говорит, что мы у пользователей самые лучшие, то стоит проверить эту метрику.

  • На скорую руку можно только прод поломать (ну или свежие CS-запросы).

  • Если сделали новую метрику и по ней выиграли, то это не значит, что продукт некуда улучшать. Реальную обратную связь можно получить только от пользователей. Попробуйте наш поиск для запросов по программированию и присылайте фидбэк. Теперь поделиться отзывом просто: внизу выдачи появился пункт «Сообщить об ошибке». Вместе мы можем упростить жизнь огромному числу разработчиков. Спасибо!

Теги:
Хабы:
Всего голосов 73: ↑71 и ↓2+85
Комментарии68

Публикации

Информация

Сайт
www.ya.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия