🤖 AI/ML

피처 스토어

Feature Store

ML 특성 관리 저장소. 재사용, 일관성 보장.

📖 상세 설명

피처 스토어(Feature Store)는 머신러닝 피처(특성)를 중앙에서 관리하고 공유하는 데이터 인프라입니다. 피처는 모델 학습과 추론에 사용되는 입력 변수로, 원시 데이터에서 추출하거나 변환해서 만듭니다. 예를 들어 "지난 30일간 구매 횟수", "평균 결제 금액", "마지막 로그인 이후 경과 시간" 같은 계산된 값들이 피처입니다. 피처 스토어는 이런 피처들의 생성, 저장, 검색, 서빙을 체계적으로 관리합니다.

피처 스토어가 등장한 배경에는 ML 팀의 공통적인 고충이 있습니다. 첫째, 동일한 피처를 여러 팀이 중복 개발하는 비효율. 둘째, 학습과 추론 시 피처 계산 로직이 달라지는 Training-Serving Skew. 셋째, 피처의 출처와 변환 이력을 추적하기 어려운 문제. 2019년 Uber가 Michelangelo를 발표한 이후 피처 스토어는 MLOps의 핵심 컴포넌트로 자리잡았습니다.

피처 스토어는 크게 오프라인 스토어와 온라인 스토어로 구성됩니다. 오프라인 스토어는 데이터 웨어하우스(BigQuery, Snowflake)에 저장되어 배치 학습에 사용됩니다. 온라인 스토어는 Redis, DynamoDB 같은 저지연 DB에 최신 피처를 캐싱해 실시간 추론을 지원합니다. 피처 변환(Feature Transformation)은 Apache Spark, Flink 같은 분산 처리 엔진으로 수행하며, 스케줄러가 정기적으로 피처를 갱신합니다.

2024-2025년 현재 주요 피처 스토어 솔루션으로 Feast(오픈소스), Tecton(상용), Databricks Feature Store, AWS SageMaker Feature Store, Google Vertex AI Feature Store 등이 있습니다. 최근에는 실시간 피처 계산(Streaming Features), 온디맨드 피처 변환, 피처 모니터링(드리프트 감지), LLM 임베딩 피처 관리 기능이 주목받고 있습니다. 대규모 ML 시스템에서 피처 스토어는 모델 개발 속도를 50% 이상 단축시킬 수 있습니다.

💻 코드 예제

Feast를 사용한 피처 스토어 설정 및 피처 서빙 예제입니다.

from feast import FeatureStore, Entity, Feature, FeatureView, FileSource
from feast.types import Float32, Int64, String
from datetime import timedelta
import pandas as pd

# 1. 피처 정의 (feature_repo/features.py)
# 엔티티 정의 - 피처의 기본 키
user = Entity(
    name="user_id",
    description="사용자 고유 ID",
    value_type=String,
)

# 데이터 소스 정의
user_daily_stats_source = FileSource(
    path="data/user_daily_stats.parquet",
    timestamp_field="event_timestamp",
    created_timestamp_column="created_timestamp",
)

# 피처 뷰 정의
user_daily_stats_fv = FeatureView(
    name="user_daily_stats",
    entities=[user],
    ttl=timedelta(days=1),  # Time-to-live
    schema=[
        Feature(name="daily_transactions", dtype=Int64),
        Feature(name="daily_amount", dtype=Float32),
        Feature(name="avg_transaction_value", dtype=Float32),
        Feature(name="days_since_last_login", dtype=Int64),
    ],
    online=True,  # 온라인 스토어에 동기화
    source=user_daily_stats_source,
    tags={"team": "fraud-detection"},
)

# 2. 피처 스토어 초기화 및 데이터 적재
def setup_feature_store():
    """피처 스토어 설정 및 오프라인/온라인 스토어 동기화"""
    store = FeatureStore(repo_path="feature_repo/")

    # 피처 정의 적용
    store.apply([user, user_daily_stats_fv])

    # 오프라인 스토어에서 온라인 스토어로 최신 피처 로드
    store.materialize_incremental(end_date=pd.Timestamp.now())

    return store

# 3. 학습용 피처 데이터 조회 (오프라인)
def get_training_features(store: FeatureStore, entity_df: pd.DataFrame):
    """배치 학습을 위한 과거 피처 조회"""
    # entity_df에는 user_id와 event_timestamp가 포함되어야 함
    training_df = store.get_historical_features(
        entity_df=entity_df,
        features=[
            "user_daily_stats:daily_transactions",
            "user_daily_stats:daily_amount",
            "user_daily_stats:avg_transaction_value",
            "user_daily_stats:days_since_last_login",
        ],
    ).to_df()

    return training_df

