Arquitecto ← Perspectivas

La Guía de AQL de CaboLabs: Referencia Práctica del Archetype Query Language

El Archetype Query Language (AQL) es el lenguaje de consulta estándar de openEHR para datos clínicos basados en arquetipos. Su razón de existir es la portabilidad: los lenguajes de consulta convencionales como SQL dependen del esquema físico de datos de una base de datos particular, por lo que una consulta escrita para un sistema generalmente no funcionará en otro — incluso cuando ambos almacenan los mismos datos clínicos. AQL resuelve esto consultando contra los modelos clínicos — arquetipos y el Modelo de Referencia (RM) de openEHR — en lugar del almacenamiento físico, haciendo las consultas compartibles entre sistemas y fronteras empresariales [1]. Esta guía condensa la especificación oficial de AQL en una referencia práctica: la anatomía de la consulta, la maquinaria de rutas y predicados, operadores y funciones, y un método para escribir consultas a mano.

Anatomía de una Consulta AQL

Una instrucción AQL tiene cinco cláusulas, que deben aparecer en este orden: SELECT (obligatoria — qué devolver), FROM (obligatoria — la fuente de datos y el ámbito de contención), WHERE (opcional — criterios de valor), ORDER BY (opcional — ordenamiento), y LIMIT (opcional — paginación). El ejemplo canónico de la especificación — presiones arteriales anormales en un EHR, las más recientes primero [1]:

SELECT
   o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude AS systolic,
   o/data[at0001]/events[at0006]/data[at0003]/items[at0005]/value/magnitude AS diastolic,
   c/context/start_time AS date_time
FROM
   EHR e[ehr_id/value=$ehrUid]
      CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1]
         CONTAINS OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
WHERE
   o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= 140 OR
   o/data[at0001]/events[at0006]/data[at0003]/items[at0005]/value/magnitude >= 90
ORDER BY c/context/start_time DESC
LIMIT 5

El modelo mental: FROM define el subconjunto del repositorio sobre el que ejecuta la consulta, WHERE filtra dentro de ese subconjunto, y SELECT proyecta exactamente los datos a devolver — desde objetos completos (una COMPOSITION completa) hasta valores primitivos. Las palabras clave no distinguen entre mayúsculas y minúsculas.

Rutas: Cómo AQL Localiza Datos

AQL usa la sintaxis de rutas de openEHR en dos variantes [3]. Las rutas de arquetipo navegan nodos definidos en un arquetipo, usando at-codes como identificadores de nodo — /data[at0001]/events[at0006]/data[at0003]/items[at0004]/value resuelve al DV_QUANTITY sistólico en el arquetipo de presión arterial. Las rutas de atributo del RM apuntan a atributos del Modelo de Referencia no definidos por ningún arquetipo — /context/start_time, /uid/value, /category en una composición. Una ruta identificada combina una variable declarada en FROM con una ruta (y opcionalmente un predicado): o/data[at0001]/.../value/magnitude. Las variables se declaran solo cuando se necesitan — las clases en FROM a las que ninguna otra cláusula hace referencia no necesitan una.

Regla práctica: nunca escribir rutas de arquetipo a mano de memoria. Extráelas del arquetipo usando las herramientas de modelado listadas en el sitio web de openEHR — los at-codes son hechos del arquetipo, y los arquetipos especializados introducen códigos con punto (at0013.1) que solo tienen sentido contra la jerarquía de especialización.

Predicados: Tres Tipos de Corchetes

Todo lo que está entre corchetes es un predicado, y AQL define tres tipos [1]:

  • Predicado estándar — forma completa con operando, operador y valor: [ehr_id/value='123456'], [ehr_id/value=$ehrUid].
  • Predicado de arquetipo — un atajo que contiene solo un ID de arquetipo, usado exclusivamente en la cláusula FROM para acotar la fuente de datos: [openEHR-EHR-OBSERVATION.blood_pressure.v1]. Es formalmente equivalente a un predicado estándar sobre archetype_node_id, que es exactamente cómo los motores lo canonizan.
  • Predicado de nodo — criterios detallados sobre nodos, desde un at-code desnudo [at0002], pasando por desambiguación basada en nombre [at0002, 'Systolic'] o [at0002 and name/value=$nameValue], hasta nombres con código de término como [at0002, snomed_ct(3.1)::313267000] y criterios generales como [at0002 and value/defining_code/terminology_id/value=$terminologyId] [2].

