본문으로 건너뛰기
ElastiCORE 3.0 은 릴리스 후보(RC)입니다: Maven Central 의 3.0.261022-rc1. 2.2 라인 프로젝트는 2.2 문서를 보세요.
버전: 3.0

Apache Ossie 시맨틱 모델 (ossie-export)

Apache Ossie(incubating)는 분석·BI·AI 플랫폼 사이에 시맨틱 메타데이터 - dataset(테이블), field(컬럼), relationship(조인), metric(지표) - 를 교환하는 ASF 의 벤더 중립 표준입니다. ElastiCORE blueprint 는 dataset 쪽이 요구하는 것을 이미 다 말하고 있으므로, 같은 내용을 두 번 선언하지 않고 내보냅니다. core spec 0.2.0.dev0(core-spec/spec.md, ossie-schema.json) 기준입니다.

데이터의 뜻을 모르는 에이전트와 BI 도구가 같은 DSL 에서 조인, PLC 같은 코드의 뜻, "매출"이 무엇인지를 받습니다.

켜는 법​

build.gradle 에서 - 번들은 그대로, 내보내기만 더함:

build.gradle
elasticore {
architecture = 'hexagonal'
rules = ['ossie-export']
}

또는 도메인의 env.yml 에서 번들과 함께:

blueprint/<도메인>/env.yml
    publisher:
rules: [hexagonal-springboot, ossie-export]

생성할 때마다 blueprint 루트에 src/main/resources/blueprint/semantic_model.yml 이 다시 만들어집니다. 프로젝트 전체가 한 모델이라 도메인을 넘는 관계가 끊기지 않습니다. schema.yml 과 같은 성격의 사이드카로 늘 다시 생성되고 손으로 고치지 않습니다. 내보내기가 실패해도 빌드가 아니라 내보내기만 저하됩니다. 스펙이 아직 dev 버전이라 바뀔 수 있습니다.

내보내는 것​

DSLOssie비고
엔티티 (@abstract·@embeddable 제외)datasets[]source = 테이블 (@table 또는 table.prefix + 이름)
-- 라벨description
@id 필드 (복합 키 포함)primary_key
@unique, @Index(unique="true")unique_keys
값 필드fields[] + expression(컬럼, OSSIE_SQL_2026) + datatype아래 타입 표
@formula(sql)expression = 그 SQL그 언어 안의 식이면 OSSIE_SQL_2026, 서브쿼리가 들어 있으면 ANSI_SQL 항목 하나 - 아래 dialect
@extend(Parent) 의 필드자식 dataset 의 fields상속된 컬럼도 그 테이블에 있으므로
@Embedded 값 객체그 컬럼들 (deliveryAddress.city)@embedded(prefix) 면 prefix_city
enum 필드datatype(글자 코드나 이름이면 String, 순번이면 Integer) + ai_context: "Codes: PLC = Placed, ..."테이블에는 코드만 있으므로 뜻을 함께
다른 엔티티 참조relationships[] + 조인 컬럼 필드실제 조인 컬럼
@password, @writeonly내보내지 않음애플리케이션도 읽어 주지 않는 값. omitted_columns 에 기록
states:, @access, @owner, @eventcustom_extensions (ELASTICORE)Ossie 에 해당 어휘가 없음
@compute, @snapshot, money / quantity필드의 custom_extensions파생 규칙과 값 타입
metrics:metrics[] (OSSIE_SQL_2026, datatype, description)선언한 것만 - 업무 지표
@terms(...) (엔티티·필드·지표)ai_context.synonyms업무 용어

DataType​

Ossie 의 DataType 은 10개입니다: String, Integer, Decimal, Float, Boolean, Date, Time, DateTime(시간대 없음), DateTimeTz(한 순간), Opaque(어휘 밖).

DSLOssieDSLOssie
string, text, clobStringfloat, doubleFloat
int, long, biginteger, quantityIntegerbooleanBoolean
decimal, bigdecimal, moneyDecimaldate / timeDate / Time
enum글자 코드나 이름이면 String, 순번이면 Integer (코드는 ai_context)datetimeDateTime
json, blob, ObjectOpaquetimestampDateTimeTz

is_time 은 쓰지 않습니다 - 스펙이 datatype 에서 기본값을 정하고, 그 답이 이 모델의 답입니다.

dialect​

스펙이 등록한 dialect 이름은 열두 개지만 의미를 정의한 것은 OSSIE_SQL_2026 하나입니다(core-spec/expression_language.md: 컬럼 참조, 산술·비교·논리 연산, CASE WHEN, 집계, COALESCE·NULLIF·CAST). ANSI_SQL 을 비롯한 나머지는 벤더 언어 이름이라 소비자가 무시해도 됩니다. 그래서 필드 식(컬럼 이름)과 metrics: 에서 만든 지표 식은 모두 OSSIE_SQL_2026 으로 내보냅니다. @formula 는 식에 따라 갈립니다: unit_price * quantity 처럼 그 언어 안의 식이면 OSSIE_SQL_2026, (select count(*) from ...) 처럼 서브쿼리가 들어 있으면 그 언어로 쓸 수 없으므로(SELECT·FROM·JOIN, 서브쿼리, CTE 는 식에서 지원하지 않음) ANSI_SQL 항목 하나로 둡니다 - 그 SQL 을 이해하는 쪽은 쓰고, 아니면 건너뜁니다. @formula 필드의 custom_extensions 에는 "formula": "database" 가 붙습니다.

내보내지 않는 것​

