LLM WikiAccess-protected knowledge portal
← 스터디 홈
3편 · 약 22분

Metric Layer 설계: 정의 충돌, semantic model, ownership

"매출"의 정의는 몇 개인가

데이터 팀 규모가 커지면 반드시 맞닥뜨리는 문제가 있다. 마케팅 팀의 대시보드에 표시된 "이번 달 매출"과 재무팀 리포트의 "이번 달 매출"이 다르다. 조사해 보면 마케팅은 gross revenue를 쓰고 재무는 net revenue를 쓰고, 고객 성공팀은 수수료 제외 수익을 쓰고 있다. 숫자가 세 개 있고 아무도 어느 것이 공식인지 모른다.

이것이 정의 충돌(metric definition conflict)이다. 84%의 데이터 팀이 정기적으로 경험한다고 보고된다. 규모가 작을 때는 "그냥 물어보면 된다"고 넘어가지만, AI 에이전트가 데이터를 직접 소비하기 시작한 지금은 잘못된 정의가 자동 의사결정에까지 전파된다는 점에서 비용이 완전히 달라졌다.

Metric Layer는 이 문제에 대한 구조적 답변이다.


1. Metric Layer가 해결하려는 문제

1.1 정의 중복의 전형적인 경로

마케팅 dbt 모델
mart_marketing_revenue
gross_amount 합산
재무 dbt 모델
mart_finance_revenue
net_amount 합산
CS Looker View
커스텀 LookML
fee 제외 계산
Ad-hoc Redash
분석가마다 다른 SQL
기준일 해석 다름
→ 같은 단어 "매출"이 4개의 다른 계산으로 흩어짐
어느 숫자가 공식인지 아무도 모름 · 조인 조건도 각자 다름 · 변경 시 4곳 모두 수정 필요
Metric Layer 도입 후: 한 곳에서 정의 → 모든 소비처에 동일 결과 제공
정의 중복이 발생하는 경로

각 팀이 각자의 BI 도구나 dbt 모델에 "매출"을 독립적으로 정의하면, 동일한 비즈니스 개념이 여러 곳에 분산된다. 시간이 지나면 각각 조금씩 달라지고, 어느 것이 공식 정의인지 아무도 모르게 된다.

1.2 Metric Layer가 주는 것

  • 단일 정의 위치: 비즈니스 지표를 한 곳에서만 정의한다.
  • 일관된 SQL 생성: 어떤 BI 도구, 어떤 쿼리 엔진을 쓰더라도 동일한 SQL이 생성된다.
  • 버전 관리: 지표 정의가 코드로 관리되어 변경 이력이 남는다.
  • 소유권 명확화: 각 지표에 owner가 명시된다.

2. Semantic Layer와 Metric Layer의 관계

두 용어가 혼용되는 경우가 많지만 개념적으로 구분할 수 있다.

소비 레이어 BI 도구 (Looker, Metabase) AI Agent / LLM Python / Notebook Metric Layer 지표 정의: revenue, churn_rate, ARPU … 각 지표에 measure, dimension, filter, time_dimension, owner 선언 Semantic Layer 엔티티 관계, 조인 경로, 집계 규칙, 접근 권한 orders ↔ customers ↔ products; date dim 정의; row-level security 물리 테이블 (dbt 모델, DWH)
Semantic Layer와 Metric Layer의 계층 관계

Semantic Layer: 테이블 간 관계, 조인 경로, 집계 규칙, 접근 권한을 선언하는 계층이다. "orders 테이블과 customers 테이블은 customer_id로 조인된다"가 여기 속한다.

Metric Layer: Semantic Layer 위에 서서 비즈니스 지표를 정의하는 계층이다. "revenue는 orders.amount를 status='paid'인 행에 대해 합산한 값이다"가 여기 속한다.

Metric Layer는 Semantic Layer의 어휘를 빌려 지표를 표현한다. 둘이 합쳐진 개념을 통틀어 "Semantic Layer"라고 부르는 경우도 있으므로, 도구마다 용어가 조금씩 다를 수 있다.


3. dbt Semantic Layer와 MetricFlow

dbt Labs는 2022년부터 MetricFlow를 인수·통합하여 dbt 안에서 지표를 정의하는 공식 방식을 제공한다.

3.1 핵심 개념

MetricFlow는 지표 요청을 데이터플로우 기반 쿼리 플랜으로 컴파일하고 엔진별 SQL로 변환한다.

# semantic_models/orders.yml  (dbt semantic model 예시)
semantic_models:
  - name: orders
    description: "주문 사실 테이블"
    model: ref('fct_orders')

    entities:
      - name: order_id
        type: primary
      - name: customer_id
        type: foreign
        expr: customer_id

    dimensions:
      - name: order_date
        type: time
        type_params:
          time_granularity: day
      - name: status
        type: categorical

    measures:
      - name: order_amount
        agg: sum
        expr: amount
      - name: order_count
        agg: count_distinct
        expr: order_id