Los predicados de nodo basados en nombre son la herramienta para estructuras de hermanos repetidos — dos clusters con el mismo at-code distinguidos solo por sus nombres en tiempo de ejecución — una situación que toda consulta de resultados de laboratorio del mundo real eventualmente encuentra.

Operadores, matches y Terminología

Los operadores de comparación son el conjunto habitual (=, !=, >, >=, <, <=) más dos buscadores de patrones. LIKE hace patrones de cadena simples — ? coincide con un carácter, * cualquier secuencia, y el valor completo debe coincidir, por lo que las búsquedas de "contiene" necesitan '*término*'. matches es el potente, tomando tres formas del lado derecho dentro de llaves [1]:

-- 1. Lista de valores (OR implícito entre elementos)
WHERE o/.../code_string matches {'18919-1', '18961-3', '19000-9'}

-- 2. URI de terminología (p. ej., una jerarquía SNOMED CT)
WHERE diagnosis/data/items[at0002.1]/value/defining_code
      matches { terminology://snomed-ct/hierarchy?rootConceptId=50043002 }

-- 3. Función TERMINOLOGY() llamando a un servidor de terminología externo
WHERE p/data/items[at0002]/value/defining_code/code_string
      matches TERMINOLOGY('expand', 'hl7.org/fhir/4.0',
                          'http://snomed.info/sct?fhir_vs=isa/50697003')

La función TERMINOLOGY(operacion, api_servicio, uri_params) es el puente de AQL a los servicios de terminología: operaciones como expand, validate, map y subsumes ejecutadas contra, por ejemplo, un servicio de terminología FHIR, con los resultados alimentados de vuelta a la consulta. Así es como "todos los diagnósticos que son un subtipo de enfermedad autoinmune" se convierte en una consulta en lugar de un join del lado de la aplicación.

Los operadores lógicos son AND, OR, NOT y EXISTS (¿existen datos en esta ruta?). Dos expresiones a nivel de composición merecen atención: NOT EXISTS c/content[...] filtra sobre la ausencia de una entrada dentro de los datos coincidentes, mientras que NOT CONTAINS en la cláusula FROM expresa una restricción de exclusión sobre la contención en sí — p. ej., composiciones de derivación que no contienen ninguna observación de laboratorio. Las expresiones de contención se componen con AND, OR y paréntesis, por lo que ámbitos de múltiples arquetipos como "encuentros que contienen una HbA1c o una observación de glucosa" son de primera clase.

Funciones y Agregación

AQL define funciones integradas de una sola fila — cadena (LENGTH, CONTAINS, POSITION, SUBSTRING, CONCAT, CONCAT_WS), numéricas (ABS, MOD, CEIL, FLOOR, ROUND), y de fecha/hora (CURRENT_DATE, NOW(), CURRENT_TIMEZONE) — más agregados: COUNT (con formas DISTINCT y *), MIN, MAX, SUM, AVG, que ignoran NULLs [1]. Agregar valores clínicos es una línea:

SELECT
   MAX(o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude) AS maxSystolic,
   AVG(o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude) AS meanSystolic
FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1]
   CONTAINS OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]

La especificación define este conjunto básico; las implementaciones pueden ofrecer funciones adicionales, lo cual es una consideración de portabilidad cuando las consultas deben ejecutarse entre plataformas.

Resultados, Ordenamiento y Paginación

Tres comportamientos confunden a los nuevos usuarios. Primero, la forma del resultado: un resultado AQL es conceptualmente una tabla bidimensional (filas de expresiones de columna seleccionadas), con plataformas devolviendo un conjunto de resultados anotado — como el definido por la API REST de openEHR — que porta metadatos de columna [4]. Segundo, el ordenamiento no está definido por defecto: sin ORDER BY, la especificación no garantiza nada sobre el orden de los resultados, por lo que cualquier consulta que alimente paginación o lógica de "valor más reciente" debe ordenar explícitamente [1]. Tercero, la paginación es LIMIT cantidad_filas OFFSET desplazamiento combinada con ORDER BY para páginas deterministas — el modificador TOP más antiguo está obsoleto. DISTINCT deduplica filas antes de que se apliquen LIMIT/OFFSET. Y los parámetros ($ehrUid, $systolicCriteria) deben portar cada valor en tiempo de ejecución: la parametrización está integrada en el lenguaje precisamente para que las instrucciones puedan compartirse y reutilizarse dentro y entre sistemas.

Hoja de Referencia de Cláusulas AQL

