Przejdź do głównej zawartości

Adnotacje semantyczne Saiku

Generyczny blok <Annotation> Mondriana to worek klucz/wartość o dowolnej formie dołączony do dowolnego elementu schemy (Cube, Dimension, Hierarchy, Level, Measure, …). Saiku rezerwuje przestrzeń nazw saiku.semantic.* wewnątrz tego worka na małe typowane słownictwo, które napędza:

  1. Warstwę AI Ask — opisy i synonimy dają LLM realny kontekst biznesowy; rodzaje agregacji, ziarna i wymagane filtry utrzymują jego propozycje zapytań w ryzach.
  2. Ochronę PII — marker saiku.semantic.pii=true przełącza poziom lub miarę w tryb „strukturalnie obecny, ale nieprzezroczysty” na powierzchniach zwróconych do agentów i blokuje drillthrough, ekspozycję share/embed oraz ścieżki pobierania przed wyciekiem wartości bazowych.

Wszystkie klucze są opcjonalne. Schema bez żadnych adnotacji saiku.semantic.* działa identycznie jak jedna bez bloku adnotacji; przestrzeń nazw jest czysto addytywna.

W skrócie

Klucz adnotacjiWażny naTyp / wartościCel
saiku.semantic.descriptionDimension · Measure · Levelwolny tekstOpis biznesowy; ujawniany w /ai/schema, aby LLM miał kontekst
saiku.semantic.synonymsDimension · Measure · Levellista CSVAlternatywne nazwy, aby AI mogło rozwiązać „country” → „Store Country”
saiku.semantic.unitMeasurewolny tekst (np. USD, kWh, count)Łańcuch jednostki; wpływa do kształtu komórki AI {value, formatted, unit}
saiku.semantic.currencyMeasurekod ISO 4217 (np. USD, EUR)Wskazówka waluty dla miar pieniężnych
saiku.semantic.aggregation_kindMeasureenum: sum · count · distinct-count · non-additiveSemantyka agregacji. Napędza semantykę sortowania/sumy w warstwie AI.
saiku.semantic.cardinalityLevelenum: low · medium · highWskazówka liczby członków. Napędza UX pickera i wskazówki kosztu AI.
saiku.semantic.grainLevelenum: year · quarter · month · week · day · hour · minuteZiarno czasu dla modala filtra dat i wnioskowania wykresu szeregu czasowego
saiku.semantic.required_filtersLevelCSV par (hierarchy, level)Poziomy, które AI musi zawrzeć w filters zawsze, gdy ten poziom jest dotknięty
saiku.semantic.piiLevel · Measureboolean (true / false)Marker PII — zobacz Ochrona PII niżej

Nieznane wartości dla pól typu enum są logowane na poziomie WARN z dozwoloną listą i poza tym ignorowane — literówka nie psuje schemy.

Gdzie je umieścić

