|
14 min de lectura
|

Introducción a FHIR Terminology: Los conceptos básicos

Resumir este artículo con:
ChatGPTPerplexityClaudeGrok

Este es el segundo artículo de la Serie de Introducción a FHIR Terminology. Repasaremos los conceptos fundamentales que conforman el Módulo de Terminology de FHIR. Veremos ejemplos concretos de los problemas que puede resolver y ofreceremos una visión general de cómo encajan las distintas piezas.

Casos de uso

Como mencionamos anteriormente, hemos observado que los recién llegados a FHIR infrautilizan las soluciones de Terminology. Creemos que parte de la razón es la falta de conciencia sobre los problemas que puede resolver; algunas personas pueden asociar Terminology con temas como estándares, conformidad, cumplimiento normativo y regulaciones. Por ello, pensamos que un buen punto de partida es mostrar algunos casos de uso concretos que se implementan fácilmente mediante un servidor de Terminology. De hecho, todos estos ejemplos se ejecutan en tiempo real contra nuestra instancia de sandbox.

Cada pestaña muestra un ejemplo en vivo, desde cuadros de búsqueda y menús desplegables hasta mapeo y traducción; abra el panel en la parte inferior del recuadro para ver las peticiones y respuestas reales1.

Contexto

Cuando un médico escribe «infarto de miocardio» y otro escribe «ataque al corazón», se refieren a lo mismo. Pero para un sistema de software, o cualquier flujo de trabajo a escala, no son más que dos cadenas de texto distintas. La capacidad de compartir significado entre las partes es fundamental para la interoperabilidad. Para eso sirven las terminologías sanitarias. Uno de los primeros ejemplos de terminología sanitaria es la Clasificación Internacional de Enfermedades (CIE), adoptada en 1893 para codificar las causas de muerte. Es anterior al software y sigue en uso hoy en día.

Trabajaremos con un conjunto de construcciones que se incluyen dentro de la definición de una terminología: taxonomías, ontologías, nomenclaturas, conjuntos de códigos, vocabularios y clasificaciones. A efectos prácticos, las llamaremos terminologías y las definiremos como un conjunto de términos con un identificador estable legible por máquina. Pueden ser infinitas, tener sinónimos, propiedades, relaciones, estructura, etc. Pero la característica principal que necesitaremos es que cada elemento tenga un identificador estable (código) y alguna etiqueta textual (término/display).

En el desarrollo web «normal», los implementadores utilizan terminologías constantemente (aunque no se llamen así). Con frecuencia se implementan como enumeraciones o como una tabla de elementos con una vista de administración CRUD (es muy habitual que las enumeraciones sean sus propios códigos y que las tablas de elementos utilicen el ID de la base de datos como identificador). Los ejemplos anteriores podrían perfectamente haberse implementado con estos patrones.

FHIR proporciona un Módulo de Terminology diseñado para resolver estos y otros problemas. Un aspecto interesante es que las mismas abstracciones permiten expresar tanto ontologías estándar, conformes y autoritativas de gran tamaño como listas locales de códigos cortas similares a enumeraciones.

Valores codificados

Muchos recursos FHIR tienen campos cuyo dominio de valores posibles se toma de una lista (una terminología). Sus valores son códigos asignados externamente que identifican un concepto definido. Por ejemplo:

resourceType: Patient
name:
  - given: [Jane]
    family: Doe
gender: female

Observe que, en este caso, name es una propiedad no vinculada: puede tomar cualquier nombre de persona, mientras que gender solo puede tomar uno de cuatro valores: male, female, other, unknown. En este caso, female es un valor codificado.

