Skip to content

External Concept Mappings

An OBML model already is an ontology of sorts: every loaded model is exported as an OBSL RDF graph that says which measures exist, which columns they read and how the data objects join. What that graph cannot say on its own is what a measure means to the business. Is Revenue the same thing as the NetRevenue your finance glossary defines? A narrower notion of it? Merely related?

External concept mappings answer that. They are descriptive links from a model artefact to a concept in an ontology you do not own: a corporate business glossary, FIBO, schema.org, GoodRelations. They never change what OBSL compiles or executes.

Two ontologies, one source of truth

OBML model ontology External business ontology
Owned by your OBML file a governance team, a standards body
Describes tables, columns, joins, dimensions, measures, metrics and how they compile business concepts and how they relate to each other
Generated by OBSL yes, as the OBSL RDF graph, from OBML never; OBSL only references it by IRI
Changes when you edit the model the ontology owners publish a new version

OBML stays the single source of truth. The RDF graph is a projection of it, and a mapping is one more fact in that projection: "this artefact relates to that external IRI in this way". OBSL never fetches, imports or restates the external ontology, not at load time and not in the graph. A mapping to an IRI nobody has published yet is allowed; it is a statement about your model, not about the network.

Why mappings never affect SQL

A mapping is metadata in the same sense description or synonyms are. It is not read by the query resolver, the planner or the code generator: compiled SQL is byte-identical with and without mappings, and so are the join path, the metric expansion and the planner's warnings. This is deliberate, and it is tested.

Two things this does not mean. It does not make a mapping edit free for the result cache: a shared model id is a hash of the whole OBML document, and the cache key includes it, so changing a mapping is a model edit like any other and cached results are scoped to the new model version. And it does not make mappings a place for logic: if a business rule should change what a query returns, it belongs in a measure filter, a static filter or a metric expression.

Syntax

Prefixes

Declare the namespaces you map into once, at the top level:

version: 1.0
ontology:
  prefixes:
    corp: "https://ontology.example.com/business/"
    fibo: "https://spec.edmcouncil.org/fibo/ontology/"
    gr:   "http://purl.org/goodrelations/v1#"

A prefix name is a conservative identifier (letters, digits, _, -, ., starting with a letter or _). A namespace is an absolute IRI. Five prefixes are built in and need no declaration: rdf, rdfs, owl, skos, xsd. You may repeat one of them verbatim, but binding a built-in name to a different namespace is rejected with INVALID_ONTOLOGY_PREFIX.

Mappings

The model itself, a data object, a dimension, a measure or a metric may carry an externalConceptMappings list:

measures:
  Revenue:
    aggregation: sum
    expression: "{[Orders].[Amount]}"
    externalConceptMappings:
      - concept: "corp:NetRevenue"          # compact IRI, expanded with ontology.prefixes
        relation: exact                     # required
        justification: curated              # optional
        source: "enterprise-finance-ontology"
        ontologyVersion: "2026.1"
        confidence: 1.0
        comment: "Approved by Finance Data Governance"
      - concept: "https://schema.org/MonetaryAmount"   # a full IRI works too
        relation: broader
