1 · Author
Schreibe YAML von Hand oder aus dem Modeler. Konvention: project.yml + models/
metrics/+facets/+joints/+lexicon/+contracts/.
Die OpenDome Semantic Layer (OSL) ist eine offene Spezifikation (Apache-2.0), die in deklarativem YAML ein semantisches Modell beschreibt, das zwei physische Ebenen umspannt: strukturierte Tabellen in Iceberg und Vektor-Collections in Lance. Eine Spec, eine Sprache, eine Governance-Kette.
Diese Seite legt das Vokabular und das mentale Modell fest. Für den normativen Vertrag siehe die Spezifikation; für die API-Oberfläche siehe die API-Referenz.
Die heutigen OSS-Semantikschichten (dbt MetricFlow, Cube, WrenAI) beschreiben relationale Tabellen. Keine behandelt Vektor-Collections als gleichberechtigte Bürger. Das erzwingt zwei parallele Modelle — das SQL-semantische und „das, was das RAG über den Kunden weiß“ — die schon am Tag nach dem Release auseinanderdriften.
OSL umspannt beide Ebenen:
JointEntity, ein logisches Objekt (Customer, Policy,
Order), das Iceberg-Spalten unter einem einzigen Primärschlüssel mit
Lance-Facetten verbindet.Einmal deklarieren. Governance, Lineage, APIs und Agenten konsumieren alle dasselbe Modell.
Das Modell
OSL beschreibt ein semantisches Modell über zwei physischen Substraten mit einer
einzigen deklarativen Sprache. Jede Ebene hat ihre eigenen Primitiven, ihre
FQN-Konvention, ihre Ausführungs-Engine und ihren Evolutionspfad. Die JointEntity
ist das Stück, das sie zusammensetzt.
Iceberg-Tabellen, SQL-Queries, Aggregationen, Joins. Hier reicht OSL MetricFlow unverändert durch:
semantic_models/*.yml beschreiben physische Entities mit ihren Dimensionen und Measures.metrics/*.yml definieren zertifizierte Metriken (simple, ratio, cumulative, derived).saved_queries/*.yml paketieren wiederverwendbare Queries.time_spine.yml definiert die zeitliche Granularität des Projekts.Die Referenz-Engine (tenant-semantic-api) kompiliert diese YAML zu SQL über
Trino, ausgeführt gegen Iceberg im Bucket des Tenants.
Lance-Collections mit indizierten Chunks. Hier definiert OSL neue Primitiven:
facets/*.yml (kind: UnstructuredFacet) beschreiben eine Lance-Collection:
Dataset-Pfad, Chunk-Schema, Embedding-Modell, Indizes (Vektor + FTS + skalar),
Metadata-Felder, row-level ACL und Retrieval-Limits.Die Engine führt hybrides Retrieval (Vektor ⊕ BM25 ⊕ Metadata-Filter) über LanceDB aus und gibt Passagen mit Zitation zurück, wobei sie die deklarierten ACL und Limits respektiert.
joints/*.yml (kind: JointEntity) deklariert ein logisches Objekt, dessen
Primärschlüssel von einem semantic_model stammt und das zusammengesetzte
Attribute bereitstellt — einige aus der strukturierten Ebene (Spalten, Metriken),
einige aus der unstrukturierten Ebene (Retrieval, gescoped durch den Schlüssel).Die Brücke ist ehrlich: Jedes join_on mappt einen Entity-Schlüssel auf ein
autoritatives, indiziertes Metadata-Feld der Facette. Ein Metadata-Feld mit
provenance: derived kann niemals ein Join-Schlüssel sein — abgeleitete
Extraktion passiert beim Ingest, nie zur Query-Zeit.
Ein Agent, der entity_get(Customer, customer_id=X) aufruft, erhält in einer
einzigen Antwort die kanonischen Attribute der Entity, die zutreffenden
vor-aggregierten Metriken und die nach customer_id=X gefilterten Lance-Chunks.
Ein Aufruf, eine Policy-Entscheidung, ein Audit-Trail.
Obwohl die Spec separate Primitiven hat (SemanticModel, JointEntity), sieht der
Konsument ein einziges Wort: Entity. Was eine Entity von einer anderen
unterscheidet, ist nicht ihr kind, sondern ihre Komposition:
| Komposition | Was es ist | Woher es kommt |
|---|---|---|
structured |
Rein tabellarische Entity (nur Iceberg) | ein SemanticModel, das weder Joint-Anker noch Brücke ist |
structured+content |
Strukturierte Spalten, verbunden mit Lance-Facetten | eine JointEntity mit unstrukturierten Beinen |
content |
Ein eigenständiges Lance-Korpus, ohne strukturierten Anker | eine UnstructuredFacet, die kein Joint absorbiert |
Relationen zwischen Entities stammen aus zwei Quellen: gemeinsame MetricFlow-Entities
(primary / foreign / unique) für strukturiert ↔ strukturiert benachbarte, und
N-N über eine Brücke — eine Junction-Tabelle (SemanticModel mit ≥2 foreign
Entities), die zu einer direkten N-N-Kante kollabiert, statt ein Knoten zu sein.
Dieses Vokabular ist das, was die domain-map (GET /osl/domain-map)
bereitstellt: ein einziger entity-Knotentyp, getaggt nach Komposition, plus
metric-Knoten und candidate-Knoten.
| Familie | Kind | Zweck | MetricFlow |
|---|---|---|---|
| Strukturierte Modellierung | SemanticModel, Metric, SavedQuery, TimeSpine |
Iceberg-Tabellen + Metriken beschreiben | ✅ identisch / erweitert |
| Unstrukturierte Modellierung | UnstructuredFacet |
Eine Lance-Collection beschreiben | ❌ OSL-only |
| Komposition | JointEntity |
Beide Ebenen unter einer logischen Entity verbinden | ❌ OSL-only |
| Katalog & Contracts | Lexicon, DataContract, PolicyBinding |
Synonyme, SLAs, Hints für den PDP | ❌ OSL-only |
Jede Primitive trägt apiVersion: osl.opendome.eu/v1, ein kind und einen
eindeutigen name. Die Identität eines Objekts ist (kind, name) — außer bei
SemanticModel, dessen Identität (catalog, schema, table) ist.
OSL deklariert; die Engine führt aus. Dazwischen liegt ein Kompilierungsschritt.
1 · Author
Schreibe YAML von Hand oder aus dem Modeler. Konvention: project.yml + models/
metrics/ + facets/ + joints/ + lexicon/ + contracts/.2 · Validate
osl validate führt JSON Schema pro Datei plus Cross-Reference aus (jeder
referenzierte FQN muss existieren). Fehler in E0xx (Schema) oder E1xx (Resolve).
3 · Compile
osl compile emittiert eine einzige target/manifest.json — die kanonische,
reproduzierbare Repräsentation, die die Engine bereitstellt und die Policy-Engine liest.
4 · Publish
osl publish lädt das Manifest auf die Engine des Tenants hoch. Atomar (Revert
mit osl publish --revert), emittiert ein osl.publish Lineage-Event.
Von dort aus bedient die Engine Queries: REST für BI/Apps, MCP-Tools für Agenten.
OSL ist streng bei Namen, weil Policies von ihnen abhängen. Vier FQN-Räume:
| Raum | Form | Beispiel |
|---|---|---|
| Strukturiert | <catalog>.<schema>.<table>[:<column>] |
iceberg.curated.customer:email |
| Unstrukturiert | lance://<collection>[/*][:<metadata_field>] |
lance://meeting_transcripts:attendees |
| Tools | <tool_kind>:<resource> |
metrics:revenue, joints:Customer |
| Joint-exposed | joint://<Entity>.<attribute> |
joint://Customer.recent_meeting_topics |
FQNs sind case-sensitive und tragen keine Version — die Versionierung lebt im
kompilierten, SHA-signierten Manifest. Die Policy-Engine konsumiert diese FQNs in
ihrem 4-D-Tupel (data, action, actor, context). OSL erfindet keine parallele
Zugriffssemantik; es emittiert die Fakten, die der PDP indexiert.
OSL ist die gemeinsame Spec zwischen all diesen Teilen, nicht die Teile selbst.