ストーリー
フィーチャーストアとは
Training-Serving Skew問題
Training-Serving Skew:
学習時(オフライン):
SQL: SELECT AVG(amount) FROM orders
WHERE customer_id = ? AND order_date >= DATE_SUB(today, 90)
→ 過去90日の平均購入額を計算(BigQueryで実行)
推論時(オンライン):
Python: orders = get_recent_orders(customer_id, days=90)
avg_amount = sum(o.amount for o in orders) / len(orders)
→ 同じロジックだが異なる実装(アプリケーションコードで実行)
問題:
- SQLとPythonで丸め処理が異なる
- 学習時は日次バッチで計算、推論時はリアルタイムで計算
- 日付の境界条件が微妙に異なる
→ モデルの精度が本番で低下する
フィーチャーストアの解決策
フィーチャーストア:
┌─────────────────────────────────────────────┐
│ フィーチャーストア │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ フィーチャー定義(Feature Definition) │ │
│ │ customer_avg_purchase_90d: │ │
│ │ entity: customer_id │ │
│ │ sql: AVG(amount) WHERE │ │
│ │ order_date >= today - 90 │ │
│ │ ttl: 1 day │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ ↓ ↓ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ オフラインストア │ │ オンラインストア │ │
│ │ (BigQuery) │ │ (Redis) │ │
│ │ 学習データ用 │ │ 推論用 │ │
│ │ 大量データ │ │ 低レイテンシ │ │
│ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ↓ ↓ │
│ 学習パイプライン 推論エンドポイント │
│ (同じフィーチャー定義で計算) │
└─────────────────────────────────────────────┘
フィーチャーストアのアーキテクチャ
主要コンポーネント
| コンポーネント | 役割 | 実装例 |
|---|---|---|
| フィーチャー定義 | フィーチャーの計算ロジックと型を宣言 | Python DSL, SQL |
| オフラインストア | 学習用の大量のフィーチャーデータを格納 | BigQuery, S3 + Parquet |
| オンラインストア | 推論用の最新フィーチャーを低レイテンシで提供 | Redis, DynamoDB |
| フィーチャーレジストリ | フィーチャーのメタデータ、バージョン、リネージ | カタログ連携 |
| マテリアライゼーション | オフライン→オンラインのデータ同期 | バッチ or ストリーム |
主要ツール比較
| ツール | ライセンス | オフライン | オンライン | ストリーミング | 特徴 |
|---|---|---|---|---|---|
| Feast | OSS | BigQuery, S3 | Redis, DynamoDB | Kafka対応 | 軽量、マルチクラウド |
| Tecton | 商用 | Spark/Snowflake | DynamoDB | ネイティブ | エンタープライズ向け |
| Vertex AI Feature Store | GCP | BigQuery | Bigtable | Dataflow | GCP統合 |
| SageMaker Feature Store | AWS | S3 | DynamoDB | Kinesis | AWS統合 |
| Hopsworks | OSS/商用 | Hive | MySQL/RonDB | Kafka | フル機能 |
Feastによるフィーチャーストアの実装
フィーチャー定義
# feature_repo/features.py
from feast import Entity, Feature, FeatureView, FileSource
from feast.types import Float64, Int64, String
from datetime import timedelta
# エンティティ定義
customer = Entity(
name="customer_id",
description="顧客の一意識別子"
)
# データソース(オフラインストア)
customer_features_source = FileSource(
path="gs://data-lake/gold/customer_features/",
timestamp_field="feature_timestamp"
)
# フィーチャービュー定義
customer_features = FeatureView(
name="customer_features",
entities=[customer],
ttl=timedelta(days=1),
schema=[
Feature(name="avg_purchase_90d", dtype=Float64),
Feature(name="total_orders_30d", dtype=Int64),
Feature(name="days_since_last_login", dtype=Int64),
Feature(name="support_tickets_90d", dtype=Int64),
Feature(name="plan_type", dtype=String),
],
source=customer_features_source,
description="顧客の行動フィーチャー(チャーン予測用)"
)
フィーチャーの取得
# 学習時(オフライン: 過去のフィーチャーを取得)
from feast import FeatureStore
store = FeatureStore(repo_path="feature_repo")
# 学習データの取得(Point-in-time correct join)
training_data = store.get_historical_features(
entity_df=entity_df, # customer_id + timestamp
features=[
"customer_features:avg_purchase_90d",
"customer_features:total_orders_30d",
"customer_features:days_since_last_login",
"customer_features:support_tickets_90d",
"customer_features:plan_type",
]
).to_df()
# 推論時(オンライン: 最新のフィーチャーを取得)
online_features = store.get_online_features(
features=[
"customer_features:avg_purchase_90d",
"customer_features:total_orders_30d",
"customer_features:days_since_last_login",
],
entity_rows=[{"customer_id": "cust_12345"}]
).to_dict()
# レイテンシ: < 10ms(Redis)
Point-in-Time Correct Join
データリーク防止
Point-in-Time Correct Join:
学習時に「未来のデータ」を使ってしまう問題を防ぐ
誤ったJoin:
学習データ: 2025年1月1日に解約した顧客のフィーチャー
フィーチャー: 2025年1月15日時点のlogin_count(= 0)
→ 解約後のデータを使って学習 → データリーク → 精度が異常に高い
Point-in-Time Correct Join:
学習データ: 2025年1月1日に解約した顧客のフィーチャー
フィーチャー: 2024年12月31日時点のlogin_count(= 解約直前の値)
→ 解約前のデータのみで学習 → 正しいモデル
「フィーチャーストアは『MLエンジニアとデータエンジニアの橋渡し』だ。データ基盤のGold層で計算したフィーチャーをストアに格納し、MLモデルに提供する。データ品質が担保されたフィーチャーが、信頼性の高いMLモデルを支える」 — 田中VPoE
まとめ
| ポイント | 内容 |
|---|---|
| Training-Serving Skew | 学習と推論で異なるフィーチャー計算ロジックが原因の精度低下 |
| フィーチャーストア | フィーチャーの定義・計算・保存・提供を一元管理 |
| オフライン/オンライン | 学習用は大量データ(BigQuery)、推論用は低レイテンシ(Redis) |
| Point-in-Time | 未来のデータを使わない正しいJoinでデータリークを防止 |
チェックリスト
- Training-Serving Skew問題とその影響を説明できる
- フィーチャーストアのオフライン/オンラインストアの違いを理解した
- Feastの基本的な使い方(定義、取得)を理解した
- Point-in-Time Correct Joinの重要性を説明できる
次のステップへ
次は「演習:MLOps基盤を設計しよう」です。Step 5で学んだMLOpsパイプラインとフィーチャーストアを使って、DataFlow社のチャーン予測基盤を設計します。
推定読了時間: 30分