Skip to content

Exporting to Apache Ossie

Apache Ossie (formerly Open Semantic Interchange) is an incubating Apache project defining a portable YAML/JSON specification for semantic model exchange across analytics, AI, and BI tools. Saiku ships an exporter that reads any Mondrian schema and produces a valid Ossie document — the same measure and dimension definitions become consumable by dbt, GoodData, Snowflake, Databricks, Salesforce, and every other tool with an Ossie converter.

Quick start

Pass a Mondrian XML schema in, get Ossie YAML out:

Terminal window
java -jar saiku-launcher/target/saiku-4.6.0.jar ossie-export \
--in saiku-home/data/Pharma.xml \
--out pharma.ossie.yaml

Or use stdin/stdout for scripting:

Terminal window
cat schema.xml | saiku ossie-export > schema.ossie.yaml

The command exits non-zero if input can’t be read (exit 2) or output can’t be written (exit 3), with a diagnostic line on stderr. Successful runs report how many semantic models were written and (if any) which cubes were skipped:

ossie-export: wrote 1 semantic model(s) to pharma.ossie.yaml

What maps to what

The exporter follows this mapping table 1:1. Everything except explicitly-listed exceptions lands in the target column verbatim.

Mondrian elementOssie output
<Cube>One semantic_model entry
Cube’s fact <Table name="..." schema="..."/>First dataset, source: "<schema>.<table>"
<Dimension foreignKey="..."> with <Hierarchy><Table/>One dim dataset per hierarchy, plus one relationship from fact.foreignKey → dim.primaryKey
<Level name="..." column="..."/>One field on the dim (or fact, for degenerate dims), with expression.dialects[0]=ANSI_SQL:column
<Level ... levelType="TimeYears"> (or Quarters/Months/Days)Field gains dimension.is_time: true
<Measure name="..." column="..." aggregator="sum"/>One metric with both ANSI_SQL (SUM(fact.column)) and MDX ([Measures].[Name]) dialects
<Measure aggregator="distinct-count">ANSI_SQL: COUNT(DISTINCT fact.column) — plus count, min, max, avg all translate
<CalculatedMember><Formula>...</Formula></CalculatedMember>Metric with MDX-only expression (no reliable ANSI SQL translation for MDX formulas)
<Annotation name="saiku.semantic.description">Element’s ai_context.instructions
<Annotation name="saiku.semantic.synonyms">Element’s ai_context.synonyms[] (CSV split, trimmed)
<Annotation name="saiku.semantic.pii">truecustom_extensions: [{vendor_name: SAIKU, data: '{"pii":true}'}] — JSON boolean, not string
<Annotation name="saiku.semantic.{cardinality,grain,aggregation_kind,required_filters}">Same SAIKU vendor extension, values serialised as JSON strings

Worked example — Pharma cube

Input excerpt from saiku-home/data/Pharma.xml:

<Cube name="Pharma Rx">
<Table name="fact_pharma" schema="public"/>
<Dimension name="Prescriber" foreignKey="prescriberkey">
<Hierarchy hasAll="true" primaryKey="prescriberkey">
<Table name="dim_prescriber" schema="public"/>
<Level name="Prescriber" column="prescriberkey" nameColumn="prescribername"
type="Numeric" uniqueMembers="true">
<Annotations>
<Annotation name="saiku.semantic.pii">true</Annotation>
</Annotations>
</Level>
</Hierarchy>
</Dimension>
<Measure name="Quantity" column="quantity_units" aggregator="sum" formatString="#,##0"/>
</Cube>

Produces this Ossie fragment:

version: 0.2.0.dev0
semantic_model:
- name: Pharma Rx
datasets:
- name: fact_pharma
source: public.fact_pharma
description: Fact table for cube 'Pharma Rx'.
- name: Prescriber
source: public.dim_prescriber
primary_key:
- prescriberkey
fields:
- name: Prescriber
expression:
dialects:
- dialect: ANSI_SQL
expression: prescriberkey
custom_extensions:
- vendor_name: SAIKU
data: "{\"pii\":true}"
relationships:
- name: fact_pharma_to_Prescriber
from: fact_pharma
to: Prescriber
from_columns:
- prescriberkey
to_columns:
- prescriberkey
metrics:
- name: Quantity
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(fact_pharma.quantity_units)
- dialect: MDX
expression: "[Measures].[Quantity]"

What isn’t (yet) supported

The first-cut converter handles the classic Mondrian 3–4 hybrid shape used by Pharma, Bank, and most customer schemas. It doesn’t yet handle:

  • Mondrian 4 <MeasureGroups> / <Dimensions> wrapper shape. FoodMart uses this. Cubes with this shape get skipped (reported to stderr) rather than emitted as schema-invalid stubs. Follow-up work tracked on the parent Ossie/SQL epic.
  • Virtual cubes (<VirtualCube>) — including our Warehouse-and-Sales example. Skipped like above.
  • Parent-child hierarchies. Emitted as flat levels; the hierarchical relationship isn’t representable in Ossie’s current dataset-oriented shape (the Ossie hierarchy working group is in flight — see the Ossie roadmap).
  • Shared dimensions consumed via <DimensionUsage source=...>. Only the classic per-cube <Dimension> embedding works today.

When Ossie’s hierarchy story stabilises (target: v0.3.0+) and Saiku’s Mondrian-4 MG converter lands, this table will shrink.

Consuming the output

Ossie YAML is validation-checked against apache/ossie’s osi-schema.json — every file the exporter produces round-trips through the schema with zero findings (there’s a unit test that asserts this on every commit). Downstream consumers:

  • dbt — Ossie’s reference converters include a dbt module.
  • Snowflake, Salesforce, GoodData, Polaris, Databricks — same directory.
  • Apache Superset and Metabase — no first-party converter yet at time of writing, but the SQL-over-Ossie work on the Saiku roadmap (parent epic saiku#1387) will make Saiku itself queryable as a semantic layer via SQL.
  • Saiku semantic annotations — the annotation keys the exporter reads (which map into Ossie’s ai_context + custom_extensions).
  • Well-known Ossie extensions — the receiving end. Once your schema exports to Ossie YAML, the saiku.display / saiku.roles / saiku.pii well-knowns are how you author annotations directly there.
  • Schema structure — where the <Annotations> block lives inside your Mondrian schema.
  • apache/ossie repository — upstream spec, converters, roadmap.