Как стать автором
Обновить
983.93
Конференции Олега Бунина (Онтико)
Профессиональные конференции для IT-разработчиков

Переходим от legacy к построению Feature Store

Уровень сложностиСредний
Время на прочтение9 мин
Количество просмотров1.1K

Невероятная история о том, как внедрить систему Feature Store в проект с огромным legacy и получить профит.

Привет, Хабр! Меня зовут Евгений Дащенко, я из компании Домклик, которая решает все вопросы, связанные с недвижимостью, включая оценку стоимости недвижимости любого типа. Это статья по мотивам моего доклада на конференции Highload++ про интерфейс между данными и ML-моделями Feature Store: как мы сделали его с нашей командой, каких результатов добились и с какими подводными камнями столкнулись на пути.

Feature Store: почему выбрали этот путь

Когда мы исследовали Feature Store, то общались со знакомыми, коллегами и друзьями, собирали референсы, ходили по конференциям. Практически все нас спрашивали: точно ли нам это надо, не проще ли сделать собственное Data Warehouse (DWH)? Мы не отметали этот путь сходу, но для себя решили разобраться с Feature Store — системой, состоящей из набора элементов-участников.

Дело в том, что оценка недвижимости в Домклик делится на два типа:

  1. Онлайн-процессы, когда любой пользователь может зайти на сайт и оценить своё жильё для продажи или аренды.

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

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

А ещё было много проблем, которые хотелось устранить.

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

Одна из причин долгого онлайн-прогнозирования — одна БД для одного типа моделей. Например, для вторичного жилья в базе была перемешана нагрузка OLAP и OLTP. Нужно было сначала обратиться за онлайн-прогнозами, потом за аналитикой. Если была реплика, то из неё можно было забрать данные для обучения, но в целом получалось неудобно и тяжело.

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

Длительные и нестабильные расчёты. Добавление новых источников позволяло расширять существующие пайплайны. Они становились ещё сложнее и длительнее в обработке. При этом у нас в расчётах участвовали пайплайны уровня critical. Первая мысль при пробуждении по утрам была: «А посчиталось ли?» И если нет, то приходилось всё перезапускать. А на следующий день внешний клиент мог выставить из-за этого штраф. Поэтому проблема была критической.

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

Большая размерность БД. Пример БД, работающей для одного типа моделей: Postgres размером 1,5 ТБ. Понятно, что эта БД может выдержать и больше, но тем не менее, когда есть онлайн + OLAP, это слишком много, неудобно.

Хаос в потоках данных. Если у бизнеса появлялись задачи для аналитиков-исследователей (data scientist), те бежали к нам с просьбами добавить несколько фич, скорректировать логику. Но такие запросы звучали сомнительно, потому что хаос выглядел примерно так:

Каждый раз приходилось ломать голову, как это добавить с учётом legacy в третьем поколении. При этом никто не знал legacy-код: там всё суперклассно и продумано до мелочей, но в нём не разобраться. Тем не менее мы попытались это сделать. Реализацию, к которой мы на текущий момент пришли, можно рассматривать как качественный MVP. Есть платформа и источники, откуда мы забираем данные, прогоняем через платформу и поставляем модельному сервису:

Выбор технологий

Feature Platform в Домклик состоит из нескольких элементов:

  • Engine — основной элемент. Работает на базе in‑house DBT + Airflow. Так как наши команды по большей части работают с табличными данными, то достаточно обычного классического хранилища, в котором будем выполнять большинство расчётов.

  • Data Lineage —  OpenMetadata

  • Data Quality — фреймворк SODA

Feature Store состоит из двух компонентов:

  • Offline Storage — Greenplum, где производятся все расчёты. Он у нас уже был в инфраструктуре и работал с аналитическим контуром. И так как мы делаем MVP, то решили, что Greenplum нам подходит — хватит для решения табличных задач.

  • Online Storage — это Postgres. У каждой модели есть своё маленькое онлайн-хранилище, в котором лежат нужные ей данные. По этой БД у нас в компании большая экспертиза. Данных не так много: Postgres в состоянии справиться с необходимой нагрузкой. К тому же эта СУБД решает задачу поиска дополнительных похожих объектов, которые требуются для работы моделей.

Ожидаем внедрения:

  • ClickHouse

  • Kafka

  • s3

  • Redis

Шаги внедрения

Мы решали бизнес-задачи и делали Feature Store. У нас нет разделения на Delivery и Discovery, поэтому нашей продуктовой командой мы сделали MVP, ведь это было нужно нам. Маленькими, но уверенными шажочками мы стандартизировали у себя подход к работе с данными для модели, и стало гораздо лучше.

Подготовка

