Saltearse al contenido

Anotaciones semánticas de Saiku

El bloque genérico <Annotation> de Mondrian es una bolsa de clave/valor de forma libre adjunta a cualquier elemento del schema (Cube, Dimension, Hierarchy, Level, Measure, …). Saiku reserva el espacio de nombres saiku.semantic.* dentro de esa bolsa para un pequeño vocabulario tipado que impulsa:

  1. La capa AI Ask — las descripciones y sinónimos le dan al LLM contexto de negocio real; los tipos de agregación, granularidades y filtros requeridos mantienen cuerdas sus sugerencias de consulta.
  2. La protección de PII — el marcador saiku.semantic.pii=true cambia un nivel o medida a modo “estructuralmente presente pero opaco” en las superficies orientadas a agentes y bloquea el drillthrough, la exposición por compartir/embed, y las rutas de descarga para que no filtren los valores subyacentes.

Todas las claves son opcionales. Un schema sin ninguna anotación saiku.semantic.* corre idénticamente a uno sin el bloque de anotación; el espacio de nombres es puramente aditivo.

De un vistazo

Clave de anotaciónVálida enTipo / valoresPropósito
saiku.semantic.descriptionDimension · Measure · Leveltexto libreDescripción de negocio; expuesta en /ai/schema para que el LLM tenga contexto
saiku.semantic.synonymsDimension · Measure · Levellista CSVNombres alternativos para que la IA pueda resolver “country” → “Store Country”
saiku.semantic.unitMeasuretexto libre (p. ej. USD, kWh, count)Cadena de unidad; fluye a la forma de celda de IA {value, formatted, unit}
saiku.semantic.currencyMeasurecódigo ISO 4217 (p. ej. USD, EUR)Pista de moneda para medidas monetarias
saiku.semantic.aggregation_kindMeasureenum: sum · count · distinct-count · non-additiveSemántica de agregación. Impulsa la semántica de orden/total en la capa de IA.
saiku.semantic.cardinalityLevelenum: low · medium · highPista de recuento de miembros. Impulsa la UX del selector y las pistas de coste de la IA.
saiku.semantic.grainLevelenum: year · quarter · month · week · day · hour · minuteGranularidad de tiempo para el modal de filtro de fecha y la inferencia de gráficos de series temporales
saiku.semantic.required_filtersLevelCSV de pares (hierarchy, level)Niveles que la IA debe incluir en filters siempre que se toque este nivel
saiku.semantic.piiLevel · Measurebooleano (true / false)Marcador PII — vea Protección de PII abajo

Los valores desconocidos para los campos tipados por enum se registran en WARN con la lista permitida y por lo demás se ignoran — un error tipográfico no rompe el schema.

Dónde ponerlas

Las anotaciones se adjuntan a cualquier elemento del schema mediante un bloque hijo <Annotations> (XML) o una clave 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>

Los niveles aceptan la misma forma <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>

Protección de PII

Marcar un nivel o medida con saiku.semantic.pii=true lo inscribe en el stack de aplicación de PII de Saiku. La anotación es la declaración — Saiku superpone cuatro puntos de aplicación sobre ella.

1. Proyección del schema de IA — captions y muestras eliminados

El endpoint /ai/schema/{connection/catalog/schema/cube} alimenta al LLM la estructura del cubo. Para cualquier elemento marcado como PII elimina:

  • caption
  • description
  • synonyms
  • miembros de muestra (los valores de ejemplo que la guía del agente suele mostrar)

El nivel o medida sigue apareciendo estructuralmente (el agente sabe que existe y puede referenciarlo por nombre) pero los valores en sí permanecen opacos. El agente puede planificar consultas que incluyan la columna PII en la proyección sin ver jamás filas reales ni miembros de muestra.

2. returns= de drillthrough bloqueado

Las peticiones de drillthrough llevan un parámetro returns= listando las columnas a exportar. Si algún token en returns= resuelve a un nivel o medida marcado como PII, el resolvedor lanza AiPiiException y el endpoint devuelve 400 con la columna ofensora nombrada en el cuerpo. El agente puede reintentar con una proyección más estrecha que omita la columna PII.

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