선언하지 않은 지표: 엔티티 필드에서 매출 공식을 지어내는 것은 추측을 내보내는 일입니다.

실제 출력 - Pet Store​

blueprint/semantic_model.yml
# Apache Ossie (incubating) semantic model - core spec 0.2.0.dev0
# Generated by ElastiCORE from the blueprint DSL - do not edit;
# regenerate with the ossie-export rule set.
version: 0.2.0.dev0
name: petstore
description: "Domain model of petstore, as its ElastiCORE DSL declares it"
ai_context:
instructions: "Each dataset is a table the generated application owns. An enumeration column holds a code; the field's ai_context lists every code and its label. Amounts (money) are decimals with their scale; a quantity is a count that is never negative. Password and write-only columns are left out on purpose. Lifecycles, access rules and derived values are in the ELASTICORE custom extensions."
datasets:
- name: PurchaseOrder
source: ps_purchase_order
primary_key: [order_id]
description: "주문"
ai_context:
synonyms: ["order", "purchase", "구매"]
fields:
- name: status
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: "status"
datatype: String
ai_context: "Codes: PLC = Placed, SHP = Shipped, CAN = Cancelled"
custom_extensions:
- vendor_name: ELASTICORE
data: "{\"lifecycle\": true, \"enumeration\": \"OrderStatus\"}"
- name: city
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: "city"
datatype: String
description: "deliveryAddress.city"
- name: total_without_vat
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: "total_without_vat"
datatype: Decimal
custom_extensions:
- vendor_name: ELASTICORE
data: "{\"compute\": \"sum(lines.subTotal)\", \"value_type\": \"money\"}"
# ...
custom_extensions:
- vendor_name: ELASTICORE
data: "{\"entity\": \"PurchaseOrder\", \"domain\": \"petstore\", \"owner\": \"customerId\", \"access\": {\"*\": \"admin\", \"cancel\": \"owner\", \"create\": \"user\", \"read\": \"owner\"}, \"states\": {\"status\": {\"initial\": \"PLACED\", \"ship\": \"PLACED -> SHIPPED\", \"cancel\": \"PLACED -> CANCELLED\", \"delete\": \"CANCELLED\"}}, \"events\": \"Placed(total), Shipped, Cancelled\", \"omitted_columns\": [\"credit_card_number\"]}"
relationships:
- name: PurchaseOrder_customer
from: PurchaseOrder
to: Customer
from_columns: [customer_id]
to_columns: [customer_id]
metrics:
- name: averageOrder
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: "(SUM(CASE WHEN PurchaseOrder.status <> 'CAN' THEN PurchaseOrder.total END)) / NULLIF((COUNT(CASE WHEN PurchaseOrder.status <> 'CAN' THEN 1 END)), 0)"
description: "주문 1건 평균 금액"
datatype: Decimal
ai_context:
synonyms: ["AOV", "객단가"]

CreditCard 의 카드 번호(@writeonly)는 dataset 의 필드가 아니라 omitted_columns 에 이름만 남습니다. Pet Store 의 referenceColumn: short 덕분에 조인 컬럼이 customer_id 입니다.

어떻게 검증하나​

  • SemanticModelTest(Pet Store 와 elasticore-template-ddd), 빌드마다: 내보낸 모든 테이블·컬럼·기본 키·조인 컬럼이 실제 DB 에 있는지 확인합니다. DB 에 없는 컬럼을 말하는 시맨틱 모델은 누군가의 BI 도구에서 실패하는 쿼리입니다.
  • MetricsTest(Pet Store): 주문을 접수·배송·취소한 뒤, 내보낸 지표마다 그 SQL 을 실제 DB 에서 실행하고(dataset 이름을 테이블로 바꿔서) 엔티티로 따로 계산한 값과 비교합니다 - 매출, 주문 수, 객단가, 배송, 취소, 고객 수.
  • 두 파일을 Ossie 의 ossie-schema.json 으로 검증한 결과는 오류 0 이었습니다(2026-10-03, 직접 실행 - 빌드 테스트에는 없음).
  • elasticore-base 의 단위 테스트: OssieExportTest, OssieMetricsTest, OssieSqlTest, OssieFormulaDialectTest.

파일을 쓰는 쪽​

semantic_model.yml 은 Ossie 를 읽는 도구를 위한 것입니다: BI 도구는 dataset·조인·지표를 다시 모델링하지 않고 받고, AI 에이전트는 ai_context(코드와 라벨, 동의어, 모델의 안내)와 지표 정의를 읽어 "지난달 매출" 을 업무의 정의 그대로 PurchaseOrder 와 revenue 로 찾습니다. 시간 축은 order_date 같은 날짜 필드에서 옵니다. 생명주기·권한·파생 값은 ELASTICORE custom extension 으로 함께 갑니다.

이력​

  • 첫 공개 릴리스(3.0.261015-alpha1) 전 - 스펙에 맞췄습니다: 전에는 semantic_model: 배열, expression 없음, money 를 String 으로, enum· 임베디드 컬럼 누락, 2.x 식 조인 컬럼, 비밀번호 컬럼 포함이었습니다.
  • 3.0.261022-rc1 - 식을 OSSIE_SQL_2026 으로 내보냅니다(전에는 모두 ANSI_SQL 이라 읽는 쪽이 전부 건너뛰어도 됐음). 서브쿼리 @formula 만 ANSI_SQL, "formula": "database" 추가. count(엔티티) 가 bare COUNT(*) 대신 키 컬럼을 셉니다(COUNT(Customer.customer_id)).