Search is a beast. For client developers, things look bright: not only is there a generous amount of query possibilities per resource, you can get paged results and you can ask the server to include related resources in the returned result as well. That last bit is very useful when you’re searching for DiagnosticReports and would like to have the Patient and Observations it refers to come along. But the client’s bright day comes at a price for the server developer: you’ll need to be prepared to spend quite some time on search, even though you’re not required to implement all of its more complex features. Of all FHIR’s REST features, Search might be the most difficult one to build.
The search specification is surprisingly small and well-hidden in a subsection of the FHIR REST page. But it is dense and, as Stroustrup once put it, it certainly does not try to insult your intelligence. At the same time, it is one of the looser parts of the specification: there is no guarantee that two FHIR servers, fed with the same source data and query parameters, will produce the same query result. So, in addition to explaining the current specification, it’s worth telling you how I implemented the FHIR search for Firely’s Spark FHIR server. That will explain possible deviations from Grahame’s server and give you an insight in how you might want to shape your own search functionality.
It’s actually going to get even more exciting than that: As we preprare for the next connectathon at the HL7 May Workgroup Meeting, we will re-implement the search functionality using Apache’s Lucene. I will document that effort right here on my blog, so you all will be there to witness if we can make it on time, on budget and whether Lucene will be up to the task. In the meantime, we’ll get to discuss the search functionality and you might even pick up some Lucene.
Let’s start our Adventures in Search with a simple example, searching a patient by some (fragment) of a name:
That should give you back a feed with tens of entries, amongst them Eve Everywoman, Adam Everyman, Terri Stevens and Beverly Holland. It’s immediately clear from this example that:
- The search on name is case-insensitive
- It searches all parts of the HumanName (given, family)
- It does partial matches, even mid-string matches
If you’d lookup the “name” search parameter on the Patient page, you’ll see this is perfectly plausible. According to that page, “name” searches “a portion of either family or given name of the patient”. Furthermore, the search parameter is defined to be of type “string”, which is one of the six types of search parameters defined on the REST search page: “string” is “(..) a simple string, like a name part (search usually functions on partial matches)”.
The important thing to take away from this is that the actual search you’ll have to do is a product of two variables, both specified in the list of search parameters for a resource: the type of parameter (which implies the looseness of the search) and the description of what you’re searching for within a resource (in this case multiple parts of the name element, which itself may repeat). It’s not always going to be the case that a parameter searches just one element of a resource: it may search multiple fields (check “word” on the Profile resource), or conversely, search just a part of an elements contents (look at the Patient’s “family” parameter).
Getting a feeling for the fun of implementing search? Well, enough for today already, we will continue in the next installment.