Saiku-Semantik-Annotationen
Mondrians generischer <Annotation>-Block ist ein freiformiger Schlüssel/Wert-Beutel, der an jedes Schema-Element (Cube, Dimension, Hierarchy, Level, Measure, …) angehängt ist. Saiku reserviert den saiku.semantic.*-Namespace innerhalb dieses Beutels für ein kleines typisiertes Vokabular, das Folgendes antreibt:
- Die AI-Ask-Ebene — Beschreibungen und Synonyme geben dem LLM echten Business-Kontext; Aggregationsarten, Granularitäten und erforderliche Filter halten seine Abfragevorschläge vernünftig.
- PII-Schutz — der
saiku.semantic.pii=true-Marker versetzt ein Level oder Measure in den Modus „strukturell präsent, aber opak” in agent-zugewandten Oberflächen und blockiert, dass Drillthrough-, Share-/Embed-Freigabe- und Download-Pfade die zugrundeliegenden Werte leaken.
Alle Schlüssel sind optional. Ein Schema ohne jegliche saiku.semantic.*-Annotationen läuft identisch zu einem ohne den Annotation-Block; der Namespace ist rein additiv.
Auf einen Blick
| Annotation-Schlüssel | Gültig auf | Typ / Werte | Zweck |
|---|---|---|---|
saiku.semantic.description | Dimension · Measure · Level | Freitext | Business-Beschreibung; sichtbar in /ai/schema, sodass das LLM Kontext hat |
saiku.semantic.synonyms | Dimension · Measure · Level | CSV-Liste | Alternative Namen, sodass die AI „country” → „Store Country” auflösen kann |
saiku.semantic.unit | Measure | Freitext (z. B. USD, kWh, count) | Einheiten-String; fließt in die AI-Zellenform {value, formatted, unit} |
saiku.semantic.currency | Measure | ISO-4217-Code (z. B. USD, EUR) | Währungshinweis für monetäre Measures |
saiku.semantic.aggregation_kind | Measure | Enum: sum · count · distinct-count · non-additive | Aggregationssemantik. Treibt Sortier-/Total-Semantik in der AI-Ebene. |
saiku.semantic.cardinality | Level | Enum: low · medium · high | Member-Anzahl-Hinweis. Treibt Picker-UX und AI-Kosten-Hinweise. |
saiku.semantic.grain | Level | Enum: year · quarter · month · week · day · hour · minute | Zeit-Granularität für Datumsfilter-Modal und Zeitreihen-Chart-Inferenz |
saiku.semantic.required_filters | Level | CSV von (hierarchy, level)-Paaren | Levels, die die AI in filters einschließen muss, wann immer dieses Level berührt wird |
saiku.semantic.pii | Level · Measure | Boolean (true / false) | PII-Marker — siehe PII-Schutz unten |
Unbekannte Werte für die enum-typisierten Felder werden auf WARN mit der erlaubten Liste geloggt und ansonsten ignoriert — ein Tippfehler bricht das Schema nicht.
Wohin damit
Annotationen hängen an jedem Schema-Element über einen Kind-<Annotations>-Block (XML) oder einen annotations:-Schlüssel (YAML).
<Measure name="Quantity" column="quantity_units" aggregator="sum" formatString="#,##0"> <Annotations> <Annotation name="saiku.semantic.description">Total units prescribed (across all dispensings).</Annotation> <Annotation name="saiku.semantic.synonyms">units, quantity, scripts</Annotation> <Annotation name="saiku.semantic.unit">count</Annotation> <Annotation name="saiku.semantic.aggregation_kind">sum</Annotation> </Annotations></Measure>measures: - name: Quantity column: quantity_units aggregator: sum formatString: "#,##0" annotations: saiku.semantic.description: "Total units prescribed (across all dispensings)." saiku.semantic.synonyms: "units, quantity, scripts" saiku.semantic.unit: count saiku.semantic.aggregation_kind: sumLevels akzeptieren dieselbe <Annotations>-Form:
<Level name="Year" column="cal_year" type="Numeric" uniqueMembers="true" levelType="TimeYears"> <Annotations> <Annotation name="saiku.semantic.description">Calendar year.</Annotation> <Annotation name="saiku.semantic.synonyms">annual, yearly, fiscal year, y</Annotation> <Annotation name="saiku.semantic.cardinality">low</Annotation> <Annotation name="saiku.semantic.grain">year</Annotation> </Annotations></Level>- name: Year column: cal_year type: Numeric uniqueMembers: true levelType: TimeYears annotations: saiku.semantic.description: "Calendar year." saiku.semantic.synonyms: "annual, yearly, fiscal year, y" saiku.semantic.cardinality: low saiku.semantic.grain: yearPII-Schutz
Das Markieren eines Levels oder Measures mit saiku.semantic.pii=true meldet es in Saikus PII-Durchsetzungs-Stack an. Die Annotation ist die Deklaration — Saiku schichtet vier Durchsetzungspunkte darüber.
1. AI-Schema-Projektion — Captions und Samples entfernt
Der /ai/schema/{connection/catalog/schema/cube}-Endpunkt füttert dem LLM die Struktur des Cubes. Für jedes PII-markierte Element entfernt er:
captiondescriptionsynonyms- Sample-Members (die Beispielwerte, die Agent-Guidance üblicherweise zeigt)
Das Level oder Measure erscheint weiterhin strukturell (der Agent weiß, dass es existiert, und kann es namentlich referenzieren), aber die Werte selbst bleiben opak. Der Agent kann Abfragen planen, die die PII-Spalte in der Projektion einschließen, ohne je tatsächliche Zeilen oder Sample-Members zu sehen.
2. Drillthrough-returns= blockiert
Drillthrough-Anfragen tragen einen returns=-Parameter, der die zu exportierenden Spalten auflistet. Wenn irgendein Token in returns= auf ein PII-markiertes Level oder Measure auflöst, wirft der Resolver AiPiiException, und der Endpunkt gibt 400 mit der beanstandeten Spalte im Body benannt zurück. Der Agent kann mit einer engeren Projektion erneut versuchen, die die PII-Spalte auslässt.
HTTP 400{ "error": "Column 'Prescriber' is annotated PII (saiku.semantic.pii=true) and cannot be returned via drillthrough."}3. Embed-/Share-Tokens auto-redigieren
Wenn Sie einen Embed- oder Share-Token minten, der an eine Abfrage gebunden ist, die ein PII-markiertes Level berührt, eskaliert der Inspector die Redaktionsrichtlinie des Tokens auf FORCE_ON, unabhängig vom Standard des Operators. Empfänger des Tokens sehen redigierte Zellen, selbst wenn das Embed nicht explizit für Redaktion konfiguriert war. Beseitigt das „Ich habe vergessen, Redaktion einzuschalten”-Fußgeschütz auf geteilten Links.
4. AI-Datenrichtlinien-Gating
PII-Annotationen sind cube-level-Fakten. Sie paaren sich mit der SAIKU_AI_POLICY-Umgebungsvariable, die der deployment-level-Regler ist:
SAIKU_AI_POLICY | Was die AI sieht |
|---|---|
schema-only | Nur Schema + Sample-Members. Keine Cellset-Werte erreichen den Provider. |
aggregated | Aggregierte Zellsummen erreichen den Provider; Row-Level-Zellen entfernt. |
row-level | Volle Zellen erreichen den Provider. PII-Annotationen redigieren dennoch Spezifika. |
Die Annotation sagt „das ist sensibel”; die Richtlinie sagt „so viel sensible Daten lassen wir durch”. Zusammen entscheiden sie, was die AI pro Turn sieht. Der Standard ist schema-only — Deployments müssen sich für lockerere Stufen entscheiden.
Pre-Flight-Scanner
PiiScanner läuft beim Start über das Schema eines Cubes und loggt WARN-Zeilen für jede Spalte, deren Namensmuster PII-förmig aussieht (matcht gegen *name*, *ssn*, *email*, *npi*, *dob*, etc.), aber nicht annotiert ist. Die Warnung enthält einen einfügefertigen XML-Snippet, sodass der Schema-Autor die Spalte anmelden kann, ohne durch die Spezifikation zu jagen:
WARN [PiiScanner] Likely PII column 'prescribername' on level [Prescriber].[Prescriber] is not annotated. Add: <Annotations> <Annotation name="saiku.semantic.pii">true</Annotation> </Annotations>Der Scanner mutiert das Schema nie — er bringt nur Kandidaten zum Vorschein. Schema-Autoren entscheiden, was tatsächlich sensibel ist.
Durchgearbeitetes Beispiel — Pharma-Demo-Cube
Das Pharma-Demo-Schema wird mit PII-Annotationen auf Prescriber-Name + NPI ausgeliefert und lässt Specialty + Decile un-annotiert (die sind operativ sicher zu teilen). Auszug aus saiku-home/data/Pharma.xml:
<Dimension name="Prescriber" foreignKey="prescriberkey"> <Hierarchy hasAll="true" primaryKey="prescriberkey"> <Table name="dim_prescriber" schema="public"/> <Level name="Specialty" column="specialty" uniqueMembers="false"/> <Level name="Decile" column="decile" type="Numeric" uniqueMembers="false"/> <Level name="Prescriber" column="prescriberkey" nameColumn="prescribername" type="Numeric" uniqueMembers="true"> <Annotations> <Annotation name="saiku.semantic.pii">true</Annotation> </Annotations> </Level> </Hierarchy> <Hierarchy name="NPI" hasAll="true" primaryKey="prescriberkey"> <Table name="dim_prescriber" schema="public"/> <Level name="NPI" column="prescribernpi" type="Numeric" uniqueMembers="true"> <Annotations> <Annotation name="saiku.semantic.pii">true</Annotation> </Annotations> </Level> </Hierarchy></Dimension>Mit diesem an Ort und Stelle gelingt einem AI-Agenten, der „break down Quantity by Specialty” fragt, das normal, aber „break down Quantity by Prescriber and download the rows” verweigert entweder (Drillthrough-Block) oder gibt aggregierte Buckets mit unterdrückten Prescriber-Namen zurück (abhängig von der AI-Richtlinienstufe).
Durchgearbeitetes Beispiel — FoodMart-Cube
FoodMart wird mit dem vollständigen deskriptiven Annotation-Satz ausgeliefert (keine PII-Spalten — synthetische Daten). Entnommen aus saiku-home/data/FoodMart4.xml:
<Level name="Store Country" column="store_country" uniqueMembers="true"> <Annotations> <Annotation name="saiku.semantic.description">Store's country.</Annotation> <Annotation name="saiku.semantic.synonyms">nation, country code</Annotation> <Annotation name="saiku.semantic.cardinality">low</Annotation> </Annotations></Level><Level name="Year" column="the_year" type="Numeric" uniqueMembers="true" levelType="TimeYears"> <Annotations> <Annotation name="saiku.semantic.description">Calendar year.</Annotation> <Annotation name="saiku.semantic.synonyms">annual, yearly, fiscal year, y</Annotation> <Annotation name="saiku.semantic.cardinality">low</Annotation> <Annotation name="saiku.semantic.grain">year</Annotation> </Annotations></Level>Dasselbe Muster skaliert über jede Dim + jedes Level. Jede Zeile ist unabhängig optional, sodass Sie die Annotationen inkrementell ausrollen können.
Validierung und unbekannte Werte
- Enum-typisierte Felder (
aggregation_kind,cardinality,grain) validieren gegen ihre erlaubte Liste. Unbekannte Werte loggen einenWARNmit dem beanstandeten Wert + der erlaubten Liste, und das Feld setzt auf unset zurück. - Boolean-Felder (
pii) akzeptierentrue/falseohne Beachtung von Groß-/Kleinschreibung nach Trim. Alles andere istfalse. Schema-Autoren bekommen den konservativen Standard, wenn sie sich vertippen. - Freitext-Felder (
description,unit,currency) werden getrimmt; leere Strings werden zunull. synonymsundrequired_filtersparsen als CSV; leere Einträge werden verworfen.
Verwandt
- Export nach Apache Ossie — wie die
saiku.semantic.*-Annotationen den Round-Trip in portables Ossie-YAML überstehen (Description + Synonyms heben sich inai_context; alles andere reitet incustom_extensionsals SAIKU-Vendor-Daten). - Wohlbekannte Ossie-Extensions — das Ossie-seitige Äquivalent (
saiku.display,saiku.roles,saiku.pii) für YAML-Modelle. Gleiche Absicht, anderes Dateiformat. - Extensions: Funktionen und Formatter — der generische
<Annotation>-Block, auf demsaiku.semantic.*aufbaut (und seine Locale-Metadaten-Konvention). - YAML-Schemas — vollständige YAML-Referenz, einschließlich
annotations:auf jedem Element. - Zugriffskontrolle und Rollen — Zugriffsdurchsetzung auf Schema-Ebene (ergänzt PII-Annotationen: ACLs regeln, wer einen Cube abfragen kann; PII-Annotationen regeln, was das Ergebnis freilegt, sobald sie es können).