Un valor codificado es principalmente un par compuesto por «system» y «code», donde system es una URL2 que identifica el sistema de códigos (terminología) que define los códigos. Esta decisión tiene implicaciones significativas en la capacidad de descubrimiento de los valores codificados: en lugar de encontrar una cadena de texto que parece un código LOINC, los valores codificados van acompañados de su identificador de sistema de códigos. En el caso del género anterior, el sistema es implícito (Administrative Gender, http://hl7.org/fhir/administrative-gender); veremos por qué en breve.

FHIR define 3 tipos de datos principales para representar estos códigos3: code, Coding y CodeableConcept.

  • code: La instancia representa únicamente el código. El sistema es implícito.
  • Coding: El tipo de dato contiene un código y un sistema que identifica el origen de la definición del código.
  • CodeableConcept: Un tipo que representa un concepto mediante texto libre y/o uno o más elementos coding.

La mayoría de los elementos codificados en FHIR utilizan CodeableConcept, ya que ofrece la mayor flexibilidad. Permite múltiples codificaciones y texto libre para expresar, por ejemplo, lo que realmente escribió la persona que introdujo el dato, o los casos en que no hay ningún código disponible. También facilita las transiciones, ya que se pueden incluir códigos antiguos y nuevos en la misma estructura (véase el ejemplo de Observation más adelante).

El tipo de dato Coding se utiliza cuando la intención es hacer referencia a un código específico, no expresar un concepto de forma general. El uso de Coding es poco frecuente, ya que es menos flexible que CodeableConcept y no permite texto libre ni traducciones.

El tipo de dato code aparece habitualmente en escenarios similares a las enumeraciones. Típicamente, estos elementos tienen una fortaleza de vinculación required, es decir: el código debe provenir del conjunto de valores especificado y no es necesario transmitir un código alternativo. Generalmente, estos elementos pueden estar implicados en la lógica de negocio, como el despacho según un valor, la comparación exacta, etc. Por ejemplo: el estado de un recurso; el código del cliente podría ignorar los recursos retired o actuar solo sobre los active.

Vinculación (Binding)

En los tipos de datos anteriores, los códigos son de tipo string; la forma de restringir el conjunto de valores que pueden tomar es mediante vinculaciones (bindings). La especificación vincula el elemento a un conjunto de valores (value set), lo que significa que solo puede tomar valores de esa lista.

Las vinculaciones tienen dos propiedades principales: valueSet y strength. valueSet define qué códigos son válidos para este elemento. strength indica cómo debe interpretarse la vinculación: required, extensible, preferred, example.

Binding example
Patient spec fragment. Notice the highlighted elements, their datatypes, binding value sets and strengths

En el ejemplo anterior, Patient.gender está vinculado al conjunto de valores Administrative Gender con una fortaleza required; por lo tanto, gender solo puede ser: male, female, other, unknown. Y maritalStatus está vinculado a Marital Status Codes con una fortaleza extensible, lo que significa que los códigos deben provenir de ese conjunto de valores a menos que el código esperado no esté cubierto por él.

Ejemplos de valores codificados

resourceType: Patient
name:
  - given: [Jane]
    family: Doe
gender: female # code / AdministrativeGender (implicit)
maritalStatus: # CodeableConcept
  text: Married
  coding:
    - system: http://terminology.hl7.org/CodeSystem/v3-MaritalStatus
      code: M
      display: Married
resourceType: Location
name : South Wing Neuro OR 1
status: suspended # code / LocationStatus (implicit)
operationalStatus: # Coding
  system: http://terminology.hl7.org/CodeSystem/v2-0116
  code: H
  display: Housekeeping
type: # CodeableConcept
  coding:
    - system: http://terminology.hl7.org/CodeSystem/v3-RoleCode
      code: RNEU
      display: Neuroradiology unit
form: # CodeableConcept without codings
  text: Room
resourceType: Observation
status: final # code / ObservationStatus (implicit)
code: # CodeableConcept with local and standard codings
 coding:
   - system: http://acmelabs.org
     code: 104177
     display: "Blood culture"
   - system: http://loinc.org
     code: 600-7
     display: Bacteria identified in Blood by Culture
valueCodeableConcept: # CodeableConcept
  coding:
    - system: http://snomed.info/sct
      code: 3092008
      display: Staphylococcus aureus
interpretation:
  text: Positive
  coding:
    - system: http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
      code: POS

Recursos

Veamos brevemente los recursos FHIR implicados en el Módulo de Terminology. En la práctica, raramente se crean directamente. Habitualmente se mantienen en otro lugar y se cargan4 en (o desde) un servidor de Terminology.

El Módulo de Terminology define cuatro recursos de Terminology principales: CodeSystem, ValueSet, ConceptMap y NamingSystem. Dedicaremos una entrada a cada uno de ellos. Por ahora ofreceremos una breve descripción general de CodeSystem y ValueSet.

CodeSystem

CodeSystem es sin duda el recurso más importante en FHIR Terminology. Se utiliza para describir un sistema de códigos, sus atributos y contenidos. En su forma más habitual, contiene una lista de conceptos, cada uno con su código, designaciones y propiedades.

Ejemplos

resourceType: CodeSystem
url: http://hl7.org/fhir/administrative-gender
version: 5.0.0
content: complete
status: active
concept:
  - code: male
    display: Male
  - code: female
    display: Female
  - code: other
    display: Other
  - code: unknown
    display: Unknown
resourceType: CodeSystem
content: supplement
supplements: http://hl7.org/fhir/administrative-gender
concept:
- code: male
  designation:
  - language: es
    value: Masculino
- code: female
  designation:
  - language: es
    value: Femenino
- code: other
  designation:
  - language: es
    value: Otro
- code: unknown
  designation:
  - language: es
    value: Desconocido
resourceType: CodeSystem
url: http://www.nlm.nih.gov/research/umls/rxnorm
version: '03022026'
publisher: National Library of Medicine
content: complete
filter:
- code: concept
  operator: [is-a, generalizes, descendent-of]
  value: comma-separated list of concept codes for direct equality testing
- code: NDC
  operator: [=,in, exists]
  value: NDC code
property:
- {code: TTY, type: string}
- {code: NDC, type: string}
- {code: RXN_STRENGTH, type: string}
- {code: dose_form_of, type: code}
- {code: has_ingredient, type: code}
- {code: has_tradename, type: code}
# ...
concept:
- code: '5640'
  display: ibuprofen
  property:
  - code: TTY
    valueString: IN
  - code: has_tradename
    valueCode: '1100067'
  - code: ingredient_of
    valueCode: '1152223'
  - code: part_of
    valueCode: '821036'
  # ...
# ...
resourceType: CodeSystem
url: http://hl7.org/fhir/sid/icd-10-cm
version: '2025'
content: complete
property:
- description: Indicator [...] transactions ("billable code")
  type: integer
  code: valid
filter:
- description: Identify valid billable codes.
  value: 0 = "header" – not valid [...]
  code: valid
  operator: ["="]
valueSet: http://hl7.org/fhir/sid/icd-10-cm/vs
concept:
- code: Chapter-1
  display: Certain infectious and parasitic diseases (A00-B99)
  concept:
  - code: Section-A00-A09
    display: Intestinal infectious diseases (A00-A09)
    concept:
    - code: A00
      display: Cholera
      concept:
      - code: A00.0
        display: Cholera due to Vibrio cholerae 01, biovar cholerae
        property:
        - code: valid
          valueInteger: 1
# ...

ValueSet

Un recurso ValueSet especifica un conjunto de códigos extraídos de uno o más sistemas de códigos.

En nuestra experiencia, este es uno de los recursos más incomprendidos en FHIR Terminology. Una posible razón es que la diferencia entre los sistemas de códigos y los conjuntos de valores no siempre queda clara para los implementadores. No ayuda que, en el núcleo de FHIR, la mayoría de los recursos CodeSystem tengan un ValueSet equivalente que incluye todos sus códigos. Por ejemplo: http://hl7.org/fhir/administrative-gender y http://hl7.org/fhir/ValueSet/administrative-gender.

La distinción principal es que los sistemas de códigos contienen la definición de los conceptos, su origen, mientras que los conjuntos de valores seleccionan códigos de los sistemas de códigos. Así, un conjunto de valores puede contener un subconjunto de un sistema de códigos, o incluso combinar varios.

Por ejemplo, RxNorm es una terminología farmacológica que incluye conceptos para nombres de marca, principios activos, formas farmacéuticas, etc. Podemos definir un conjunto de valores con los principios activos de RxNorm. Los conceptos incluidos seguirían siendo conceptos de RxNorm, pero solo tendríamos principios activos.

Otro caso de uso habitual de los conjuntos de valores es añadir una opción nula. Supongamos que usamos ISO 3166 (códigos de país) en un formulario. Muestra correctamente todos los países y sus códigos, pero no existe un código de país «Desconocido». Podemos definir un conjunto de valores que incluya todos los códigos de ISO 3166 y el concepto UNK de NullFlavor.

Ejemplos

resourceType: ValueSet
url: http://example.org/rxnorm-ingredients
title: RxNorm Ingredients
compose:
  include:
  - system: http://www.nlm.nih.gov/research/umls/rxnorm
    filter:
    - property: TTY
      op: =
      value: IN
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/example
title: LOINC Codes for Cholesterol in Serum/Plasma
compose:
  include:
  - system: http://loinc.org
    concept:
    - code: 14647-2
      display: Cholesterol [Moles/Volume]
    - code: 2093-3
      display: Cholesterol [Mass/Volume]
    - code: 35200-5
      display: Cholesterol [Mass Or Moles/Volume]
    - code: 9342-7
      display: Cholesterol [Percentile]
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/administrative-gender
status: active
compose:
  include:
  - system: http://hl7.org/fhir/administrative-gender
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/yesnodontknow
name: YesNoDontKnow
compose:
  include:
  - valueSet: ["http://terminology.hl7.org/ValueSet/v2-0136"]
  - system: http://terminology.hl7.org/CodeSystem/data-absent-reason
    concept:
    - code: asked-unknown
      display: Don't know

Operaciones

La principal forma de interactuar con el módulo de Terminology y sus recursos es mediante operaciones. La especificación R6 define 8 operaciones específicas de Terminology. A lo largo de esta serie analizaremos la mayoría de ellas en detalle. En este artículo presentaremos $expand, la que impulsa la mayoría de los ejemplos anteriores.

ValueSet/$expand

Dado un conjunto de valores, devuelve la lista de códigos que define. Esta operación es ideal para poblar elementos de interfaz de usuario: menús desplegables, campos de búsqueda, selectores de códigos, etc. Además del conjunto de valores, se puede especificar un filtro de búsqueda por texto, paginación, qué propiedades y designaciones devolver, en qué idioma responder, entre otros parámetros.

Tomemos nuestro primer ejemplo: un campo de búsqueda con completado automático sobre los hallazgos clínicos de SNOMED. Supongamos que queremos buscar «diabetes mellitus» y obtener 10 resultados. A continuación se muestra cómo podría ser una petición:

GET https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand
[Query]
url: http://snomed.info/sct?fhir_vs=isa/404684003
count: 10
filter: diabetes mellitus
curl -G 'https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand' \
  --data-urlencode 'url=http://snomed.info/sct?fhir_vs=isa/404684003' \
  --data-urlencode 'count=10' \
  --data-urlencode 'filter=diabetes mellitus'
ParámetroValorExplicación
urlhttp://snomed.info/sct?fhir_vs=isa/404684003URL implícita para los conceptos de hallazgos clínicos de SNOMED5
count10Número de conceptos a encontrar
filterdiabetes mellitusTexto a buscar

También podemos proporcionar un conjunto de valores en línea en la petición; esto nos permite construir consultas sobre un sistema de códigos mediante propiedades. Por ejemplo, supongamos que queremos obtener todos los medicamentos de marca que contienen tanto cafeína como paracetamol (acetaminofén) como principios activos.

POST https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand
Content-Type: application/json
{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "valueSet",
      "resource": {
        "resourceType": "ValueSet",
        "status": "active",
        "compose": {
          "include": [
            {
              "system": "http://www.nlm.nih.gov/research/umls/rxnorm",
              "filter": [
                { "property": "TTY", "op": "=", "value": "BN" },
                { "property": "tradename_of", "op": "=", "value": "CUI:161" },
                { "property": "tradename_of", "op": "=", "value": "CUI:1886" }
              ]
            }
          ]
        }
      }
    }
  ]
}
curl -X POST 'https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand' \
  -H 'Content-Type: application/json' \
  -d '{
    "resourceType": "Parameters",
    "parameter": [
      {
        "name": "valueSet",
        "resource": {
          "resourceType": "ValueSet",
          "status": "active",
          "compose": {
            "include": [
              {
                "system": "http://www.nlm.nih.gov/research/umls/rxnorm",
                "filter": [
                  { "property": "TTY", "op": "=", "value": "BN" },
                  { "property": "tradename_of", "op": "=", "value": "CUI:161" },
                  { "property": "tradename_of", "op": "=", "value": "CUI:1886" }
                ]
              }
            ]
          }
        }
      }
    ]
  }'
