10.3.1ValueSet Expansion

 

The FHIR Specification defines two resource types that are used as a part of defining and using codes:

  • The CodeSystem resource defines a collection of codes.
  • The ValueSet resource creates a collection of codes drawn from one or more CodeSystems, for some specific use.

ValueSets are defined by a collection of rules (the composition). These rules can be simple inclusion rules (e.g. "include codes A, B, and C") or much more complex rules (e.g. "include any codes that are a child of code A", or "include codes with a specific property value", etc).

10.3.2ValueSet Expansion Pre-Calculation

 

When a ValueSet is uploaded into Smile CDR (e.g. a complete and valid resource of type ValueSet is created in the FHIR repository), Smile CDR will schedule a background job to calculate the expansion and store it in a dedicated set of database tables. Using this pre-calculated expansion has several advantages:

  • Requesting the expansion can proceed much more quickly since the expansion doesn't need to be calculated on-demand.
  • It is possible to test the ValueSet for membership of a specific code (a common task during resource validation) much more efficiently.
  • It is possible to request specific pages (by offset and page size) of ValueSets where the expansion is too large to fit in memory.

When you perform a ValueSet expansion on a previously stored ValueSet, an extension will be added to the ValueSet.meta element. This extension shows the status of the pre-calculation. If the pre-calculation has not yet been completed, you will see a response similar to the following:

10.3.2.1Testing for Pre-Calculation Status

To test whether a ValueSet has been pre-calculated, simply request the expansion using the $expand operation. For example, the following request can be used to request the expansion of the LOINC ValueSet:

GET ValueSet/$expand?url=http://loinc.org/vs

If this ValueSet has not been precalculated, a response resembling the following will be produced.

{
  "resourceType": "ValueSet",
  "meta": {
    "extension": [ {
      "url": "http://hapifhir.io/fhir/StructureDefinition/valueset-expansion-message",
      "valueString": "ValueSet \"ValueSet.url[http://example.com/my_value_set]\" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: NOT_EXPANDED | The ValueSet is waiting to be picked up and pre-expanded by a scheduled task."
    } ]
  },
  "status": "active",
   [ ... Remaining Fields Not Shown ... ]
}

After the pre-calculation has completed, you will see a response similar to the following:

{
  "resourceType": "ValueSet",
  "meta": {
    "extension": [ {
      "url": "http://hapifhir.io/fhir/StructureDefinition/valueset-expansion-message",
      "valueString": "ValueSet was expanded using an expansion that was pre-calculated at 2021-09-21T14:11:12.324-04:00"
    } ]
  },
  "status": "active",
   [ ... Remaining Fields Not Shown ... ]
}

10.3.2.2Invalidating Pre-Calculated Expansion

Any time that a ValueSet resource is updated in the database in a way that causes the version number to be incremented, any previously calculated expansion is immediately invalidated and will no longer be used by the system. A new scheduled task is immediately created that will re-calculate the expansion in the background. Until this re-calculation is complete, any expansion requests or code validation requests against this ValueSet will be perfomed using an in-memory expansion.

It is also possible to manually request that the existing pre-calculated expansion be invalidated and a new one calculated. This is useful in cases where the underlying CodeSystem has been changed in a meaningful way.

To invalidate an existing Pre-Calculated expansion, use the $invalidate-expansion operation by issuing a POST against the ValueSet resource ID. For example:

POST ValueSet/my-valueset/$invalidate-expansion

10.3.3Expanding Hierarchical CodeSystems and ValueSets

 

Many CodeSystem resources define Concepts in a hierarchy. For example, a fictitious "Animals" CodeSystem might define a code "Pets" with child codes "Dogs" and "Cats".

The hierarchy in a CodeSystem often indicates an "is-a" relationship between the parent code and the child codes. This is not always the case; the hierarchy can imply different kinds of relationships depending on the specific system.

ValueSets can be used to retrieve all of the codes that are a child of a specific code in a CodeSystem. For example, suppose you have the following CodeSystem. Note how there are two codes at the root level ("A" and "B") and each of these codes have children, some of which have further children.

{
  "resourceType": "CodeSystem",
  "url": "http://example.com/my_code_system",
  "content": "complete",
  "concept": [ {
    "code": "A",
    "display": "Code A",
    "concept": [ {
      "code": "AA",
      "display": "Code AA",
      "concept": [ {
        "code": "AAA",
        "display": "Code AAA"
      } ]
    }, {
      "code": "AB",
      "display": "Code AB"
    } ]
  }, {
    "code": "B",
    "display": "Code B",
    "concept": [ {
      "code": "BA",
      "display": "Code BA"
    }, {
      "code": "BB",
      "display": "Code BB"
    } ]
  } ]
}

The hierarchy for the codes above can be visualized as follows:

|-- A
|   |-- AA
|   |   \-- AAA 
|   \-- AB
\-- B 
    |-- BA
    \-- BB