Cláusula Propósito Herramientas Clave Atención Con
FROM Acotar la fuente de datos Expresiones de clase, predicados de arquetipo, CONTAINS (con AND/OR/NOT) Consulta de población vs. consulta de un EHR: omitir el predicado ehr_id consulta todos los registros
WHERE Filtrar por valores de datos Operadores de comparación, LIKE, matches, EXISTS, TERMINOLOGY() Reglas de comillas: cadenas y fechas/horas entre comillas, números y booleanos no
SELECT Proyectar los datos de retorno Rutas identificadas, variables de objeto completo, funciones, literales, alias AS, DISTINCT Seleccionar composiciones completas cuando solo se necesitan dos campos infla los payloads
ORDER BY Ordenar resultados ASC/DESC, múltiples expresiones de ordenamiento No existe ordenamiento por defecto — la paginación sin orden es no determinista
LIMIT Paginar LIMIT n OFFSET m con ORDER BY TOP está obsoleto; no mezclar con LIMIT

Un Método para Escribir AQL a Mano

La propia especificación recomienda un método de tres pasos, que hemos encontrado coincide con cómo trabajan realmente los modeladores experimentados [1]. Paso 1 — FROM: identificar los conceptos clínicos en la pregunta ("presión arterial", "encuentro de salud"), mapear cada uno a su arquetipo, decidir el ámbito de un EHR versus la población, y conectar la jerarquía de contención usando el RM (las composiciones contienen observaciones). Paso 2 — WHERE: traducir cada criterio en una expresión identificada — declarar una variable para el arquetipo sobre el que se filtra, construir la ruta al valor del dato, elegir el operador, unir criterios con operadores lógicos. Paso 3 — SELECT: escribir las rutas identificadas para exactamente los valores a devolver, crear alias legibles, luego agregar ORDER BY y LIMIT si la pregunta implica "el más reciente" o "los N primeros". Trabajar primero con FROM mantiene la honestidad: obliga a tomar las decisiones de arquetipo y contención — el corazón semántico de la consulta — antes de cualquier detalle de ruta.

El Rol de CaboLabs

CaboLabs no solo usa AQL — contribuimos a darle forma: el fundador de CaboLabs Pablo Pazos es un colaborador acreditado de la especificación oficial de AQL, incluyendo el mecanismo de paginación LIMIT/OFFSET introducido en la versión 1.1.0, y hemos implementado motores de consulta AQL desde cero [1]. Esa profundidad a nivel de especificación y motor es lo que aportamos a los compromisos de consultoría: formación en AQL para equipos clínicos y de ingeniería, diseño y revisión de consultas, estrategias de indexación de rutas de arquetipo y evaluación de plataformas openEHR. Nuestro repositorio de datos clínicos nativo en openEHR, Atomik, lo pone en producción — consulta de arquetipos basada en estándares sobre un CDR construido por personas que conocen el lenguaje desde adentro.

Si tu equipo está adoptando AQL, migrando consultas entre plataformas, o necesita que la capa de consultas de una plataforma de datos clínicos sea diseñada correctamente, habla con nosotros en cabolabs.com — pocos equipos conocen AQL mejor, y podemos demostrarlo en el propio registro de cambios de la especificación.

Referencias y Fuentes Verificables

  1. Fundación openEHR: Especificación del Archetype Query Language (AQL) (La especificación oficial ESTABLE en la que se basa esta guía: estructura de consulta, sintaxis de rutas, predicados, operadores, funciones, paginación LIMIT/OFFSET, la obsolescencia de TOP, y el registro de enmiendas que acredita a los colaboradores incluyendo a Pablo Pazos de CaboLabs).
  2. Fundación openEHR: Ejemplos de AQL (Documento complementario oficial con consultas trabajadas, incluyendo predicados de nodo basados en nombre, at-codes especializados, coincidencia de terminología y ejemplos aritméticos).
  3. Fundación openEHR: Visión General de la Arquitectura openEHR — Rutas y Localizadores (Definición oficial de la sintaxis de rutas de openEHR y las expresiones de predicado sobre las que AQL se construye; respalda las secciones de rutas y predicados).
  4. Fundación openEHR: API REST de openEHR — Consulta (API REST oficial para ejecutar consultas AQL ad-hoc y almacenadas, definiendo la estructura del conjunto de resultados anotado y el paso de parámetros; respalda las notas de resultados y ejecución).

¿Tienes alguna pregunta?

Dinos cómo podemos ayudarte.

Empresa CaboLabs Health Informatics
Dirección Juan Paullier 995, Montevideo, Uruguay
Teléfono +598 99 043 145