# metrics/revenue.yml  (지표 정의 예시)
metrics:
  - name: revenue
    description: "결제 완료된 주문의 총 매출"
    label: "Revenue"
    type: simple
    type_params:
      measure: order_amount
    filter: |
      {{ Dimension('orders__status') }} = 'paid'
    meta:
      owner: "[email protected]"
      slack_channel: "#data-finance"

  - name: arpu
    description: "활성 사용자 1인당 평균 매출"
    label: "ARPU"
    type: ratio
    type_params:
      numerator: revenue
      denominator: active_users

3.2 MetricFlow가 지원하는 지표 유형

유형설명예시
simple단일 measure에 집계·필터revenue, order_count
rationumerator / denominatorARPU, conversion_rate
cumulativewindow 내 누적 집계rolling_30d_revenue
derived다른 지표들의 수식 조합gross_margin = (revenue - cost) / revenue

3.3 쿼리 방식

MetricFlow를 통해 정의된 지표는 dbt Cloud의 Semantic Layer API, JDBC, Python SDK로 조회할 수 있다.

# CLI 조회 예시
dbt sl query --metrics revenue --group-by order_date__month --limit 12
# Python SDK 예시
from dbt_semantic_interfaces.query_interface import MetricFlowQueryRequest

results = mf_client.query(
    metrics=["revenue", "arpu"],
    group_by=["order_date__month", "customer__tier"],
    where="order_date__month >= '2026-01-01'"
)

4. 지표 정의의 핵심 요소

좋은 지표 정의는 계산 방법만이 아니라 맥락을 담는다.

계산 정의
measure: 집계 대상 컬럼
agg: sum / count / avg / max / min
filter: 집계 조건
time_dimension: 기준 날짜 컬럼
grain: day / week / month
맥락 정의
label: 사람이 읽는 이름
description: 계산 방식 설명
owner: 책임 팀/담당자
slack_channel: 질문/변경 채널
status: active / deprecated
접근 제어
visibility: public / team / private
allowed_teams: 접근 허용 팀
row_level_filter: RLS 조건
certified: 공식 지표 여부
계산 정의만 있으면 "숫자를 어떻게 뽑는지"는 알아도 "누가 책임지는지", "언제 사용해야 하는지"를 모른다
지표 정의의 구성 요소

4.1 시간 차원의 중요성

가장 흔한 정의 충돌 중 하나는 기준 날짜가 다른 경우다.

  • 주문 생성 시각(created_at) 기준 매출
  • 결제 완료 시각(paid_at) 기준 매출
  • 배송 완료 시각(shipped_at) 기준 매출

같은 "이번 달 매출"이라도 어느 날짜 컬럼을 기준으로 하느냐에 따라 숫자가 달라진다. 지표 정의에서 time_dimension을 명시하는 이유가 여기 있다.

4.2 필터와 해석의 함정

filter: status = 'paid'는 명확해 보이지만, status가 시간이 지나면서 completedfulfilled로 바뀌었다면 어떻게 되는가? 필터는 enum 값의 변화에 취약하다. 지표 정의에 filter의 의도("결제가 확정된 주문")를 description에 명시해두면 미래의 유지보수자가 맥락을 이해할 수 있다.


5. Ownership 구조 설계

Metric Layer의 효과는 기술적 정의만으로는 반쪽이다. 누가 그 지표를 소유하는가를 명확히 해야 완성된다.

5.1 Ownership 레이어

레이어소유 주체책임
데이터 소유권원천 시스템 팀 (백엔드, 서비스팀)소스 테이블 스키마, 컬럼 의미
모델 소유권데이터 엔지니어링 / Analytics Engineeringdbt 모델, 지표 YAML
비즈니스 정의 소유권도메인 팀 (재무, 마케팅, 프로덕트)어느 계산이 공식인지
소비 소유권BI 개발자, 데이터 분석가대시보드, 리포트

데이터 엔지니어가 기술적 구현을 담당하더라도 "revenue는 net이냐 gross냐"는 재무팀이 결정해야 한다. 이 구분이 없으면 엔지니어가 추측으로 구현하고, 나중에 재무팀이 다른 답을 요구한다.

5.2 정의 충돌 해결 프로세스