To create a ValueSet containing all of the children of a specific code in this CodeSystem, a ValueSet with a filter can be defined:

{
   "resourceType": "ValueSet",
   "url": "http://example.com/my_value_set",
   "status": "active",
   "compose": {
      "include": [ {
         "system": "http://example.com/my_code_system",
         "filter": [ {
            "property": "concept",
            "op": "is-a",
            "value": "A"
         } ]
      } ]
   }
}

Note that the "is-a" filter will exclude the concept itself. The following example combines an "is-a" filter with a simple explcit code inclusion in order to include the code "A" as well as all of its descendents.

{
   "resourceType": "ValueSet",
   "url": "http://example.com/my_value_set",
   "status": "active",
   "compose": {
      "include": [ {
         "system": "http://example.com/my_code_system",
         "filter": [ {
            "property": "concept",
            "op": "is-a",
            "value": "A"
         } ]
      }, {
         "system": "http://example.com/my_code_system",
         "concept": [ {
           "code": "A"
         } ]
      } ]
   }
}

10.3.3.1Requesting A Flat Expansion

Performing a ValueSet expansion is as simple as invoking an HTTP POST on the following URL: http://[server-base-url]/ValueSet/$expand?url=http://example.com/my_value_set

This will produce the following response. Note that the hierarchy is not included in the response.

 {
  "resourceType": "ValueSet",
  "status": "active",
  "compose": {
    "include": [ {
      "system": "http://example.com/my_code_system",
      "filter": [ {
        "property": "concept",
        "op": "is-a",
        "value": "A"
      } ]
    }, {
      "system": "http://example.com/my_code_system",
      "concept": [ {
        "code": "A"
      } ]
    } ]
  },
  "expansion": {
    "identifier": "dcd5e662-bd53-4137-a0af-55771e37b3cb",
    "timestamp": "2021-04-06T14:38:39-04:00",
    "total": 4,
    "offset": 0,
    "parameter": [ {
      "name": "offset",
      "valueInteger": 0
    }, {
      "name": "count",
      "valueInteger": 1000
    } ],
    "contains": [ {
      "system": "http://example.com/my_code_system",
      "code": "AB",
      "display": "Code AB"
    }, {
      "system": "http://example.com/my_code_system",
      "code": "AA",
      "display": "Code AA"
    }, {
      "system": "http://example.com/my_code_system",
      "code": "AAA",
      "display": "Code AAA"
    }, {
      "system": "http://example.com/my_code_system",
      "code": "A",
      "display": "Code A"
    } ]
  }
}

10.3.3.2Requesting a Hierarchical Expansion

If you would like the parent-child relationships to be reflected in the response, you can add the includeHierarchy parameter in your request. For example: http://[server-base-url]/ValueSet/$expand?url=http://example.com/my_value_set&includeHierarchy=true

This will produce the following response:

{
  "resourceType": "ValueSet",
  "status": "active",
  "compose": {
    "include": [ {
      "system": "http://example.com/my_code_system",
      "filter": [ {
        "property": "concept",
        "op": "is-a",
        "value": "A"
      } ]
    }, {
      "system": "http://example.com/my_code_system",
      "concept": [ {
        "code": "A"
      } ]
    } ]
  },
  "expansion": {
    "identifier": "442d78a4-1fb5-452e-8df6-94802129a653",
    "timestamp": "2021-04-06T14:38:39-04:00",
    "total": 4,
    "offset": 0,
    "parameter": [ {
      "name": "offset",
      "valueInteger": 0
    }, {
      "name": "count",
      "valueInteger": 1000
    } ],
    "contains": [ {
      "system": "http://example.com/my_code_system",
      "code": "A",
      "display": "Code A",
      "contains": [ {
        "system": "http://example.com/my_code_system",
        "code": "AB",
        "display": "Code AB"
      }, {
        "system": "http://example.com/my_code_system",
        "code": "AA",
        "display": "Code AA",
        "contains": [ {
          "system": "http://example.com/my_code_system",
          "code": "AAA",
          "display": "Code AAA"
        } ]
      } ]
    } ]
  }
}

10.3.4Searching for Codes

 

When building applications that capture data using coded values, a common requirement is to search for codes. This might be done in order to present a user with a dropdown-list, or to provide a type-ahead display with codes matching the characters that a user has entered so far in a text box.

The standard mechanism for performing searches is to use the ValueSet $expand operation. A simple example is shown below, searching for all codes in the http://acme.org CodeSystem (i.e. the CodeSystem in the repository where CodeSystem.url = http://acme.org) having a display name starting with the string "Systolic".

POST /ValueSet/$expand
Content-Type: application/fhir+json

{
  "resourceType": "ValueSet",
  "compose": {
    "include": [ {
      "system": "http://acme.org",
      "filter": [ {
        "property": "display",
        "op": "=",
        "value": "Systolic"
      } ]
    } ]
  }
}