3. Los tokens de embed/compartir auto-redactan

Cuando acuña un token de embed o de compartir vinculado a una consulta que toca un nivel marcado como PII, el inspector escala la política de redacción del token a FORCE_ON independientemente del por defecto del operador. Los receptores del token ven celdas redactadas incluso si el embed no se configuró explícitamente para redacción. Elimina el foot-gun de “olvidé activar la redacción” en enlaces compartidos.

4. Control de política de datos de IA

Las anotaciones PII son hechos a nivel de cubo. Se emparejan con la variable de entorno SAIKU_AI_POLICY, que es el dial a nivel de despliegue:

SAIKU_AI_POLICYQué ve la IA
schema-onlySolo schema + miembros de muestra. Ningún valor de cellset llega al proveedor.
aggregatedLos totales de celda agregados llegan al proveedor; las celdas a nivel de fila se eliminan.
row-levelLas celdas completas llegan al proveedor. Las anotaciones PII aún redactan detalles específicos.

La anotación dice “esto es sensible”; la política dice “cuántos datos sensibles dejamos pasar”. Juntas deciden qué ve la IA por turno. El por defecto es schema-only — los despliegues deben optar por los niveles más laxos.

Escáner pre-vuelo

PiiScanner corre sobre el schema de un cubo al arranque y registra líneas WARN para cualquier columna cuyo patrón de nombre parezca tener forma PII (coincide con *name*, *ssn*, *email*, *npi*, *dob*, etc.) pero no esté anotada. La advertencia incluye un fragmento XML listo para pegar para que el autor del schema pueda inscribir la columna sin buscar en la especificación:

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

El escáner nunca muta el schema — solo aflora candidatos. Los autores del schema deciden qué es realmente sensible.

Ejemplo trabajado — cubo demo Pharma

El schema demo Pharma se entrega con anotaciones PII en el nombre del prescriptor + NPI, y deja specialty + decile sin anotar (esos son operacionalmente seguros de compartir). Extracto de 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>

Con esto en su sitio, un agente de IA que pregunta “break down Quantity by Specialty” tiene éxito normalmente, pero “break down Quantity by Prescriber and download the rows” o bien rechaza (bloqueo de drillthrough) o devuelve cubos agregados con los nombres de prescriptor suprimidos (dependiendo del nivel de política de IA).

Ejemplo trabajado — cubo FoodMart

FoodMart se entrega con el conjunto completo de anotaciones descriptivas (sin columnas PII — datos sintéticos). Extraído de 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>

El mismo patrón escala a través de cada dim + level. Cada línea es independientemente opcional, así que puede desplegar las anotaciones de forma incremental.

Validación y valores desconocidos

  • Los campos tipados por enum (aggregation_kind, cardinality, grain) validan contra su lista permitida. Los valores desconocidos registran un WARN con el valor ofensor + la lista permitida y el campo queda sin definir por defecto.
  • Los campos booleanos (pii) aceptan true / false de forma insensible a mayúsculas tras recortar. Cualquier otra cosa es false. Los autores del schema obtienen el por defecto conservador si escriben mal.
  • Los campos de texto libre (description, unit, currency) se recortan; las cadenas vacías se vuelven null.
  • synonyms y required_filters parsean como CSV; las entradas vacías se descartan.

Relacionado

  • Exportar a Apache Ossie — cómo las anotaciones saiku.semantic.* sobreviven al round-trip a YAML Ossie portable (description + synonyms se elevan a ai_context; todo lo demás cabalga en custom_extensions como datos de proveedor SAIKU).
  • Extensiones conocidas de Ossie — el equivalente del lado de Ossie (saiku.display, saiku.roles, saiku.pii) para modelos YAML. Misma intención, distinto formato de archivo.
  • Extensiones: funciones y formateadores — el bloque genérico <Annotation> sobre el que se construye saiku.semantic.* (y su convención de metadatos de locale).
  • Schemas YAML — referencia YAML completa, incluyendo annotations: en cada elemento.
  • Control de acceso y roles — aplicación de acceso a nivel de schema (complementa las anotaciones PII: los ACL controlan quién puede consultar un cubo; las anotaciones PII controlan qué expone el resultado una vez que pueden).