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

В отделе маршрутизации Glovo нам поручено разработать модели машинного обучения (ML), которые оценивают продолжительность каждого значимого этапа заказа Glovo. Например, у нас есть модели для прогнозирования времени подготовки ресторана, времени в пути курьера, общего времени доставки и прочего. Эти прогнозы затем используются для различных вариантов использования: для повышения эффективности наших операций - мы используем наши модели машинного обучения, чтобы выбрать, какой курьер и магазин доставит заказ - и для улучшения взаимодействия с нашими партнерами и клиентами: когда мы уведомляем партнера о новый заказ? какие ETA мы показываем нашим клиентам и партнерам? -.

В Routing мы используем машинное обучение для оптимизации наших операций и предоставления точных оценок партнерам и клиентам

Что-то, что действительно хорошо сработало для нашей команды, - это сочетание инженеров-программистов (SWE), аналитиков данных (DA) и специалистов по данным (DS). Поскольку модели, над которыми мы работаем, критически важны для нашего бизнеса, их необходимо развертывать с очень низкой задержкой и высокой доступностью, масштабируясь для обработки миллионов прогнозов каждую минуту. Для достижения этой цели решающее значение имеет многопрофильная команда.

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

Моделирование поведения наших партнеров и курьеров.

Первые разработанные нами модели в значительной степени основывались на функциях, отражающих исторические свойства. Например, мы рассчитываем среднее время подготовки ресторана за последние несколько недель; средняя скорость курьера, количество заказов, обработанных каждым партнером в прошлом месяце, и т. д. Эти агрегированные данные предоставляют ценную информацию для наших моделей машинного обучения, но не отражают то, что на самом деле происходит в настоящее время. Например, один из наших партнеров мог подготовить заказ за 8 минут. Но если что-то изменится в любой день - скажем, например, что ФК «Барселона» играет с «Реал Мадрид», а их ресторан полон клиентов и заказов Glovo - тогда мы можем ожидать более длительного времени на подготовку.

Заказы могут быстро накапливаться во время Эль-Классико

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

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

Первое реализованное нами решение основывалось на SQL-запросах для вычисления этих агрегатов в режиме, близком к реальному времени, и их кэширования с коротким временем существования (10 минут). Всякий раз, когда нам требовалась функция, мы проверяли, рассчитывалась ли она за последние 10 минут. Если так, мы бы использовали это значение; в противном случае мы бы выполнили SQL-запрос для его вычисления, а затем кэшировали бы его. Обратите внимание, что это означает, что каждая функция будет рассчитана в настоящее время или до 10 минут назад.

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

Это решение было самым быстрым способом начать, но имело несколько недостатков: 1) чтобы избежать конфликтов в нашей БД, мы могли вычислять эти функции только каждые 10 минут, поэтому они не были такими свежими и точными, как мы хотели 2) SQL можно использовать для простые агрегации, но реализация и поддержка более сложных преобразований может быть болезненной и 3) мы дублировали логику на разных языках программирования, наши обучение и логический вывод иногда не совпадали.

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

  • Каждый раз, когда происходит соответствующее бизнес-событие, мы публикуем подробное событие в AWS Kinesis. Например, у нас могут быть события OrderCreated и OrderPicked с соответствующими полями. Для события OrderCreated нам может быть интересно опубликовать его id, products, creation_time и т. Д. Для события OrderPicked нам будет интересно узнать, кто был курьером и когда был получен заказ.
  • Эти события могут использоваться рядом функций AWS Lambda, которые вычисляют характеристики. События OrderCreated и OrderPicked, о которых мы упоминали ранее, могут быть полезны для расчета количества заказов, которые еще не были приняты в ресторане: каждый раз, когда происходит одно из них, мы можем пересчитать функцию для соответствующего ресторана.
  • Результаты этих функций затем сохраняются в кеше Redis и извлекаются при выполнении запросов к нашим моделям машинного обучения.

Наша архитектура, управляемая событиями: мы используем лямбда-выражения AWS Kinesis и AWS для обработки событий с необходимыми данными для преобразований и их результатов. Хранилище Redis позволяет нам хранить любые промежуточные данные и значения функций.

Новая система значительно улучшила способ работы с информацией в реальном времени. Это не только улучшило ключевые показатели эффективности нашей модели машинного обучения в результате предоставления более свежих и точных функций, но и теперь позволяет нашему DS очень быстро придумывать новые преобразования и автономно изменять уже существующие. При использовании этих функций потери наших моделей машинного обучения уменьшились на 20%. Поскольку мы не рекомендуем старую систему, мы также ожидаем, что нагрузка на нашу БД значительно снизится.

Это лишь очень краткий обзор новой системы. Есть много деталей, которые могут вас заинтересовать:

  • Если вы специалист по данным, вам может быть интересно узнать: как избежать дублирования кода для обучения и вывода? Как мы можем гарантировать, что рассчитываемые характеристики одинаковы в обеих средах? Какие типы агрегатов были наиболее полезными? Как это повлияло на наши ключевые показатели эффективности? На эти вопросы мы ответим в статье DS.
  • Если вы инженер-программист, вам может быть интересно, как мы разработали систему, позволяющую DS независимо создавать и поддерживать функции в реальном времени, и как мы использовали лямбда-выражения AWS, Redis и пошаговые функции, чтобы позволить нашей системе масштабироваться до тысяч Запросы

Мы рассмотрим эти аспекты более подробно в двух будущих статьях, посвященных аспектам Data Science и Engineering нашего решения.