|
14 min de lectura
|

Introducción a FHIR Terminology: 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 quienes se inician en FHIR suelen aprovechar poco las soluciones de Terminology. Creemos que parte del motivo es la falta de conocimiento sobre los problemas que puede resolver; algunas personas asocian Terminology con temas como estándares, conformidad, cumplimiento normativo o regulaciones. Por eso pensamos que un buen punto de partida es mostrar algunos casos de uso concretos que se implementan fácilmente mediante un servidor de terminología. 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 listas desplegables hasta mapeo y traducción; abra el panel en la parte inferior del recuadro para ver las solicitudes y respuestas reales1.

Contexto

Cuando un médico escribe «ataque al corazón» y otro escribe «infarto de miocardio», se refieren a lo mismo. Pero para un sistema informático, o cualquier flujo de trabajo a escala, son simplemente dos cadenas de texto distintas. La capacidad de compartir significado entre las partes es fundamental para la interoperabilidad. Para eso existen 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 enmarcan en la definición de una terminología: taxonomías, ontologías, nomenclaturas, conjuntos de códigos, vocabularios, 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 «convencional», 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 usen el identificador 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 grandes ontologías estándar, conformes y autorizadas, como listas locales cortas de códigos similares a enumeraciones.

Valores codificados

Muchos recursos FHIR tienen campos cuyo dominio de valores posibles se extrae 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 sin restricciones: puede tomar cualquier nombre humano, 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 casualmente 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 una persona introdujo manualmente o los casos en que no hay código disponible. También facilita la transición, ya que es posible 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 referenciar 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 enumeraciones. Típicamente, estos elementos tienen una fuerza de vinculación required, es decir: el código debe provenir obligatoriamente del conjunto de valores especificado y no es necesario expresar un código alternativo. Por lo general, estos elementos pueden estar involucrados en la lógica de negocio, como la distribución 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

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. La especificación vincula el elemento a un conjunto de valores, 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 fuerza required; por lo tanto, gender solo puede ser: male, female, other, unknown. Y maritalStatus está vinculado a Marital Status Codes con una fuerza extensible, lo que significa que los códigos deben provenir de ese conjunto de valores salvo que el código esperado no esté incluido.

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

A continuación, examinaremos brevemente los recursos FHIR involucrados en el módulo de Terminology. En la práctica, rara vez se crean directamente. Generalmente se mantienen en otro lugar y se cargan4 en un servidor de terminología (o desde él).

El módulo de Terminology define cuatro recursos de terminología principales: CodeSystem, ValueSet, ConceptMap y NamingSystem. Dedicaremos un artículo a cada uno de ellos. Por ahora, ofreceremos una breve visión general de CodeSystem y ValueSet.

CodeSystem

CodeSystem es posiblemente el recurso más importante en FHIR Terminology. Se utiliza para describir un sistema de códigos, sus atributos y su contenido. 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 sistemas de códigos y conjuntos de valores no siempre resulta clara para los implementadores. No ayuda el hecho de que, en el núcleo de FHIR, la mayoría de los recursos CodeSystem tienen 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. Por lo tanto, 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 de medicamentos que incluye conceptos para nombres comerciales, principios activos, formas farmacéuticas, etc. Podemos definir un conjunto de valores de los principios activos en RxNorm. Los conceptos incluidos seguirían siendo conceptos de RxNorm, pero solo tendríamos principios activos.

Otro caso de uso habitual para 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 a través de operaciones. La especificación R6 define 8 operaciones específicas de terminología. A lo largo de esta serie, examinaremos 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 rellenar elementos de interfaz de usuario: listas desplegables, campos de búsqueda, selectores de códigos, etc. Además del conjunto de valores, se puede especificar un filtro de búsqueda de texto, paginación, las propiedades y designaciones que se deben devolver, el idioma de respuesta, entre otros parámetros.

Tomemos nuestro primer ejemplo: un campo de búsqueda predictiva 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 verse una solicitud:

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 directamente en la solicitud, lo que nos permite construir consultas sobre un sistema de códigos mediante propiedades. Por ejemplo, supongamos que queremos obtener todos los medicamentos de marca que tienen tanto cafeína como 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 comerciales
tradename_ofCUI:161Contiene acetaminofén
tradename_ofCUI:1886Contiene cafeína

A continuación

En nuestro próximo artículo examinaremos los canónicos. Cómo se identifican los recursos de terminología, 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 usando agrupación por lotes; mantenemos las solicitudes aisladas para facilitar su inspección.

  2. Profundizaremos en el funcionamiento de estas URL en un artículo futuro sobre canónicos.

  3. La especificación en realidad 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 terminología que impulse una aplicación sanitaria desde cero.

  5. Véase https://terminology.hl7.org/en/SNOMEDCT.html para saber cómo usar 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.