On this page:

5.6Search Parameters

 

An important concept for setting up a FHIR repository is defining the search parameters that will be indexed and made available for searching by the system.

5.6.1Search Parameter Concepts

 

Search parameters are essentially named paths within resources that are indexed by the system so that they can be used to find resources that match a given criteria.

For example, the FHIR specification defines the gender search parameter on the Patient resource, giving it a path of Patient.gender. This means that every time a new Patient resource is created – or an existing one is updated – the value found at the path Patient.gender will be indexed. Clients may then use a URL search parameter named gender to find resources with a given gender.

Once these parameters have been defined in your database, clients can use them to find matching resources:

GET [base]/Patient?gender=male

5.6.2Default Search Parameters

 

The FHIR specification defines a set of built-in parameters that are wide ranging and broadly useful. For example, the FHIR definition for the Patient resource contains search parameters such as:

  • name (Search for patient by name)
  • birthdate (Search for patient by date of birth)
  • identifier (Search for patient by identifier)

For a general purpose repository, using the default search parameters is useful since these parameters represent a wide variety of use cases. Additionally, using the default parameters is good for interoperability since clients may expect standard parameters to be supported across different servers.

However, it is often useful to customize the supported search parameters. For example:

  • You may wish to add additional search parameters that will index fields that do not have a standard search parameter defined.
  • You may wish to add additional search parameters that will index extensions used by your clients.
  • You may wish to disable search parameters that are not used in order to improve performance and conserve space (disabling unnecessary search parameters can have a dramatic impact on write performance in some cases).

5.6.3Managing Search Parameters

 
Modifying search parameters requires the FHIR_MODIFY_SEARCH_PARAMETERS permission.

In a relational FHIR Storage module, each search parameter is represented by a SearchParameter resource in the database. When Smile CDR starts for the first time, the database will be preseeded with search parameter resources that correspond to the various default parameters.

If you want to customize the available search parameters, there are several ways to do so.

Using the Web Admin Console

To configure search parameters in the Web Admin Console, log into the console then select "Config -> Search Parameters".

You will be presented with a list of all available search parameters. You can create new ones, update existing ones, and disable ones you do not need.

Using the FHIR Endpoint

A new search parameter can also be created by simply uploading an appropriate SearchParameter resource. This is same process used to upload any other type of resource.

For example, POSTing the following resource to a server that supports custom search parameters will create a new search parameter on the Patient resource named eyecolour.

{
	"resourceType": "SearchParameter",
	"title": "Eye Colour",
	"base": [ "Patient" ],
	"status": "active",
	"code": "eyecolour",
	"type": "token",
	"expression": "Patient.extension('http://acme.org/eyecolour')",
	"xpathUsage": "normal"
}

5.6.4An Example Search Parameter

 

What follows is an example of a search parameter on an extension. We'll suppose that in our system we've defined an extension for a given patient's eye colour. Patient resources stored in our database will have the eye colour extension set, and we want to be able to search on this extension, too.

1. Create the Search Parameter

First, define a search parameter and upload it to your server. The following shows the SearchParameter resource:

{
	"resourceType": "SearchParameter",
	"title": "Eye Colour",
	"base": [ "Patient" ],
	"status": "active",
	"code": "eyecolour",
	"type": "token",
	"expression": "Patient.extension('http://acme.org/eyecolour')",
	"xpathUsage": "normal"
}

In Java, this can be created as follows:

// Create a search parameter definition
SearchParameter eyeColourSp = new SearchParameter();
eyeColourSp.addBase("Patient");
eyeColourSp.setCode("eyecolour");
eyeColourSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
eyeColourSp.setTitle("Eye Colour");
eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
eyeColourSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);

// Upload it to the server
client
	.create()
	.resource(eyeColourSp)
	.execute();

2. Upload Some Resources

Let's upload two Patient resources with different eye colours.

{
  "resourceType": "Patient",
  "extension": [
    {
      "url": "http://acme.org/eyecolour",
      "valueCode": "blue"
    }
  ],
  "active": true
}
{
  "resourceType": "Patient",
  "extension": [
    {
      "url": "http://acme.org/eyecolour",
      "valueCode": "green"
    }
  ],
  "active": true
}

