Consultando JSON anidado
Telemetry convierte objetos JSON anidados en rutas de campo de puntos consultables. Esto mantiene unido el contexto relacionado en el momento de la ingesta y, al mismo tiempo, mantiene los valores individuales disponibles para SQL.
Esta guía cubre la ruta completa desde un contrato de evento hasta filtros, agregados, cambios de esquema y solución de problemas. Inspeccione el esquema de la tabla antes de copiar una consulta: la ortografía y el tipo exacto del identificador provienen de los eventos que envió.
Diseñar un evento anidado estable
Utilice objetos anidados cuando los campos formen un concepto duradero. Mantenga los valores escritos, omita cargas útiles confidenciales y evite colocar estructuras que cambian con frecuencia en una matriz.
{
"event_name": "tool_call_completed",
"event_id": "evt_7f31",
"account_id": "acct_8f31",
"release": "2026.07.3",
"workflow": {
"name": "answer_question",
"version": "v2"
},
"tool": {
"name": "inventory_lookup",
"outcome": "success",
"duration_ms": 184,
"usage": {
"input_units": 820,
"output_units": 244
}
}
}
El grano de fila es una llamada de herramienta completa. tool.duration_ms es siempre numérico, tool.outcome proviene de un conjunto controlado y los identificadores son seudónimos. Los argumentos de solicitud, las indicaciones del modelo, el contenido generado, las credenciales y los mensajes de error sin procesar están deliberadamente ausentes.
Envía el objeto a través del SDK:
await telemetry.log("tool_call_completed", event);
El registro API agrega el tiempo del evento administrado utilizado en las consultas y elimina de forma recursiva valores nulos, objetos vacíos y matrices vacías. Lea tipos de datos de eventos y capacidad de nulidad antes de utilizar un valor vacío como estado comercial.
Inspeccione antes de agregar
Comience con una muestra acotada. Según el esquema de la tabla, una ruta anidada puede aparecer como un identificador compuesto o requerir un identificador de puntos entre comillas dobles:
SELECT
timestamp_utc,
event_id,
workflow.name,
tool.name,
tool.outcome,
tool.duration_ms
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '1 hour'
ORDER BY timestamp_utc DESC
LIMIT 50;
Si el esquema expone un nombre de columna de puntos literal, cite la ruta completa:
SELECT
"workflow.name",
"tool.name",
"tool.duration_ms"
FROM tool_call_completed
LIMIT 50;
No cambie entre formas entre comillas y sin comillas mediante conjeturas. Verifique el esquema de la tabla, ejecute una pequeña muestra y use el formulario que coincida con el campo almacenado.
Filtrar y agregar campos anidados
Los campos anidados funcionan en filtros, grupos, cálculos y ordenamiento. Esta consulta compara el volumen de la herramienta, las fallas y la duración de p95 en una ventana completa y limitada:
SELECT
tool.name AS tool_name,
COUNT(*) AS calls,
SUM(CASE WHEN tool.outcome = 'error' THEN 1 ELSE 0 END) AS errors,
100.0 * SUM(CASE WHEN tool.outcome = 'error' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS error_rate_pct,
approx_percentile_cont(tool.duration_ms, 0.95) AS p95_duration_ms
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
AND workflow.name = 'answer_question'
GROUP BY tool.name
HAVING COUNT(*) >= 20
ORDER BY error_rate_pct DESC, calls DESC;
Si su tabla utiliza identificadores de puntos entre comillas, cite cada ruta completa en la misma consulta:
SELECT
"tool.name" AS tool_name,
approx_percentile_cont("tool.duration_ms", 0.95) AS p95_duration_ms
FROM tool_call_completed
WHERE "workflow.name" = 'answer_question'
GROUP BY "tool.name";
Manejar los caminos faltantes deliberadamente
Una fila anterior creada antes de que se introdujera tool.usage.output_units no tendrá ese campo. Un nuevo evento con un valor nulo, de objeto vacío o de matriz vacía tampoco almacena ningún valor para esa ruta después de la normalización.
Utilice IS NULL para medir la cobertura antes de confiar en un nuevo campo:
SELECT
release,
COUNT(*) AS calls,
SUM(CASE WHEN tool.usage.output_units IS NULL THEN 1 ELSE 0 END)
AS missing_output_units,
100.0 * SUM(CASE WHEN tool.usage.output_units IS NULL THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS missing_rate_pct
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY release
ORDER BY release;
No reemplace un número faltante con cero a menos que cero sea el significado comercial correcto. “No informado”, “no aplicable” y un cero medido real son estados diferentes.
Evoluciona caminos anidados de forma segura
Trate cada ruta de puntos como un contrato de esquema:
| Cambiar | Efecto | Implementación más segura |
|---|---|---|
Añadir tool.usage.cache_hit |
Las filas existentes no tienen valor | Agregue el campo escrito, mida la cobertura y luego actualice a los consumidores |
Cambiar el nombre de tool.name |
Las consultas existentes todavía leen la ruta anterior. | Escritura dual de las rutas antiguas y nuevas durante la migración |
Cambie tool.duration_ms de número a cadena |
El conflicto de tipos puede rechazar la ingestión | Agregue un nuevo campo numérico y migre |
Mover tool.outcome a otro objeto |
Crea una nueva ruta, no un movimiento in situ | Versione el contrato y admita ambas rutas temporalmente |
| Cambiar formas de elementos de matriz | Produce un contrato analítico inestable. | Emita una fila por resultado duradero o utilice campos con nombres fijos |
Mantenga el mismo significado y escriba en cada profundidad. Generalmente es compatible agregar un campo anidado opcional; cambiar el tipo de ruta o reutilizarla para darle un nuevo significado no lo es.
Decidir cuándo aplanar
Los objetos anidados son útiles para espacios de nombres estables como tool, workflow o billing. Un campo plano puede ser mejor cuando se utiliza en casi todas las consultas o paneles.
Prefiere un campo plano o con emisión separada cuando:
- el valor define el grano de la fila o el resultado del evento primario;
- los operadores deben escanearlo en casi todas las investigaciones;
- varios productores no pueden ponerse de acuerdo sobre una estructura anidada;
- una matriz realmente representa múltiples resultados independientes.
Cambiar de anidado a plano posteriormente es una migración de esquema. Elija basándose en las preguntas y los límites de propiedad, no en la estética de la carga útil.
Solucionar problemas de una consulta de campo anidado
Si una consulta no puede encontrar una ruta anidada:
- Consulta una muestra sin procesar reciente con
LIMIT 50. - Inspeccione el esquema de la tabla para ver el nombre y el tipo exactos con puntos.
- Pruebe la forma de identificador entre comillas del esquema en lugar de agregar la sintaxis de extracción JSON de otro dialecto SQL.
- Confirme que el productor realmente envió un valor que no sea nulo ni vacío.
- Agrupe los valores faltantes por
releaseo versión del productor. - Compruebe si hay un cambio de tipo entre los productores nuevos y antiguos.
- Reduzca la consulta a un campo y una ventana de tiempo reciente antes de restaurar uniones o agregados.
Telemetry usa DataFusion SQL, por lo que las funciones PostgreSQL, BigQuery, Snowflake o MySQL JSON copiadas de otro sistema pueden no aplicarse. Utilice la sintaxis ejercitada en el DataFusion SQL referencia.
Lista de verificación de producción
- Dale a cada objeto anidado un significado y un propietario duraderos.
- Mantenga estables el tipo, las unidades y los valores controlados de cada ruta.
- Excluya secretos, contenido de usuario, cargas útiles sin procesar y texto de error ilimitado.
- Pruebe accesorios exitosos, fallidos, con campos faltantes y versiones antiguas.
- Mida la adopción de nuevos campos antes de hacer que un panel o una alerta dependan de ello.
- Documente el grano de la hilera, la necesidad de retención y el plan de migración.
Continúe con diseñar un esquema de evento, evolución del esquema y receta de tasa nula de campo obligatorio.