Начали с изучения источников и запросов, которые использовались на тот момент. Казалось бы, очевидный шаг, но чтобы всё найти, из-за legacy надо было сначала всё изучить.

Дальше сформировали детальный слой хранилища. Офлайн-хранилище просто нарезали по слоям:

  • Raw Layer, или сырой слой данных. Здесь хранятся ненормализованные данные.

  • Stage Layer. Выступает сейчас детальным слоем. Хранит в себе нормализованные данные, которые превращены из Raw в нормализованные данные, и некую data-модель. Мы не стали усложнять, поэтому не выбрали Data Vault или Anchor. В принципе, наша data-модель похожа на снежинку.

Затем изучили логику текущих пайплайнов. После того как сформировали детальный слой хранилища, начали изучать DAGs. Естественно, это было долго, потому что код написан хаотично, не было никакой стандартизации и тестов.

Вот как спроектировано холодное хранилище:

Есть слои Raw, Stage и Marts. В слое Marts как раз хранится витрина холодного хранилища, которое работает под конкретную модель. Это те данные, которые нужны, чтобы обучить модель, забрать оттуда актуальный срез и поставить в Online Storage. На текущий момент это достаточно удобно для нас, потому что там лежат данные за весь период, и они работают для конкретной модели.

Как формируется слой Marts:

  1. Подготовка простых фич. Источник проходит через все слои, где выполняются вычисления, агрегации, соединения. После этого витрины готовы соединяться в холодное хранилище. Всё просто, потому что даётся расчёт на уровне SQL.

  2. Подготовка сложных фич. Здесь точкой отправки выступает Greenplum. Оттуда берётся батч данных и прогоняется с помощью DAG.

Например, прогон батча через модели классификации или кластеризации. После того как модель отработает, появляются новые фичи, которые либо нужны для того, чтобы работать на инференсе, либо понадобятся в будущем для обучения модели. После выполнения расчётов они складываются в отдельную БД Postgres. Postgres становится источником, а дальше прогоняется по всем слоям уже в Greenplum и соединяется в холодное хранилище.

Возникает вопрос доставки данных в Online Storage.

Доставка данных

Для этого мы придумали шаблонизированный DAG доставки.

После того как холодное хранилище готово, начинает работать DAG. Он берёт актуальный батч и поставляет в Online Storage. Модель вытаскивает актуальные данные и работает непосредственно с инференсом.

Упрощённо схема выглядит так:

Этот шаблонизированный DAG управляется на уровне конфига, где мы задаём параметры, которые прогоняем при каждом успешном запуске.

Работа DAG состоит из четырёх задач:

  1. Валидация схемы.

from typing import Optional, Sequence
from pydantic import BaseModel

class ContractMapping(BaseModel):
    conn_target_name: str
    schema_validation: type[BaseModel]
    query_collect: str
    query_insert: str
    query_delete: str
    swap_queries: Optional[Sequence[str]] = None

Чтобы DAG заработал, мы решили попробовать концепцию data-контракта. По большей части это похоже на контракт REST API, где мы точно знаем, каким должен быть запрос для конкретного эндпоинта, а каким — ответ. Мы уверены, что, отправив определённый запрос, получим структурно один и тот же ответ. В целом это просто некий data-класс, описываемый правилами, которые вы определите и будете использовать при работе.

Дальше этот data-контракт регистрируется в шаблоне DAG, и при запуске конфига вызывается его использование.

На эту тему коллега из нашей команды написал статью на Хабре: «Data‑contract — давайте попробуем договориться».

2. Проверка данных.

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

checks for buildings_table:
  - freshness(load_time) < 1d
  - duplicate_count(building_id):
    name: building unique
    fail: when > 0
  - missing_count(zhk_id):
    name: all building have zhk_id
    fail: when > 0

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

3-4. Загрузка и удаление дельты. На этом DAG завершает свою работу.

Data catalog

Мы рассматривали два инструмента: DataHub и OpenMetadata. В целом они сильно похожи по возможностям, но, по моим референсам, DataHub использовался и дошёл до рабочего состояния гораздо раньше. У многих знакомых компаний он уже успешно интегрирован и без проблем работает.

Однако мы выбрали OpenMetadata. Причин две:

  1. UI визуально понятнее, удобнее, нативнее. В нём практически невозможно запутаться.

  2. Количество инфраструктурных инструментов для поддержки этого ресурса. В случае  OpenMetadata, это Airflow, Elastic и Postgres. Для DataHub понадобятся ещё Kafka и MySQL вместо Postgres.

Data lineage

Напомню, как выглядел наш Data lineage раньше:

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