FiltroValorExplicación
TTYBNSolo nombres de marca
tradename_ofCUI:161Contiene paracetamol (acetaminofén)
tradename_ofCUI:1886Contiene cafeína

A continuación

En nuestro próximo artículo analizaremos los canonicals: cómo se identifican los recursos de Terminology, qué convenciones se utilizan y cómo funciona el versionado y la resolución.

Footnotes

  1. La forma más eficiente de implementar algunos de estos ejemplos es mediante batching; mantenemos las peticiones aisladas para facilitar su inspección.

  2. Profundizaremos en el funcionamiento de estas URL en un artículo futuro sobre canonicals.

  3. En realidad, la especificación define 4 tipos de datos (y 3 adicionales). Sin embargo, CodeableReference se define en términos de CodeableConcept y los adicionales son casos especiales. Por eso nos centramos en los tres primeros. Véase https://build.fhir.org/terminologies.html.

  4. En un artículo futuro veremos un tutorial para configurar un servidor de Terminology desde cero para potenciar una aplicación sanitaria.

  5. Véase https://terminology.hl7.org/en/SNOMEDCT.html para consultar cómo utilizar SNOMED con FHIR Terminology. Dedicaremos un artículo futuro a SNOMED CT.

Compartir este artículo
Comments
Comments
Sign in
Loading comments...
Subscribe to our blog

Get the latest articles on FHIR, interoperability, and healthcare IT.