Adnotacje dołączają się do dowolnego elementu schemy przez potomny blok <Annotations> (XML) lub klucz annotations: (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>

Poziomy akceptują ten sam kształt <Annotations>:

<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>

Ochrona PII

Oznaczenie poziomu lub miary przez saiku.semantic.pii=true włącza je do stosu wymuszania PII w Saiku. Adnotacja jest deklaracją — Saiku nakłada na nią cztery punkty wymuszania.

1. Projekcja schemy AI — captiony i próbki usunięte

Endpoint /ai/schema/{connection/catalog/schema/cube} podaje LLM strukturę kostki. Dla każdego elementu oznaczonego PII usuwa:

  • caption
  • description
  • synonyms
  • przykładowych członków (przykładowe wartości, które wskazówki dla agenta zwykle pokazują)

Poziom lub miara nadal pojawia się strukturalnie (agent wie, że istnieje, i może się do niej odwołać po nazwie), ale same wartości pozostają nieprzezroczyste. Agent może planować zapytania zawierające kolumnę PII w projekcji bez oglądania faktycznych wierszy czy przykładowych członków.

2. Drillthrough returns= zablokowany

Żądania drillthrough niosą parametr returns= listujący kolumny do eksportu. Jeśli którykolwiek token w returns= rozwiązuje się na poziom lub miarę oznaczoną PII, resolver rzuca AiPiiException, a endpoint zwraca 400 z nazwaną w ciele obrażającą kolumną. Agent może spróbować ponownie z węższą projekcją, która pomija kolumnę PII.

HTTP 400
{
"error": "Column 'Prescriber' is annotated PII (saiku.semantic.pii=true) and cannot be returned via drillthrough."
}

3. Tokeny embed/share auto-redagują

Gdy wybijasz token embedu lub share związany z zapytaniem, które dotyka poziomu oznaczonego PII, inspektor eskaluje politykę redakcji tokenu do FORCE_ON niezależnie od domyślnej operatora. Odbiorcy tokenu widzą zredagowane komórki, nawet jeśli embed nie był jawnie skonfigurowany na redakcję. Eliminuje pułapkę „zapomniałem włączyć redakcję” na współdzielonych linkach.

4. Bramkowanie polityki danych AI

Adnotacje PII to fakty na poziomie kostki. Łączą się w parę ze zmienną środowiskową SAIKU_AI_POLICY, która jest pokrętłem na poziomie wdrożenia:

SAIKU_AI_POLICYCo widzi AI
schema-onlyTylko schema + przykładowi członkowie. Żadne wartości cellsetu nie docierają do dostawcy.
aggregatedZagregowane sumy komórek docierają do dostawcy; komórki na poziomie wierszy usunięte.
row-levelPełne komórki docierają do dostawcy. Adnotacje PII nadal redagują szczegóły.

Adnotacja mówi „to jest wrażliwe”; polityka mówi „tyle wrażliwych danych przepuszczamy”. Razem decydują, co AI widzi na turę. Domyślnie to schema-only — wdrożenia muszą świadomie włączyć luźniejsze poziomy.

Skaner pre-flight

PiiScanner przebiega po schemie kostki przy starcie i loguje linie WARN dla każdej kolumny, której wzorzec nazwy wygląda na kształt PII (dopasowuje się do *name*, *ssn*, *email*, *npi*, *dob* itd.), ale nie jest adnotowana. Ostrzeżenie zawiera gotowy do wklejenia fragment XML, aby autor schemy mógł włączyć kolumnę bez polowania po specyfikacji:

WARN [PiiScanner] Likely PII column 'prescribername' on level [Prescriber].[Prescriber] is not annotated. Add:
<Annotations>
<Annotation name="saiku.semantic.pii">true</Annotation>
</Annotations>

Skaner nigdy nie mutuje schemy — jedynie ujawnia kandydatów. Autorzy schemy decydują, co jest faktycznie wrażliwe.

Przykład — kostka demo Pharma

Schema demo Pharma dostarczana jest z adnotacjami PII na nazwie prescribera + NPI, a pozostawia specialty + decile bez adnotacji (te są operacyjnie bezpieczne do udostępniania). Wyciąg z 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>

Z tym na miejscu agent AI pytający „break down Quantity by Specialty” odnosi sukces normalnie, ale „break down Quantity by Prescriber and download the rows” albo odmawia (blokada drillthrough), albo zwraca zagregowane kubełki ze stłumionymi nazwami prescriberów (zależnie od poziomu polityki AI).

Przykład — kostka FoodMart

FoodMart dostarczany jest z pełnym opisowym zestawem adnotacji (brak kolumn PII — dane syntetyczne). Zaczerpnięte z 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>

Ten sam wzorzec skaluje się na każdy wymiar + poziom. Każda linia jest niezależnie opcjonalna, więc możesz wdrażać adnotacje przyrostowo.

Walidacja i nieznane wartości

  • Pola typu enum (aggregation_kind, cardinality, grain) walidują się względem swojej dozwolonej listy. Nieznane wartości logują WARN z obrażającą wartością + dozwoloną listą, a pole domyślnie przyjmuje wartość nieustawioną.
  • Pola boolean (pii) akceptują true / false bez rozróżniania wielkości liter po przycięciu. Cokolwiek innego to false. Autorzy schemy dostają konserwatywną wartość domyślną, jeśli się pomylą.
  • Pola wolnego tekstu (description, unit, currency) są przycinane; puste łańcuchy stają się null.
  • synonyms i required_filters parsują się jako CSV; puste wpisy są odrzucane.

Powiązane

  • Eksport do Apache Ossie — jak adnotacje saiku.semantic.* przeżywają round-trip do przenośnego YAML-a Ossie (description + synonyms podnoszą się do ai_context; wszystko inne jedzie w custom_extensions jako dane dostawcy SAIKU).
  • Dobrze znane rozszerzenia Ossie — odpowiednik po stronie Ossie (saiku.display, saiku.roles, saiku.pii) dla modeli YAML. Ten sam zamiar, inny format pliku.
  • Rozszerzenia: funkcje i formattery — generyczny blok <Annotation>, na którym buduje się saiku.semantic.* (i jego konwencja metadanych lokalizacji).
  • Schemy YAML — pełna referencja YAML, w tym annotations: na każdym elemencie.
  • Kontrola dostępu i role — wymuszanie dostępu na poziomie schemy (uzupełnia adnotacje PII: ACL-e bramkują kto może odpytać kostkę; adnotacje PII bramkują co wynik ujawnia, gdy już mogą).