3. Search!

Finally, let's try searching: http://example.com:8000/Patient?eyecolour=blue

This produces a search result that contains only the matching resource:

{
  "resourceType": "Bundle",
  "id": "bc89e883-b9f7-4745-8c2f-24bf9277664d",
  "meta": {
    "lastUpdated": "2017-02-07T20:30:05.445-05:00"
  },
  "type": "searchset",
  "total": 1,
  "link": [
    {
      "relation": "self",
      "url": "http://example.com:8000/fhir/context/Patient?eyecolour=blue"
    }
  ],
  "entry": [
    {
      "fullUrl": "http://example.com:8000/fhir/context/Patient/2",
      "resource": {
        "resourceType": "Patient",
        "id": "2",
        "meta": {
          "versionId": "1",
          "lastUpdated": "2017-02-07T20:30:05.317-05:00"
        },
        "extension": [
          {
            "url": "http://acme.org/eyecolour",
            "valueCode": "blue"
          }
        ],
        "active": true
      },
      "search": {
        "mode": "match"
      }
    }
  ]
}

5.6.5Enforcing Uniqueness

 

This section outlines how to ensure that values are unique within a repository.

5.6.6Unique Composite Search Parameters

 

Unique composite search parameters are special search parameters that are a combination of one or more existing search parameters. These search parameters enforce uniqueness for the values matched by the given search parameters across the entire repository.

Consider a repository that stores Encounter resources. These encounters have a subject (the Patient) and a date (the date of the encounter). This combination of parameters may be expressed using a search such as the following URL: https://try.smilecdr.com:8000/Encounter?date=2017-07-09&subject=Patient/b765fe0d-34fa-4427-b540-1be4ec4acbda

Now, suppose you wish to enforce a business rule that a given Patient may only have one Encounter per day. A composite search parameter can be used to enforce this uniqueness by declaring that combinations of the Encounter:date and Encounter:subject search parameters are globally unique.

Unique Composite Search Parameters enforce this uniqueness using a unique database index enforced by the RDBMS, so they are consistent even under high concurrency. They are declared using a SearchParameter resource. The following example shows a SearchParameter resource for this case:

{
  "resourceType": "SearchParameter",
  "extension": [
    {
      "url": "http://hapifhir.io/fhir/StructureDefinition/sp-unique",
      "valueBoolean": true
    }
  ],
  "status": "active",
  "code": "subject-and-date",
  "base": [
    "Encounter"
  ],
  "type": "composite",
  "expression": "Encounter",
  "component": [
    {
      "definition": {
        "reference": "SearchParameter/123"
      },
      "expression": "Encounter"
    },
    {
      "definition": {
        "reference": "SearchParameter/456"
      },
      "expression": "Encounter"
    }
  ]
}

The composite search parameter above contains two references to other SearchParameter resources (in this case, Encounter:patient and Encounter:date, which are represented by the IDs SearchParameter/123 and SearchParameter/456 respectively).

In order to create the composite search parameter, first the existing SearchParameter resources should be looked up to determine their respective IDs. This can be done using a query such as the following example: http://example.com:8000/SearchParameter?base=Encounter&code=date,patient

This returns a result such as the following (most of the content has been removed for readability):

{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "resource": {
        "resourceType": "SearchParameter",
        "id": "123",
        "code": "patient"
      }
    },
    {
      "resource": {
        "resourceType": "SearchParameter",
        "id": "456",
        "code": "date"
      }
    }
  ]
}

Note that it is not necessary for the parameter to have more than one component. If a single search parameter should be unique, the composite search parameter may have a single component.

The http://hapifhir.io/fhir/StructureDefinition/sp-unique extension must exist in a search parameter in order for it to be indexed as a unique search parameter, and this extension should have a boolean value of true as shown above.