Data Catalog OpenMetadata упростил Data lineage. Погружаться в потоки данных конкретной модели стало гораздо проще.

Это скриншот с официального сайта, потому что наш нативный скриншот не прошёл проверку у кибербезопасности. Мы выкрутились и нарисовали схему. Она гораздо объёмнее, в ней больше источников и витрин, чем на скриншоте.

Есть слой Greenplum, в нём витрины, которые рассчитываются и объединяются — происходит магия на SQL. Потом считается финальная витрина на слое Marts, запускается DAG и дальше отправляется в Online Storage.

Клиент из команды фронтов или бэка заходит в модельный сервис и запрашивает онлайн-оценку. Модельный сервис состоит из двух компонентов: как правило, Rest’овый Python API и Online Storage, с которыми работает модель. API делает запрос в БД и получает дополнительные фичи. Они там преобразовываются, либо происходит расчёт. В итоге получается ответ для клиента. Offline Storage Greenplum поставляет данные в Online Storage, и делает он это на постоянной основе.

Наши модели работают по правилу T-1, то есть все актуальные данные минус один день. Этого достаточно. Условия по хранению и количеству всех данных в Online Storage определяет DS-команда.

Такой MVP у нас уже реализован. Но нам этого мало — мы хотим двигаться дальше, развивать платформу и Feature Store.

Куда двигаемся дальше

В будущем мы хотим видеть такую систему:

Цветом выделены блоки, которые намерены добавить или расширить. Кроме того, планируем добавить Meta Store и Meta SDK, а также расширить data-источники и Online Storage.

В качестве целевых технологий выбрали:

  • Meta Store. Скорее всего, Postgres.

  • Meta SDK. Возможно, какой-нибудь Python-фреймворк.

  • Data-источники — хотим расширить до ClickHouse, Kafka, S3, чтобы работать совместно. Так как команд у нас много, Feature Store предполагаем сделать общим для всех команд.

  • Online Storage — где-то Postgres хватает, а где-то его категорически недостаточно. Будем внедрять что-то ещё.

Meta Store + SDK

От этих инструментов и элементов в платформе мы ожидаем следующее:

  • Регистрация фич. Хотим, чтобы Meta Store хранил всю доступную метаинформацию о фичах, используемых аналитиками-исследователями. Ключевым фактором является регистрация фич, которые мы представляем в следующем виде:

from feature_store import MetaStore

meta_store = MetaStore(dsn=dsn)

meta_store.feature_registry(
  type='feature:model',
  feature=geocode_feature,
  ml_model_meta=flats_model,
  description='Вычисление города и страны',
)

На текущий момент Meta Store SDK находится в стадии исследования. Мы либо сделаем in-house решение, либо возьмём что-то на рынке, или же сделаем комбинацию «in‑house плюс вендор».

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

  • Декларативное описание фич. Хочется понимать, что это за фича, о чём она, какие у нее типы, что она может.

  • Каталог фичей. Финальный пункт — data-каталог, который DS-команда или команда ML-инженеров могут использовать для поиска фичей, гипотетически способных помочь в разработке моделей.

class Feature:
    name: str
    type: DataType
    version: str
    description: str

Чего достигли

Feature Store — это полезно. Мы проделали большую работу с точки зрения технических переработок, разработок, доработок и стандартизации, получили изменения. Но бизнесу нужно объяснить, какую выгоду приносит любая используемая технология или разработка.

  1. Уменьшили Time-To-Market. Мы сократили TTM примерно до пяти недель, причём в худшем случае. Влияние Feature Store на скорость поставки составляет порядка 30% и более. Отмечу, что такой прирост нам дал не только Feature Store, но и ряд других изменений внутри команды.

    Снижение Time-To-Market позволяет бизнесу проверить больше гипотез. А чем больше гипотез проверит бизнес, тем лучше будет результат для компании — увеличится выручка, сократятся затраты, улучшится качество работы с пользователем и т.д.

  2. Оптимизировали хранение данных. А ещё мы разделили бесконечный Postgres и сократили его до актуального состояния, когда Online Storage работает только с актуальными данными, которые нужны модели.

  3. Улучшили производительность. Также увеличили RPS, нужный пользователям. Теперь готовы переварить порядка 250 RPS с моделями, с которыми работаем.

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

Выводы

Задумываться о внедрении своей feature-платформы (Feature Store) в компании стоит тогда, когда уже есть модели в проде, и когда с каждым днём становится сложнее поддерживать их и добавлять новые. Это ключевой фактор. Но следует учесть, что для Online Storage придётся подготавливать пайплайны.

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

Теги:
Хабы:
+27
Комментарии0

Публикации

Информация

Сайт
www.ontico.ru
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия