google / android-fhir

The Android FHIR SDK is a set of Kotlin libraries for building offline-capable, mobile-first healthcare applications using the HL7® FHIR® standard on Android.
https://google.github.io/android-fhir/
Apache License 2.0
494 stars 294 forks source link

Custom SearchParameter for local search to support offline use case #1382

Closed joiskash closed 1 year ago

joiskash commented 2 years ago

Is your feature request related to a problem? Please describe. The current search implementation in the FHIR engine is based on the FHIR specification where it is specified that the default search strategy for token search as string is an exact match. We have a requirement to perform partial match to reduce the search space while displaying results on the UI.

Describe the solution you'd like Support SearchParameter for custom search strategies .

Describe alternatives you've considered We have a working version with online search, but this is needed for the offline use case.

cc: @jingtang10 @fredhersch

jingtang10 commented 2 years ago
maimoonak commented 2 years ago

Token Text Search:

The fhir query supports search by modifiers like :missing, :exact, :text, :in, :below, :above, :not, :[type], :identifier,:above, :below etc for different parameters (Token, String, Reference, URI). For token specifically these are ALL -> :missing; e.g. gender:missing=true TOKEN -> :text, :in, :below, :above and :not-in

Current requirement seems like asking for a support of :text modifier. Which means searching text field of CodeableConcept or display field of Coding. Please note that this does not do partial search on code field. Here is the doc for token modifiers in details http://hl7.org/fhir/R4/search.html#token.

Example -> Condition?code:text=headache

Possible Solution:

Extension search:

FHIR by default does not support extension search.

To allow search by extension there is need to

@jingtang10 @f-odhiambo

maimoonak commented 2 years ago

There is another ticket which aims working on Full text search i.e.e FTS (android FTS-3/4). The FTS is powerful but specific to android with a specific set of features. The language/syntax and virtual table structure is also its own.

As mentioned in comment above the FHIR search is very powerful and has specific rules for each param type. Moreover hapi itself has implemented the search using Lucene the use of Lucene on android SDK can help with query syntax conformance with HAPI query syntax with all features available without any customization/deviation/complexity easily.

Some aspects to evaluate are performance (Lucene claims to be faster), complexity (FTS has shorter learning curve), scalability (HAPI uses Lucence hence accommodating syntax and features is easier), size (Lucene claims to be compact but uses Files, FTS uses sqlite) etc.

I am doing a small POC on Lucene and then we can benchmark and decide the workable approach.

@jingtang10 @f-odhiambo @shoaibmushtaq25

joiskash commented 2 years ago

An example use case is Partial search with identifier Eg:

fhirEngine
        .search<Patient>(
          Search(ResourceType.Patient).apply {
            filter(identifierPartial, { value.contains("some-id") })
          }
        )
        .isEmpty()

SearchParameter

{
    "resourceType": "SearchParameter",
    "id":"648e32a3-7959-4662-b254-bd9c980f62a9",
    "title": "Partial Identifier",
    "status": "active",
    "code": "identifierPartial",
    "base": [
      "Patient"
    ],
    "type": "string",
    "expression": "Patient.identifier.value",
    "xpathUsage": "normal",
    "modifier": [
      "contains"
    ]
}

Search of encounter based on Encounter.service-type

fhirEngine
        .search<Encounter>(
          Search(ResourceType.Encounter).apply {
            filter(service-type, { this.value = of("Patient Check In") })
          }
        )
        .isEmpty()

The SearchParameter that we are using in the HAPI FHIR server is

{
    "resourceType": "SearchParameter",
    "id":"786344c7-644e-4665-80fa-86290c9bb71a",
    "title": "Service Type Text",
    "status": "active",
    "code": "service-type",
    "base": [
      "Encounter"
    ],
    "type": "string",
    "expression": "Encounter.serviceType.text",
    "xpathUsage": "normal"
}