Apache Ossie는 "시맨틱 모델(semantic model)을 어떤 YAML 형식으로 적을 것인가"를 정하는 규격 하나와, 그 규격을 기계가 검증할 수 있게 만든 JSON Schema, 그리고 기존 도구들의 형식을 이 규격으로 오가게 해주는 변환기 7종이 전부인 저장소다. 코드베이스라기보다 규격서(specification)에 가깝다.
fct_orders.amount_usd라는 컬럼만 있지만, 시맨틱 모델은 "총매출 = SUM(orders.amount) 단, 취소 주문 제외"라고 사람 말로 정의한다. BI 대시보드·AI 에이전트가 이 정의를 읽어 같은 숫자를 낸다.dbt는 dbt대로, Snowflake는 Snowflake대로, Tableau는 Tableau대로 "매출"을 각자의 형식으로 적어 왔다. 도구 A에서 B로 옮기려면 매번 새 변환기를 만들어야 했다. Ossie는 가운데에 중립 규격 하나를 세워 두고 각 도구가 그것 하나만 지원하면 되게 만들려 한다.
왜 하필 지금? — AI 에이전트 때문이다. 사람은 "이 대시보드의 매출은 취소분이 빠졌나?"를 눈치껏 확인하지만, LLM은 정의가 흔들리면 그대로 틀린 숫자를 자신 있게 말한다. Ossie의 스펙에 ai_context라는 필드가 모든 계층에 1급 시민으로 들어가 있는 이유다.
저장소는 크게 네 덩어리로 나뉜다.
| 덩어리 | 실체 | 상태 |
|---|---|---|
| 규격 문서 | core-spec/spec.md(594줄) + spec.yaml(주석 달린 예시 233줄) + osi-schema.json(JSON Schema, 330줄) | v0.2.0.dev0 (초안). 정식 릴리스는 0.1.1 |
| 온톨로지 레이어 | ontology/ontology.md(612줄) + ontology.json(313줄) — 물리 테이블과 무관한 순수 개념 층 | 제안 단계 |
| 도구 | validation/validate.py(290줄, 실제 동작) + cli/(Go, 전부 스텁) | 검증기만 실동작 |
| 변환기 | converters/ — dbt, GoodData, Salesforce, Snowflake, Polaris, Omni, OrionBelt, Honeydew | 대부분 동작, 품질 편차 큼 |
Go로 만든 ossie CLI는 validate·convert·plugin 세 명령이 전부 "not yet implemented"만 출력한다. 플래그 설계와 디렉토리 관리(~/.ossie/plugins)까지만 되어 있는 골격이다. 지금 실제로 쓸 수 있는 건 Python 스크립트 validation/validate.py 하나다.
또한 DISCLAIMER 파일이 명시하듯 이건 인큐베이팅(incubating) 단계다. Apache 재단이 "정식 프로젝트로 졸업시킬지 아직 검토 중"이라는 뜻이며, 안정성·거버넌스 성숙도가 보장되지 않는다.
README가 직접 지목하는 문제는 세 가지다: 도구마다 다르게 정의된 같은 KPI, 정의를 수동으로 맞추느라 낭비되는 시간, 그리고 "일관성 없는 비즈니스 로직에 기반해 신뢰할 수 없는 결과를 내놓는 AI 에이전트"다. 세 번째가 2026년의 결정타다.
사내에 "매출"이라는 단어가 일곱 가지 뜻으로 돌아다니는 회사를 상상하자. 사람 애널리스트는 회의에서 "어느 매출이요?"라고 되묻는다. 하지만 LLM은 되묻지 않는다. 아무거나 하나 골라서 자신 있게 보고한다. 시맨틱 레이어 표준화는 원래 BI 업계의 오래된 숙제였는데, AI가 그 숙제를 "안 하면 큰일 나는 일"로 바꿔 놓았다.
docs/index.md에 적힌 참여 조직에는 Alation, Anomalo, Atlan, AtScale, BlackRock, Cloudera, Databricks, dbt Labs, Snowflake, GoodData, Informatica, Mistral AI, Oracle, Qlik, Salesforce, Starburst가 함께 들어 있다. 데이터 웨어하우스 시장에서 서로를 잡아먹으려는 회사들이 같은 규격을 만든다는 것 자체가 뉴스거리다.
이 저장소는 원래 open-semantic-interchange/OSI 조직에 있다가 Apache로 옮겨왔다. 커밋 로그에 그 흔적이 그대로 남아 있다.
9738b1e Welcome Apache Ossie (incubating)
267638d docs: flag repository as legacy, point to apache/ossie
710da10 feat(cli): scaffold ossie CLI # (#151)
309acbf [OSI][Omni] Add Omni semantic model converter # (#175)
07be017 chore: add EditorConfig tab indentation for Go files # (#225)
수치로 보면 총 212커밋 중 최근 30일(2026-06-18~07-18)에만 52커밋이 몰려 있고, 마지막 push는 이 글을 쓰기 하루 전이다. 열린 이슈 55개도 대부분 "새 변환기 추가"류다 — #227 Lightdash 변환기, #224 Databricks Unity Catalog 변환기, #222 sqlglot 기반 OSI SQL 딜렉트, #228 uv 전환.
| 대상 | Ossie와의 관계 |
|---|---|
| dbt Semantic Layer / MetricFlow | 경쟁이 아니라 "스포크"로 취급. converters/dbt가 dbt Labs의 metricflow_semantic_interfaces 패키지를 그대로 import해 양방향 변환한다. 단 dbt의 cumulative 메트릭 등은 변환 시 정보가 손실되며, 이를 숨기지 않고 ConverterIssue로 기록한다. |
| Cube | 참여 조직 목록엔 있으나 저장소에 변환기 코드 없음. |
| Malloy | 직접 비교 서술 없음. 다만 Malloy 창시자 Lloyd Tabb이 워킹그룹 참가자 명단에 있다. |
| OpenMetadata / DataHub | 영역이 다르다. 저들은 "데이터 카탈로그(발견·거버넌스)", Ossie는 "모델 교환 포맷". 로드맵의 "Catalog Integration" 항목에서 향후 통합만 언급. |
| FIBO 등 도메인 온톨로지 | 미정리 상태. 이슈 #220 "clarify Ossie's relationship with FIBO"가 열려 있다. |
스펙 자체를 보면 dbt·Cube보다 표현력이 뛰어나지 않다. dimension은 is_time: boolean 필드 하나뿐이고, 계층(hierarchy)·단위·통화는 로드맵에만 있다. Ossie의 승부수는 "더 좋은 규격"이 아니라 "아무도 소유하지 않은 규격"이다. 따라서 이 프로젝트의 성패는 코드 품질이 아니라 벤더들이 실제로 자기 제품에 import/export를 붙여 주느냐에 달려 있다. 역사적으로 이런 컨소시엄 표준은 성공(SQL, OpenTelemetry)과 실패(수많은 XML 표준)가 반반이다.
| 언어 | 줄 수 | 어디에 쓰이나 |
|---|---|---|
| Python | 19,802 | 참조 구현 패키지(python/), 검증기, 변환기 6종(dbt·GoodData·Omni·OrionBelt·Honeydew·Snowflake) |
| YAML/JSON | 8,929 | 이게 사실상 본체. 스펙 스키마, 예제 모델(TPC-DS 594줄, flights 1,155줄), 테스트 픽스처 |
| Java | 6,642 | 변환기 2종 — Apache Polaris 카탈로그 연동, Salesforce/Tableau |
| Go | 295 | CLI 골격. 기능이 스텁이라 줄 수가 적다 |
validation/validate.py의존성 선언 방식이 재미있다. requirements.txt도 pyproject.toml도 없이, 파일 맨 위 주석에 의존성을 적는 PEP 723 인라인 메타데이터를 쓴다.
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "jsonschema>=4.26.0",
# "pyyaml>=6.0.3",
# "sqlglot>=30.12.0",
# ]
# ///
uv run validate.py 한 줄이면 uv가 알아서 가상환경을 만들고 jsonschema·sqlglot을 설치해 실행한다. 사용자에게 "pip install 먼저 하세요"를 요구하지 않는 것이 핵심 — 표준 채택률을 높이려는 프로젝트에 딱 맞는 선택이다.python/ (PyPI명 apache-ossie)의존성은 pydantic과 pyyaml 둘뿐. 스펙을 파이썬 객체로 읽고 쓰는 얇은 층이다.
converters/dbt/dependencies = [
"apache-ossie>=0.2.0.dev0",
"metricflow>=0.209.0", # dbt Labs 패키지를 그대로 의존!
"sqlglot>=20.0",
"jinja2>=3.0",
"PyYAML>=6.0",
]
# 빌드 백엔드: hatchling · 패키지 매니저: uv (uv.lock 존재)
// cli/go.mod
go 1.26.2
require github.com/spf13/cobra v1.10.2 // + mousetrap, pflag
// 배포: GoReleaser (cli/.goreleaser.yaml)
Cobra의 플래그 설계는 이미 꽤 정교하다 — --from/--to 상호배타(MarkFlagsMutuallyExclusive), --input 필수, --plugin으로 변환기 경로 직접 지정, --timeout, --max-input-size. 이 설계는 "변환기를 플러그인으로 설치하고 CLI가 오케스트레이션한다"는 미래 그림을 드러낸다. 다만 실행 로직은 비어 있다.
converters/polaris/pom.xml, converters/salesforce/pom.xml 둘 다 Maven이고 ASF 부모 POM(org.apache:apache:39)을 상속한다. Salesforce 변환기는 HandlerFactory + PipelineStep의 파이프라인 패턴으로 구성돼 있다.
| 파일 | 역할 |
|---|---|
.github/workflows/cli-ci.yml | 유일한 CI 워크플로. cli/** 경로가 바뀔 때만 돌며 go build / go vet / go test 수행. Python 변환기용 CI는 저장소에서 확인 불가 |
.asf.yaml | ASF 인프라 설정. main 브랜치 보호, 리뷰 1명 필수, dismiss_stale_reviews, required_linear_history, merge는 squash만 허용, Copilot 코드리뷰 활성화 |
DISCLAIMER / NOTICE / LICENSE | Apache 인큐베이팅 필수 3종 세트 |
이 저장소의 핵심 산출물은 코드가 아니라 YAML 스펙과 JSON Schema다. 그래서 무거운 테스트 파이프라인 대신, 사람이 읽는 스펙 문서 변경에 7일 토론 + [VOTE] 스레드라는 훨씬 무거운 사회적 CI를 걸어 놓았다. "무엇을 자동화하고 무엇을 사람 합의에 남길 것인가"의 좋은 사례다.
Ossie가 존재하는 이유를 한 장의 그림으로 요약하면 이렇다. converters/README.md에 실린 다이어그램을 옮긴다.
수학이 단순하다. 도구가 N개일 때 서로 직접 변환기를 만들면 N × (N-1)개가 필요하다. 도구 8개면 56개다. 가운데 중립 허브를 두면 각 도구가 "허브로 내보내기 1개 + 허브에서 읽기 1개"만 만들면 되므로 2 × N = 16개로 줄어든다.
항공사 노선과 같다. 모든 도시를 직항으로 잇는 대신 인천 같은 허브 공항 하나를 두면 노선 수가 급감한다. 대가는 경유의 불편 — 허브를 거치면서 원본에만 있던 정보가 깎여 나간다. dbt 변환기가 CUMULATIVE_SEMANTICS_LOSS 같은 이슈 코드를 남기는 게 정확히 이 경유 손실이다.
스펙의 핵심 개념은 다섯 개다. 위에서 아래로 내려가며 읽으면 된다.
Ossie는 "표현식을 하나의 언어로 통일"하지 않는다. 대신 같은 개념에 대해 여러 딜렉트의 표현식을 나란히 적게 한다.
dialects:
- "ANSI_SQL"
- "SNOWFLAKE"
- "DATABRICKS"
- "BIGQUERY"
- "MDX" # 다차원 큐브 질의어
- "TABLEAU"
- "MAQL" # GoodData 전용
이상적으로는 중립 표현식 언어 하나를 정하고 각 엔진용 SQL로 컴파일해야 한다(core-spec/expression_language.md 761줄이 그 제안서다). 하지만 MDX나 MAQL처럼 SQL이 아닌 언어까지 포용하려니 "각자 자기 언어로 적되 같은 이름표를 붙이자"로 후퇴했다. 결과적으로 같은 메트릭을 4개 딜렉트로 적으면 4벌을 손으로 동기화해야 하는 부담이 생긴다. 이슈 #222(sqlglot 기반 OSI SQL 딜렉트)가 이 문제를 정면으로 다루는 중이다.
semantic_model:
- name: retail_analytics
ai_context: "소매 주문·상품 분석용 모델"
datasets:
- name: orders
source: PROD.PUBLIC.FCT_ORDERS
primary_key: [order_id]
fields:
- name: order_date
expression:
dialects:
- dialect: ANSI_SQL
expression: order_date
dimension:
is_time: true
ai_context:
synonyms: ["purchase date", "transaction date"]
relationships:
- name: order_lines_to_products
from: orders # many 쪽
to: products # one 쪽
from_columns: [product_id, variant_id] # 복합 FK 지원
to_columns: [id, variant_id]
metrics:
- name: total_revenue
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(orders.amount)
ai_context:
synonyms: ["total sales", "revenue"]
custom_extensions:
- vendor_name: SNOWFLAKE
data: '{"warehouse": "ANALYTICS_WH", "database": "PROD"}'
ai_context를 1급 시민으로모델·데이터셋·필드·관계·메트릭 모든 계층에 ai_context가 들어간다. 그리고 JSON Schema에서 oneOf로 문자열과 객체를 둘 다 허용한다.
# 간단하게 쓰고 싶으면 문자열 하나
ai_context: "매출 분석에 사용하세요"
# 자세히 쓰고 싶으면 객체
ai_context:
instructions: "Use this for sales analysis"
synonyms: ["orders", "purchases", "sales"]
examples: ["Show total sales last month"]
JSON Schema의 oneOf로 스칼라와 객체를 둘 다 받는 이 패턴은 설정 파일 DSL 설계의 정석이다. 입문자는 문자열 한 줄로 시작하고, 고급 사용자는 객체로 확장한다. 스키마가 조금 복잡해지는 대가로 채택 장벽을 크게 낮춘다.
여기서 Ossie의 야심이 드러난다. Dataset/Field는 결국 물리 테이블에 묶인 논리 층인데, 그 위에 물리 스키마와 완전히 무관한 순수 개념 층을 하나 더 두려 한다(ontology/).
name: EnterpriseOntology
ontology:
- concept:
name: SocialSecurityNr
type: ValueType # 의미가 붙은 데이터 타입
extends: [Integer]
- concept:
name: Employee
type: EntityType # 실세계 개념
extends: [Person]
| 온톨로지 개념 | 의미 |
|---|---|
EntityType | 실세계에 존재하는 개념 — Employee, Customer, Product |
ValueType | 부가 의미를 가진 데이터 타입 — SocialSecurityNr는 그냥 Integer가 아니다 |
| 내장 개념 | Any, Boolean, Date, DateTime, Decimal, Float, Integer, String |
Multiplicity | ManyToOne / OneToOne |
| 개념 속성 | extends(상위 개념), derived_by, identify_by, requires(제약 표현식) |
이 층은 별도 JSON Schema(ontology/ontology.json)를 갖고, ontology_mappings로 물리 시맨틱 모델과 연결된다. 즉 Ossie는 "물리에 붙은 시맨틱 레이어"와 "물리와 무관한 온톨로지" 두 스택을 모두 가지려 한다.
# validation/validate.py — 딜렉트 매핑
DIALECT_MAP = {
"ANSI_SQL": None, "SNOWFLAKE": "snowflake",
"DATABRICKS": "databricks", "BIGQUERY": "bigquery",
"MDX": None, "TABLEAU": None, "MAQL": None,
}
# sqlglot이 파싱 못하는 딜렉트는 SQL 검증 자체를 건너뛴다
SKIP_SQL_VALIDATION = {"MDX", "TABLEAU", "MAQL"}
# python/src/ossie/models.py
class OSIRelationship(BaseModel):
model_config = ConfigDict(frozen=True, populate_by_name=True)
name: str
from_dataset: str = Field(..., alias="from") # from은 파이썬 예약어!
to: str
from_columns: list[str]
to_columns: list[str]
class OSIDocument(BaseModel):
version: str = "0.2.0.dev0"
semantic_model: list[OSISemanticModel]
def to_osi_yaml(self, **kwargs):
data = self.model_dump(by_alias=True, exclude_none=True,
mode="json", **kwargs)
return yaml.dump(data, default_flow_style=False,
sort_keys=False, allow_unicode=True)
포인트 셋: frozen=True로 모델을 불변화(스펙 문서는 값 객체다), alias="from"으로 파이썬 예약어 회피, exclude_none=True로 빈 필드를 출력에서 제거해 왕복 변환(round-trip) 시 YAML이 지저분해지지 않게 한다. 그리고 OSIAIContext = Union[str, OSIAIContextObject]로 스키마의 oneOf를 파이썬 타입으로 그대로 미러링한다.
| 순서 | 파일 | 왜 |
|---|---|---|
| 1 | core-spec/spec.yaml | 주석이 많은 예시라 스펙 전체 모양을 10분에 파악할 수 있다 |
| 2 | examples/tpcds_semantic_model.yaml | 장난감이 아닌 실제 규모(594줄)의 모델이 어떻게 생겼는지 |
| 3 | validation/validate.py | 스펙이 어떻게 강제되는지 — 290줄이라 통독 가능 |
| 4 | core-spec/osi-schema.json | JSON Schema 작성법 학습용 교재로 훌륭하다 |
| 5 | converters/README.md | "Writing a Converter" 8단계 가이드 + 허브앤스포크 근거 |
| 6 | ROADMAP.md / CONTRIBUTING.md | 미결 논쟁이 뭔지, Apache 거버넌스가 어떻게 도는지 |
compliance/가 비어 있다는 사실의 무게표준 프로젝트에서 준수성 테스트 스위트(compliance test suite)는 규격 문서만큼 중요하다. "우리 제품은 Ossie를 지원합니다"라는 주장을 검증할 수단이 없으면, 각 벤더가 제멋대로 해석한 방언들이 생겨나 표준이 무의미해진다. 지금 이 디렉토리는 README 한 줄뿐이다. 이 프로젝트가 진짜인지 판단하려면 compliance/가 채워지는지를 지켜보면 된다.
osi-schema.json은 JSON Schema 학습 교재로 쓸 만하다. 실제로 쓰인 기법들:
| 기법 | Ossie에서의 쓰임 |
|---|---|
$defs + $ref | Dataset·Field·Metric·Relationship을 재사용 가능한 정의로 분리 |
oneOf | ai_context를 문자열 또는 객체 둘 다 허용 |
additionalProperties: false | 오타 난 필드를 조용히 무시하지 않고 에러로 잡아냄 |
| 중첩 배열 | unique_keys가 "배열의 배열" — 복수의 복합 유니크 키 표현 |
| free-form 문자열 | vendor_name을 일부러 enum으로 안 함 → 스펙 개정 없이 새 벤더 확장 가능 |
additionalProperties: falsediscription 같은 오타를 즉시 잡지만, 벤더가 임의 필드를 넣을 수 없어 확장성이 떨어진다. Ossie는 엄격하게 잠그되 custom_extensions라는 공식 탈출구를 따로 판 절충안을 택했다.같은 스펙을 세 벌로 유지한다. spec.md(산문 설명) / spec.yaml(주석 많은 예시) / osi-schema.json(기계 검증). 중복처럼 보이지만 각각 독자가 다르다 — 의사결정자, 구현자, 도구.
가구 조립 설명서와 같다. 완성 사진(spec.md), 단계별 그림(spec.yaml), 그리고 나사 규격표(osi-schema.json). 셋 다 필요하고, 셋이 어긋나면 아무도 조립하지 못한다. 표준 프로젝트의 실질적 난이도는 이 세 벌을 동기화하는 데 있다.
배울 것: frozen=True(값 객체), alias로 예약어 회피, Union 타입으로 스키마 oneOf 미러링, model_dump(by_alias=True, exclude_none=True, mode="json")으로 깔끔한 왕복 직렬화.
sqlglot은 20종 이상의 SQL 방언을 파싱·변환하는 파이썬 라이브러리다. Ossie는 검증에만 쓰지만, 이 라이브러리 자체가 "SQL을 문자열이 아니라 AST로 다루는" 세계로 들어가는 관문이다. 이슈 #222는 여기서 더 나아가 sqlglot에 OSI 전용 딜렉트를 등록해 표현식을 자동 트랜스파일하자는 제안이다.
dbt 변환기의 msi_to_osi.py는 dbt의 PydanticSemanticManifest를 순회하며 Entity/Dimension/Measure를 Ossie Field로, dbt Metric을 OSIMetric으로 옮긴다. 이때 옮길 수 없는 것을 조용히 버리지 않고 명시적으로 기록한다.
ConverterIssueType.CUMULATIVE_SEMANTICS_LOSS
ConverterIssueType.CONVERSION_METRIC_DROPPED
포맷 변환기를 만들 때 가장 흔한 죄는 변환 못 하는 걸 조용히 버리는 것이다. 사용자는 나중에 숫자가 틀어지고 나서야 알게 된다. Ossie 변환기는 손실 항목을 타입이 붙은 이슈 객체로 리포팅한다. 어떤 ETL·마이그레이션 코드를 짜든 그대로 훔쳐 쓸 수 있는 패턴이다.
CONTRIBUTING.md가 유난히 상세해서, 오픈소스 거버넌스를 글이 아니라 실물로 볼 수 있다.
| 개념 | Ossie에서의 실제 |
|---|---|
| PPMC | Podling PMC — 인큐베이팅 프로젝트의 운영위 |
| Mentors / IPMC | 인큐베이터 PMC가 상위 감독. 릴리스는 dev@ossie.apache.org 투표 → general@incubator.apache.org 투표 2단계 |
| lazy consensus | 일반 코드 PR — committer 1명 이상 +1, veto 없으면 병합 |
| 스펙 변경 | 7일 토론 + [VOTE] 스레드 + PPMC +1 3표 이상 |
| ICLA / CCLA | 개인/회사 기여자 라이선스 동의서 |
validate.py의 인라인 메타데이터, 변환기들의 uv.lock, 빌드 백엔드 hatchling. setup.py 시대를 건너뛰고 현재 관행을 바로 배울 수 있는 샘플이다. (열린 이슈 #228이 "저장소 전체를 uv로 전환"이다.)
기능은 비었지만 골격은 배울 만하다. MarkFlagsMutuallyExclusive(상호배타 플래그), MarkFlagsOneRequired, PersistentPreRunE. 특히 Cobra가 PersistentPreRunE를 부모→자식으로 자동 상속하지 않는다는 함정을 코드 주석으로 직접 경고해 둔 부분이 실전 지식이다.
다행히 요구사항이 거의 없다. GPU도 클라우드 계정도 필요 없고, YAML 파일을 읽고 검증하는 것이 전부다.
| 구성요소 | 요구사항 | 비고 |
|---|---|---|
| 검증기 | Python 3.11+ (uv 권장) | 의존성 3개(jsonschema, pyyaml, sqlglot). uv가 있으면 설치 불필요 |
| 참조 패키지 | Python 3.11+, pydantic | pip install apache-ossie |
| dbt 변환기 | Python + uv | metricflow를 끌어오므로 의존성이 무거움 |
| OrionBelt 변환기 | Python 3.12+ | 다른 변환기보다 요구 버전이 높다 |
| Java 변환기 | Maven + JDK | polaris, salesforce |
| CLI | Go 1.26.2 | 빌드는 되지만 실행하면 "not yet implemented" |
| 메모리/디스크 | 사실상 무관 | 저장소 전체 1.3MB |
대부분의 트렌딩 AI 저장소가 GPU·API 키·도커를 요구하는 것과 달리, Ossie는 노트북에서 텍스트 파일 하나 고치고 python validate.py 한 줄이면 끝난다. 표준을 배우기에 이보다 좋은 조건은 없다.
git clone --depth 1 https://github.com/apache/ossie.git
cd ossie
python validation/validate.py examples/tpcds_semantic_model.yaml
통과를 확인한 뒤 일부러 세 가지를 망가뜨려 각각 어느 검증 단계에서 잡히는지 관찰한다: ① 필드 이름 하나를 다른 필드와 같게 만들기(→ validate_unique_names), ② relationship의 to를 없는 데이터셋 이름으로 바꾸기(→ validate_references), ③ 메트릭 표현식을 SUM(orders.amount처럼 괄호를 빠뜨리기(→ validate_sql).
배우는 것: "스키마 검증"과 "의미 검증"이 왜 별개인지. JSON Schema는 ②③을 절대 못 잡는다.
가계부 CSV, 운동 기록, 게임 전적 등 자기 데이터를 골라 datasets 2개 이상 + relationship 1개 + metric 3개로 모델링한다. 검증을 통과시키는 것이 목표.
여기서 진짜 배우는 건 문법이 아니라 "내 메트릭의 정의가 사실은 모호했다"는 자각이다. "이번 달 지출"에 환불은 포함인가? 카드 결제일 기준인가 승인일 기준인가? — 이걸 ai_context.instructions에 문장으로 적어 보면 시맨틱 레이어가 왜 필요한지 몸으로 알게 된다.
from ossie.models import OSIDocument
import yaml
doc = OSIDocument(**yaml.safe_load(open("examples/tpcds_semantic_model.yaml")))
for model in doc.semantic_model:
for m in (model.metrics or []):
print(m.name, "|", m.expression.dialects[0].expression)
여기서 확장: ① ai_context가 비어 있는 메트릭 목록(= AI가 오해할 위험 지점) 뽑기, ② 어떤 relationship에도 참여하지 않는 고아 데이터셋 찾기, ③ 결과를 마크다운 표로 출력. 배우는 것: 스펙을 "읽는 도구"를 만들면 스펙 구조가 머리에 박힌다.
validate 명령을 실제로 구현하기cli/cmd/validate.go의 runValidate가 지금 "not yet implemented"만 출력한다. Python validate.py의 4단계 파이프라인을 Go로 이식한다 — gopkg.in/yaml.v3로 파싱, santhosh-tekuri/jsonschema로 스키마 검증, 이름 유일성·참조 무결성은 직접 구현.
배우는 것: 같은 로직을 두 언어로 짜 보면 "스펙 준수 구현이 여러 개 있을 때 생기는 미묘한 불일치"라는 표준의 진짜 어려움을 체감한다. (SQL 검증까지는 무리다 — Go에 sqlglot 대응물이 마땅치 않다는 것 자체가 발견이다.)
converters/README.md의 "Writing a Converter" 8단계 가이드를 따라 아직 없는 도구용 변환기를 만든다 — Metabase, Superset, Looker(LookML), Lightdash(이슈 #227에 이미 요청이 있다) 등.
최소 스코프: 대상 도구의 모델 파일을 파싱해 dataset/field/metric만 Ossie YAML로 내보내고, 손실 항목을 ConverterIssue로 기록. converters/dbt를 구조 템플릿으로 삼으면 된다.
배우는 것: Apache 기여 프로세스 실전(ICLA 서명, dev 메일링 리스트, PR 리뷰). 이력서에 "Apache 프로젝트 컨트리뷰터"를 적을 수 있는 현실적으로 가장 쉬운 경로 중 하나다 — 이 프로젝트는 지금 변환기를 절실히 원한다.
| 주차 | 주제 | 할 것 |
|---|---|---|
| 1주차 | 시맨틱 레이어 개념 | Ossie 스펙 통독 + 과제 1·2. 병행해서 dbt의 MetricFlow 문서, Cube 문서를 훑어 "같은 문제를 다르게 푼 세 가지"를 비교. 핵심 질문: 차원(dimension)과 메트릭(metric)을 왜 분리하는가? |
| 2주차 | 스키마 언어와 DSL 설계 | JSON Schema Draft 2020-12 공식 문서 + osi-schema.json 정독. 직접 작은 설정 파일 스키마를 설계해 보기. oneOf/anyOf/allOf 차이, $ref 순환 참조 문제를 실습으로 확인 |
| 3주차 | SQL을 AST로 다루기 | sqlglot 튜토리얼 — 파싱, 딜렉트 변환(transpile), AST 순회. 과제 3을 확장해 "모든 메트릭 표현식에서 참조되는 컬럼 목록 추출" 구현. 이게 되면 lineage(계보) 분석의 기초를 잡은 것 |
| 4주차 | 데이터 카탈로그 · 거버넌스 | OpenMetadata나 DataHub를 도커로 띄워 보고, "카탈로그"와 "시맨틱 레이어"의 역할 차이를 정리. 병행해서 Ossie의 ROADMAP.md·GitHub Discussions를 읽으며 미결 논쟁 파악 → 과제 5로 기여 |
이 로드맵은 "AI 시대의 데이터 엔지니어"가 되는 경로다. 파이프라인을 짜는 기술(Airflow·Spark)은 이미 성숙했고, 지금 부족한 인력은 "비즈니스 정의를 기계가 읽을 수 있는 형태로 옮기는 사람"이다. Ossie는 그 일을 배우기에 가장 부담 없는 교재다 — 인프라가 필요 없으니까.
| 용어 | 뜻 |
|---|---|
| Ossie | Apache Ossie. 구명 OSI(Open Semantic Interchange). 시맨틱 모델 교환 규격 |
| 시맨틱 모델 | 물리 테이블 위에 얹은 비즈니스 의미 층. 데이터셋·필드·관계·메트릭으로 구성 |
| dataset | Ossie의 "엔티티". 대개 물리 테이블 하나에 대응. source로 db.schema.table 지정 |
| field | 행 단위 속성. dimension.is_time이 붙으면 시간 차원으로 취급 |
| metric | 집계 측정치. SUM(orders.amount) 같은 표현식. 여러 데이터셋에 걸칠 수 있음 |
| relationship | 데이터셋 간 외래키 조인. from(many) → to(one), 복합 컬럼 지원 |
| dialect | 표현식을 적을 SQL 방언. ANSI_SQL/SNOWFLAKE/DATABRICKS/BIGQUERY/MDX/TABLEAU/MAQL |
| ai_context | LLM 그라운딩용 필드. instructions·synonyms·examples. 모든 계층에 존재 |
| custom_extensions | 벤더 확장용 탈출구. vendor_name(자유 문자열) + data |
| ontology | 물리 스키마와 무관한 순수 개념 층. EntityType / ValueType |
| EntityType / ValueType | 실세계 개념(Employee) vs 의미가 붙은 데이터 타입(SocialSecurityNr) |
| 허브 앤 스포크 | 중립 허브를 둬 변환기 수를 N×(N-1)에서 2×N으로 줄이는 통합 패턴 |
| MetricFlow / MSI | dbt Labs의 시맨틱 레이어 엔진과 그 인터페이스 패키지. Ossie dbt 변환기가 직접 의존 |
| sqlglot | 다중 SQL 방언 파서/트랜스파일러(Python). Ossie 검증기가 표현식 문법 검사에 사용 |
| JSON Schema | JSON/YAML 구조를 검증하는 표준. Ossie는 Draft 2020-12 사용 |
| PEP 723 | 파이썬 단일 파일 스크립트가 주석에 의존성을 선언하는 표준. uv run으로 즉시 실행 |
| uv | Rust로 만든 초고속 파이썬 패키지/프로젝트 매니저 |
| hatchling | 현대적 파이썬 빌드 백엔드. setuptools 대체 |
| Cobra | Go CLI 프레임워크. kubectl·docker 등이 사용 |
| 인큐베이팅 | Apache 재단 정식 프로젝트 이전의 검증 단계. DISCLAIMER 파일 필수 |
| PPMC / IPMC | Podling PMC(인큐베이팅 운영위) / Incubator PMC(상위 감독) |
| lazy consensus | 명시적 반대(veto)가 없으면 승인으로 간주하는 Apache 의사결정 방식 |
| Apache Polaris | 오픈소스 Iceberg 카탈로그. Ossie가 변환기를 제공하는 ASF 자매 프로젝트 |
| Cortex Analyst | Snowflake의 자연어 질의 기능. Ossie Snowflake 변환기의 출력 대상 |
| TPC-DS | 의사결정 지원 시스템 표준 벤치마크 스키마. Ossie의 대표 예제 모델 |
| 준수성 테스트 | 구현이 규격을 지키는지 검사하는 테스트 스위트. Ossie compliance/는 아직 비어 있음 |
| 분류 | 링크 |
|---|---|
| 저장소 | github.com/apache/ossie |
| 공식 사이트 | ossie.apache.org |
| TrendShift | trendshift.io/repositories/44755 |
| 스펙 문서 | core-spec/spec.md · core-spec/osi-schema.json · core-spec/expression_language.md |
| 변환기 가이드 | converters/README.md ("Writing a Converter" 8단계) |
| 로드맵 · 기여 | ROADMAP.md · CONTRIBUTING.md · GitHub Discussions |
| 메일링 리스트 | dev@ossie.apache.org |
| 연관 학습 | JSON Schema 공식 문서 · sqlglot(github.com/tobymao/sqlglot) · dbt MetricFlow 문서 · Apache Polaris |