API AI Query — cubos OLAP
La API AI Query permite a un agente consultar un cubo OLAP Mondrian sin ver ni escribir jamás MDX. El agente obtiene un schema autodescriptivo, rellena una petición JSON contra él, el servidor valida cada nombre, ejecuta, y devuelve registros tipados. Si un nombre está mal, el error le dice al agente exactamente qué corregir — sin ingeniería de prompts requerida.
Esta es la contraparte OLAP de la
API AI Query para modelos Ossie (la superficie
SQL/YAML-semántico). La misma disciplina, las mismas barandillas; esta
trabaja contra cubos Mondrian en lugar de YAML de Ossie. Sobre ella se
sienta la capa de lenguaje natural /ai/ask — el
endpoint de ask traduce una pregunta en inglés llano exactamente al
cuerpo de petición documentado aquí.
Orientación rápida
Tres endpoints cubren ~90% del uso de los agentes:
| Endpoint | Propósito |
|---|---|
GET /rest/saiku/api/ai/cubes | Lista cada cubo que el llamador puede consultar. |
GET /rest/saiku/api/ai/schema/{cubeId} | Schema autodescriptivo — medidas, dimensiones, jerarquías, niveles, miembros de muestra, sinónimos, y el JSON Schema de la petición. |
POST /rest/saiku/api/ai/query | Ejecuta una petición tipada. Respuesta en formato de registros por defecto; matrix en ?format=matrix. |
Endpoints de cola larga (documentados en las páginas enlazadas):
| Endpoint | Propósito |
|---|---|
GET /rest/saiku/api/ai/members/search | Búsqueda por subcadena de miembros en un nivel. |
POST /rest/saiku/api/ai/scenario/whatif | Simulación what-if con write-back. |
POST /rest/saiku/api/ai/query/execute-async | Envía para ejecución en segundo plano (consulte status / result). |
POST /rest/saiku/api/ai/anomaly | Ejecuta la consulta y luego marca anomalías a lo largo de un eje temporal. |
POST /rest/saiku/api/ai/forecast | Proyecta puntos futuros (ETS / ARIMA / Prophet). |
POST /rest/saiku/api/ai/ask | Pregunta en lenguaje natural. Necesita una clave de LLM. |
El cubeId en todas partes es el cuádruple
connection/catalog/schema/cubeName unido con /. Todos los endpoints
requieren una sesión autenticada; los endpoints POST requieren el par
cookie/cabecera CSRF.
Paso 1 — listar los cubos
GET /rest/saiku/api/ai/cubes[ { "connectionName": "unknown_foodmart", "catalog": "FoodMart", "schema": "FoodMart", "cubeName": "Sales", "cubeCaption": "Sales", "defaultMeasure": "Unit Sales", "measureCount": 8 }]El cuádruple connectionName/catalog/schema/cubeName es el
identificador de cubo usado en todo lo demás.
Paso 2 — obtener el schema tipado
GET /rest/saiku/api/ai/schema/unknown_foodmart/FoodMart/FoodMart/SalesNo codifique en URL las barras — la plantilla de ruta acepta la forma
multi-segmento connection/catalog/schema/cubeName directamente. La
respuesta es densa — esto es lo que hace la API autodescriptiva:
{ "cubeId": "unknown_foodmart/FoodMart/FoodMart/Sales", "measures": { "store sales": { "name": "Store Sales", "uniqueName": "[Measures].[Store Sales]", "description": "Net retail revenue in USD across all transactions.", "synonyms": ["revenue", "turnover", "top-line"], // accepted as `name` on input "unit": "USD", "aggregationKind": "sum" } // …8 measures total… }, "measureAliases": { "revenue": "store sales", "turnover": "store sales" }, "dimensions": { "time": { "name": "Time", "uniqueName": "[Time]", "hierarchies": { "time by": { "name": "Time By", "levels": { "quarter": { "name": "Quarter", "synonyms": ["quarterly", "qtr"], // accepted as `level` on input "sampleMembers": [ { "caption": "Q1", "uniqueName": "[Time].[Time By].[Quarter].&[Q1]" } ] } } } } } }}Los sinónimos y alias de nombre para mostrar se aceptan como entrada en
cualquier sitio donde se acepte el name canónico — un agente puede
decir "revenue" y el servidor lo resuelve a Store Sales.
Paso 3 — ejecutar una consulta
“Muestra Store Sales y Unit Sales por Product Family, top 3 por Store Sales.”
POST /rest/saiku/api/ai/queryContent-Type: application/json{ "cube": "unknown_foodmart/FoodMart/FoodMart/Sales", "measures": [{ "name": "Store Sales" }, { "name": "Unit Sales" }], "rows": [{ "dimension": "Product", "hierarchy": "Products", "level": "Product Family" }], "order": [{ "by": "Store Sales", "direction": "desc" }], "limit": 3}cube acepta o bien la forma de objeto de 4 segmentos o bien la cadena
compacta "connection/catalog/schema/cube".
Respuesta (200):
{ "status": "SUCCESS", "format": "records", "metadata": { "generatedMdx": "SELECT NON EMPTY {[Measures].[Store Sales], [Measures].[Unit Sales]} ON COLUMNS, NON EMPTY TopCount([Product].[Products].[Product Family].Members, 3, [Measures].[Store Sales]) ON ROWS FROM [Sales]", "freshness": { "computedAtMillis": 1715798421042, "cached": false } }, "data": [ { "Product Family": "Food", "Store Sales": { "value": 409035.59, "formatted": "409,035.59", "unit": null }, "Unit Sales": { "value": 191940.0, "formatted": "191,940", "unit": null } } ], "totalRows": 3, "runtimeMs": 421}Cada fila es un objeto autodescriptivo indexado por el caption de columna legible por humanos. Cada celda numérica es un sobre tipado:
value— número parseado (para matemáticas / ordenación / graficado)formatted— la cadena de visualización pre-formateada de Mondrian (para la UI)unit— inferida de la cadena formateada (USD,GBP,EUR,JPY,%) onull
generatedMdx se devuelve para depuración; los agentes normalmente lo
ignoran.
Formato matrix
Los clientes indexados por posición se salen de los registros con
?format=matrix — la respuesta lleva matrix en lugar de data, cada
fila indexada por el índice de columna como cadena, las celdas siguen
siendo el sobre tipado {value, formatted, unit}.
Privacidad: k-anonimato
Cuando ai.kAnonymity está definido (por defecto 5; 0 lo
deshabilita), el servidor enmascara los valores de medida de celdas
pequeñas antes de que el resultado cruce la frontera de la IA — cualquier
fila cuya medida de recuento en el resultado cae por debajo de k tiene
sus celdas de medida enmascaradas con suppressed: true. Aplica a
registros y matrix, y a los endpoints derivados /ai/anomaly +
/ai/forecast.
Paso 4 — la validación enseña al agente
Suministre un nombre que no resuelve y el servidor devuelve 400 con un cuerpo del que el agente puede autocorregirse — sin necesidad de reintentar mediante prompts:
{ "status": "VALIDATION_ERROR", "error": "Unknown measure 'Made Up Measure'", "field": "measures[].name", "available": ["Unit Sales", "Store Cost", "Store Sales", "Profit", "Customer Count"]}El agente lee field (qué estuvo mal), lee available[] (los valores
legales), corrige y reintenta. Corren dos capas: un validador de
forma (JSON Schema — campos faltantes, tipos incorrectos, violaciones
de enum, con rutas de campo indexadas por array como filters[0].op) y
un validador semántico (resolución del cubo — nombres que son
válidos en forma pero no existen). El contrato es idéntico en cualquier
caso: lea field, lea available[], corrija, reintente.
A dónde ir después
- API AI Ask — la capa de lenguaje natural que produce el
cuerpo de petición de arriba, más los endpoints compañeros
members/search,scenario/whatifypii-suggestions. - Agent Spaces — personas que limitan esta superficie a un conjunto de cubos en lista de permitidos.
- Agent Skills — flujos de trabajo escritos por admins, descubribles desde cada ask.
- Servidor MCP — la misma superficie tipada para hosts de
agentes externos (
list_cubes,describe_cube,run_query, …). - API AI Query para modelos Ossie — la contraparte SQL/YAML-semántico.
- API de inferencia de IA — una superficie diferente: el diseñador de cubos en tiempo de diseño (profile → propose → render), no la ejecución de consultas.