5.6.7Search Parameter Statistics

 
The system gathers statistical information about search parameters using an algorithm that facilitates speedy collection; however, it is not always accurate or immediately up-to-date. Do not rely on these statistical values for any absolute calculations.

Smile CDR gathers statistics at runtime about the actual values indexed by a search parameter for resources in the database and the use of that search parameter by clients.

The following statistics are gathered:

  • Count: Refers to the total number of paths that are indexed by this parameter.
  • Resource Spread: Refers to the number of resources that contain values indexed by this parameter. A parameter with a low resource spread will only match a smaller number of resources, whereas a parameter with a high resource spread could potentially match a larger number.
  • Value Spread: Refers to the number of unique values indexed by this parameter. A parameter that matches a field bound to a ValueSet with a small number of codes (e.g. Patient.gender) will have a low value spread. A parameter that can contain many different values (e.g. Observation.value) could have a much higher value spread.
  • Last Used: Refers to how recently the parameter was actually used as a part of a search for resources.

5.6.8Example Search Parameter Expressions

 

Paths are defined using FHIRPath, which is an expression language defined by FHIR. In its simplest form, this can take the form of a single dotted path:

Patient.name.given

In the example above, any values for the patient's given name(s) will all be indexed.

Paths can also perform more advanced lookups. The following examples show a few paths for various FHIR features:

NameExpression and Example Resource
Extension With Reference Value: This example indexes the value on a custom extension that is added to a resource. Note that the extension does not need to be declared anywhere (aside from in the SearchParameter resource) in order for this example to work. Patient.extension('http://acme.com/doctor').value.as(Reference)

{
  "resourceType": "Patient",
  "extension": [{
    "url": "http://acme.com/doctor",
    "valueReference": {
      "reference": "Practitioner/A"
    }
  }]
}
Contained Resource: The following example indexes on a field that is found within a contained resource inside the resource that is being indexed. Observation.specimen.resolve().receivedTime

{
  "resourceType": "Observation",
  "id": "O1",
  "contained": [
    {
      "resourceType": "Specimen",
      "id": "FOO",
      "receivedTime": "2011-01-01"
    }
  ],
  "status": "final",
  "specimen": {
    "reference": "#FOO"
  }
}
Bundle Entry Resource: When storing Bundles directly (i.e. by POST-ing them to the /Bundle endpoint as opposed to processing them as FHIR transactions), this path can be used to index on a value within an individual resource found within the Bundle. Bundle.entry.resource.as(MessageHeader).id

{
  "resourceType": "Bundle",
  "type": "message",
  "entry": [
    {
      "resource": {
        "resourceType": "MessageHeader",
        "id": "123"
      }
    }
  ]
}
Bundle Entry Resource 2: This example shows a FHIR Document (a bundle with a Bundle.type of document where the first entry continas a Composition resource) with a custom search parameter indexing a field within the Composition. This example allows clients to search for documents with a given encounter reference. Bundle.entry[0].resource.as(Composition).encounter

{
  "resourceType": "Bundle",
  "type": "document",
  "entry": [
    {
      "resource": {
        "resourceType": "Composition",
        "encounter": {
          "reference": "Encounter/2"
        }
      }
    }
  ]
}
Multiple Paths: This example indexes multiple paths, meaning it can be used to provide one search parameter that will look for a value in multiple places within a resource. DiagnosticReport.performer | DiagnosticReport.resultsInterpreter

{
  "resourceType": "DiagnosticReport",
  "resultsInterpreter": {
    "reference": "Practitioner/A"
  }
}

5.6.9Filter Search Parameter

 

Smile CDR can be configured to enable the FHIR _filter search parameter, using the filter_search.enabled property.

The filter search parameter is extremely powerful, as it allows a level of expressiveness in searches that is not possible with standard REST URL search parameters. It also potentially allows clients to perform searches for which no appropriate database indexes exist, making it a potentially dangerous operation for public servers. As such it is disabled by default.

Users of the Filter Search Parameter are advised to examine the generated SQL (e.g. by enabling Performance Tracing and then examining the Transaction Log) and ensuring that the database has indexes to appropriately support the queries being performed.