Property Type Required Description
concept string Yes The external concept, as a compact IRI (prefix:LocalName) or a full IRI (https://..., urn:...). See Compact versus full IRIs
relation enum Yes exact, close, broader, narrower, related. There is no implicit exact. See Choosing the relation
justification enum No How the mapping came to exist: curated (a human decision), imported (from another catalog or format), generated or inferred (by tooling), lexical (a name match only)
source string No Where the mapping comes from: a catalog, ontology or process name
ontologyVersion string No Version of the external ontology the concept was taken from
confidence number No 0 to 1
comment string No Free text: approval, caveat, rationale

The resolver expands every concept to an absolute IRI. The API returns it as expanded_iri; in the RDF graph it is the object of the direct skos:*Match triple on every mapping, and additionally the obsl:targetConcept of the provenance resource that only mappings with provenance get (see OBSL Graph & SPARQL). Query the SKOS predicates, not obsl:targetConcept, to see every mapping. The expanded form is derived, so authoring expandedIri in YAML is an UNKNOWN_PROPERTY error.

Compact versus full IRIs

A value is a full IRI when its scheme is followed by // (https://...) or when it is a URN (urn:...). Anything else of the form prefix:local is a compact IRI, and its prefix must be declared or built in. Treating every scheme: as absolute would let an undeclared prefix through silently, which is exactly the typo this rule exists to catch.

Value Reads as Result
corp:NetRevenue compact expanded with corp
https://schema.org/Product full kept as written
urn:isbn:0451450523 full kept as written
acme:Thing with no acme prefix compact UNKNOWN_ONTOLOGY_PREFIX
NetRevenue relative reference INVALID_CONCEPT_IRI
_:b0 blank node INVALID_CONCEPT_IRI
<https://x.example/A> angle-bracketed INVALID_CONCEPT_IRI, write it without the brackets
corp:Net Revenue contains whitespace INVALID_CONCEPT_IRI

Where mappings are allowed

Model, data object, dimension, measure, metric. Not columns or joins: a customer_id column identifies a Customer rather than being one, and a join relates two concepts rather than matching either. Both need a more precise relation vocabulary than SKOS matching offers, so they are deliberately out of scope until one exists. Putting externalConceptMappings on a column is an UNKNOWN_PROPERTY error.

Synthesized row-count measures (Sales Count and friends) cannot carry mappings either; they are never persisted. Map a declared measure instead.

Choosing the relation

The relation reads artefact first, in the SKOS direction: it describes the external concept as seen from your OBML artefact.

relation SKOS predicate Means Example
exact skos:exactMatch the artefact and the concept mean the same thing measure Net Revenuecorp:NetRevenue
close skos:closeMatch similar enough to be used interchangeably in many applications measure Revenueschema:MonetaryAmount
broader skos:broadMatch the external concept is the broader one; the artefact is a narrower notion of it measure Net Revenuecorp:Revenue
narrower skos:narrowMatch the external concept is the narrower one; the artefact covers more than it data object Customers (retail and corporate) → corp:RetailCustomer
related skos:relatedMatch associated, neither equivalent nor hierarchical metric Return Ratecorp:CustomerSatisfaction

The two hierarchical relations are the ones people get backwards, so once more with the same example:

measures:
  Net Revenue:
    externalConceptMappings:
      - concept: corp:Revenue        # Revenue in general
        relation: broader            # corp:Revenue is broader than Net Revenue
dataObjects:
  Customers:                         # all customers, retail and corporate
    externalConceptMappings:
      - concept: corp:RetailCustomer
        relation: narrower           # corp:RetailCustomer is narrower than Customers

Pick broader when the glossary term is the umbrella, narrower when your model object is the umbrella.

Rules the resolver enforces

One IRI carries one relation per artefact. Two entries on the same artefact that expand to the same IRI are DUPLICATE_CONCEPT_MAPPING when they agree on the relation and CONFLICTING_CONCEPT_MAPPING when they do not; the later entry is dropped and the artefact still loads, so every problem is reported at once. The same IRI on different artefacts is fine, and often exactly the point: Revenue maps exact and Revenue Doubled maps narrower to the same corp:NetRevenue.

Error code Cause
ONTOLOGY_PARSE_ERROR ontology or ontology.prefixes is not a mapping
INVALID_ONTOLOGY_PREFIX prefix name is not an identifier, namespace is not an absolute IRI, or a built-in prefix is rebound
UNKNOWN_ONTOLOGY_PREFIX a compact IRI uses a prefix that is neither declared nor built in (the message lists the known ones)
INVALID_CONCEPT_IRI blank node, relative reference, angle brackets, forbidden characters, empty local name
INVALID_CONCEPT_MAPPING an entry is not a mapping, relation is missing or unknown, justification unknown, confidence outside 0..1, or the list is not a list
DUPLICATE_CONCEPT_MAPPING same expanded IRI and relation twice on one artefact
CONFLICTING_CONCEPT_MAPPING same expanded IRI with two different relations on one artefact
ONTOLOGY_PREFIX_CONFLICT an extends fragment or an inheriting child binds an already-bound prefix to a different namespace

All of them carry the YAML source span. extends fragments and inheriting children may declare their own prefixes and model-level mappings; they are unioned into the merged model, and a fragment is held to the same strictness as a top-level document.

Reading mappings back

REST. The describe responses (schema, dimensions/{name}, measures/{name}, metrics/{name}) carry each artefact's mappings under external_concept_mappings, and schema adds ontology_prefixes. Three endpoints answer the cross-cutting questions, each with a top-level shortcut:

Endpoint Question
GET .../concept-mappings?concept=corp:NetRevenue which artefacts map to this concept? (also namespace=, relation=, types=)
GET .../concept-mappings/namespaces which external namespaces does the model link into, how much?
GET .../concept-mappings/unmapped which artefacts still have no mapping?

See the endpoint reference.

RDF and SPARQL. Every mapping is a direct skos:*Match triple from the artefact to the expanded IRI; a mapping with provenance also has an obsl:ExternalConceptMapping resource carrying it. The model's prefixes are bound on the graph. See OBSL Graph & SPARQL for a query.

OSI / Apache Ossie. ontology and every artefact's mappings survive the OBML → OSI → OBML round trip inside the ORIONBELT vendor extension of the corresponding OSI entity, since OSI has no native slot for them. See OSI Interoperability.

Guidance

Map what carries business identity. A measure that a KPI report is built on, a data object a glossary term names, a dimension that is the official classification. Mapping every artefact for completeness produces links nobody curated, which is worse than no link: prefer an unmapped report you can act on over lexical mappings you cannot trust.

Say how you know. justification, source and ontologyVersion are what let a reader, or an agent, decide how much weight a mapping deserves. A curated mapping with an approval comment is governance; a generated mapping at confidence: 0.6 is a suggestion.

Do not encode rules as mappings. "Orders over 10k are Strategic" is not a narrower mapping to corp:StrategicOrder; it is a rule with a threshold, and it will get its own OBML syntax. A mapping says what an artefact is, not when a row qualifies.

Keep one namespace per authority. If two teams publish overlapping glossaries, map to the one that owns the definition and record the other under source or comment rather than mapping both exact.

Correct:

measures:
  Gross Margin:
    externalConceptMappings:
      - concept: corp:GrossMargin
        relation: exact
        justification: curated
        source: finance-glossary
        ontologyVersion: "2026.1"

Not what you want:

measures:
  Gross Margin:
    externalConceptMappings:
      - concept: corp:GrossMargin
        relation: exact
      - concept: corp:Margin            # broader, not a second exact
        relation: exact
      - concept: corp:HighMarginOrder   # a rule, not a meaning
        relation: narrower
dataObjects:
  Orders:
    columns:
      Customer ID:
        externalConceptMappings:        # UNKNOWN_PROPERTY: columns identify, they do not mean
          - concept: corp:Customer
            relation: exact