# 4. 실시간 추론용 피처 조회 (온라인)
def get_online_features(store: FeatureStore, user_ids: list):
    """실시간 추론을 위한 최신 피처 조회 (저지연)"""
    feature_vector = store.get_online_features(
        features=[
            "user_daily_stats:daily_transactions",
            "user_daily_stats:daily_amount",
            "user_daily_stats:avg_transaction_value",
            "user_daily_stats:days_since_last_login",
        ],
        entity_rows=[{"user_id": uid} for uid in user_ids],
    ).to_dict()

    return feature_vector

# 5. 온디맨드 피처 (실시간 계산)
from feast import on_demand_feature_view, RequestSource

@on_demand_feature_view(
    sources=[user_daily_stats_fv],
    schema=[Feature(name="risk_score", dtype=Float32)],
)
def risk_features(inputs: pd.DataFrame) -> pd.DataFrame:
    """실시간으로 계산되는 파생 피처"""
    df = pd.DataFrame()
    # 간단한 규칙 기반 리스크 스코어
    df["risk_score"] = (
        inputs["daily_transactions"] * 0.3 +
        inputs["days_since_last_login"] * 0.2 +
        (inputs["daily_amount"] / 1000) * 0.5
    ).clip(0, 100)
    return df

# 사용 예시
if __name__ == "__main__":
    store = setup_feature_store()

    # 온라인 피처 조회 (실시간 추론)
    features = get_online_features(store, ["user_123", "user_456"])
    print(f"온라인 피처: {features}")

    # 학습 데이터 생성
    entity_df = pd.DataFrame({
        "user_id": ["user_123", "user_456"],
        "event_timestamp": [pd.Timestamp("2025-01-20"), pd.Timestamp("2025-01-20")]
    })
    training_data = get_training_features(store, entity_df)
    print(f"학습 데이터:\n{training_data}")

📊 피처 스토어 솔루션 비교

솔루션 유형 온라인 지연 특징
Feast 오픈소스 ~10ms 유연한 배포, 다양한 스토어 지원
Tecton 상용 (SaaS) ~5ms 실시간 피처, 엔터프라이즈 기능
AWS SageMaker FS 관리형 ~10ms AWS 통합, IAM 보안
Databricks FS 관리형 ~15ms Unity Catalog 통합, 리니지
Vertex AI FS 관리형 ~10ms GCP 통합, BigQuery 연동

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"현재 각 팀에서 동일한 사용자 피처를 따로 계산하고 있어요. 피처 스토어를 도입하면 중복 작업을 없애고, Training-Serving Skew도 방지할 수 있습니다. Feast로 시작하면 인프라 비용도 최소화할 수 있어요."
💬 면접에서
"피처 스토어는 오프라인 스토어와 온라인 스토어로 구성됩니다. 오프라인은 과거 피처를 저장해 Point-in-Time 조회로 학습 데이터를 생성하고, 온라인은 최신 피처를 저지연으로 서빙해 실시간 추론을 지원합니다."
💬 기술 토론에서
"실시간 사기 탐지에서 스트리밍 피처가 필수인데, Feast만으로는 한계가 있어요. Tecton의 실시간 파이프라인이나 Flink + Feast 조합을 검토해야 합니다. 밀리초 단위 지연이 중요하면 자체 Redis 캐시 레이어도 고려해보세요."

⚠️ 흔한 실수 & 주의사항

Point-in-Time Join 없이 학습 데이터 생성

미래 데이터가 학습에 포함되면 Data Leakage가 발생합니다. 피처 스토어의 Point-in-Time 조회 기능을 활용해 특정 시점 기준으로 과거 피처만 조회하세요.

온라인 스토어 TTL 미설정

TTL(Time-to-Live) 없이 피처를 저장하면 오래된 데이터가 계속 서빙됩니다. 피처 특성에 맞는 TTL을 설정하고 정기적으로 materialize를 실행하세요.

피처 모니터링 및 드리프트 감지 설정

프로덕션 피처의 분포 변화를 모니터링하세요. 피처 드리프트는 모델 성능 저하의 주요 원인입니다. Evidently, Great Expectations 같은 도구로 자동 알림을 설정하세요.

🔗 관련 용어

📚 더 배우기