1. 충돌 감지
같은 이름의 지표가 다른 값을 반환하거나, 다른 이름으로 같은 개념이 여러 개 존재
2. 이해관계자 목록 수집
어느 팀이 이 지표를 어디서 쓰는지 파악 · 현재 정의를 각 팀에서 수집
3. 비즈니스 정의 회의
공식 정의 결정 → 대안 정의가 필요한 경우 별도 이름으로 공존 허용
4. YAML 코드화 + owner 지정
metrics/*.yml에 공식 정의 작성 · 대안 정의는 별도 지표명으로 작성
5. 기존 대시보드 마이그레이션
기존 커스텀 계산을 Metric Layer 지표로 교체 · 불일치 리포트 감시
정의 충돌 해결 흐름

5.3 지표 네이밍 규칙

정의 충돌의 상당 부분은 이름이 모호해서 발생한다. 팀마다 동의할 수 있는 네이밍 규칙을 만들면 충돌이 줄어든다.

# 권장 패턴
{동사/형용사}_{명사}_{시간범위?}_{필터조건?}

예시:
revenue_gross          # 총매출 (세금·수수료 포함)
revenue_net            # 순매출 (수수료 제외)
revenue_net_paid       # 결제 완료 순매출
revenue_net_paid_30d   # 최근 30일 결제 완료 순매출
orders_count_new       # 신규 주문 수 (재구매 제외)
churn_rate_seat        # 시트 기준 이탈률
churn_rate_account     # 계정 기준 이탈률

6. Semantic Layer 도구 선택

도구특징적합한 상황
dbt Semantic Layer + MetricFlowdbt 프로젝트에 내장, YAML 정의, OSS 가능dbt 중심 스택, 새로 구축
Looker (LookML)Google 생태계, 강력한 조인·액세스 제어BigQuery + Google 클라우드
Cube.js헤드리스 Semantic Layer, 다양한 엔진 지원멀티 BI 도구 통합
AtScale엔터프라이즈, MDX/DAX 호환Excel·Power BI 중심 조직
Metriql오픈소스, dbt 메타데이터 활용소규모 팀, 자체 호스팅

대부분의 신규 프로젝트에서 dbt를 이미 쓰고 있다면 MetricFlow가 가장 진입 비용이 낮다. 기존 Looker 투자가 있는 조직은 LookML을 유지하면서 점진적으로 MetricFlow로 이전하는 하이브리드 경로가 현실적이다.


7. 실전 운영: Metric Layer를 건강하게 유지하기

지표 정의는 한 번 작성하면 끝이 아니다.

지표 변경 프로세스: 지표 정의를 변경하면 해당 지표를 사용하는 모든 대시보드와 리포트에 영향이 간다. Pull Request 기반 리뷰, downstream 소비처 목록 공지, 변경 로그 작성이 필요하다.

deprecated 처리: 더 이상 공식적이지 않은 지표는 즉시 삭제하지 말고 status: deprecated로 표시하고 대체 지표 이름을 안내한다. 삭제는 소비처 전환 확인 후에 한다.

지표 카탈로그: 정의된 지표를 검색 가능한 UI로 제공하면 새 분석가가 기존 지표를 재발견하지 못해 또 다른 커스텀 계산을 만드는 상황을 방지할 수 있다. dbt Cloud의 Explorer, Atlan, DataHub 같은 카탈로그 도구와 연동이 가능하다.


마무리

Metric Layer는 기술 도구이기 전에 조직의 합의를 코드로 만드는 과정이다. YAML 파일이 아무리 잘 작성되어 있어도 비즈니스 소유자가 정의에 동의하지 않았다면 또 다른 대시보드가 만들어진다. 반대로 조직적 합의만 있고 코드화가 없다면 그 합의는 시간이 지나면서 사라진다.

다음 편에서는 이 지표들의 기반이 되는 dbt 모델의 심화 패턴, 즉 레이어별 구현 전략, incremental 모델, snapshot을 다룬다.

References

  • dbt Labs, "About MetricFlow": https://docs.getdbt.com/docs/build/about-metricflow
  • dbt Labs, "dbt Semantic Layer": https://docs.getdbt.com/docs/use-dbt-semantic-layer/dbt-sl
  • dbt Labs, "Build your metrics": https://docs.getdbt.com/docs/build/build-metrics-intro
  • Atlan, "Metrics Layer: A Single Source of Truth for All KPI Definitions": https://atlan.com/metrics-layer/
  • Coalesce, "Semantic Layers in 2025: A Catalog Owner and Data Leader Playbook": https://coalesce.io/data-insights/semantic-layers-2025-catalog-owner-data-leader-playbook/
  • AtScale, "What Actually Changed in 2025 and Why It Redefined the Semantic Layer": https://www.atscale.com/blog/why-ai-redefined-the-semantic-layer/
  • Querio, "Metrics Layer vs Semantic Layer: What's the Difference?": https://querio.ai/articles/metrics-layer-vs-semantic-layer-difference
  • Alwyn DSouza, "Metrics as Code: Building a Semantic Layer With dbt and MetricFlow": https://medium.com/towards-data-engineering/metrics-as-code-building-a-semantic-layer-with-dbt-and-metricflow-93d7e29e6ab3