Stream: cql
Topic: Hooking up CQL engine to FHIR server
ravi.kuchi (Aug 04 2021 at 01:44):
Hi, I am looking to hook-up CQL engine to my FHIR server so I can execute CQL against the data present in my FHIR server. My server is SmileCDR (Licensed version of Hapi) and the FHIR version is 3.0.2. I checked both cqf-ruler and cql_execution_service projects. On the cqf-ruler project I see that it works on the data that is posted on the hapi version of the server but I want it to work with the data present on my server . On the cql_execution_service project, I am getting lot of errors mainly I think because it is outdated and there seems to be some work needed to make it usable. So, I am looking for guidance as to which implementation I would refer and begin with so I could serve my purpose.
Just to be clear on the ask, I am looking to execute the 'evaluate' operation
Alexander Kiel (Aug 04 2021 at 08:31):
I can't help you with a hook-up version of a CQL engine but HAPI itself recently integrated the cqf execution engine to enable the $evaluate operation. https://hapifhir.io/hapi-fhir/docs/server_jpa_cql/cql.html
Maybe you can license this extension for SmileCDR.
I'm the main developer of Blaze, I FHIR Server that also has an internal CQL engine. If evaluation performance is important to you, my first tests between HAPI and Blaze show that Blaze is about 1000x faster.
ravi.kuchi (Aug 04 2021 at 12:42):
Thanks for the input @Alexander Kiel , I am aware that Smile also has support to $evaluate-measure but I am looking at $evaluate so I can execute the CQL statements captured in a Library.
Bryn Rhodes (Aug 04 2021 at 13:28):
This website allows you to run arbitrary CQL against an arbitrary FHIR server: https://cql-runner.dataphoria.org/
Bryn Rhodes (Aug 04 2021 at 13:28):
Code for it is here: https://github.com/DBCG/cql_runner
Bryn Rhodes (Aug 04 2021 at 13:29):
Basically, it's using the $cql operation of a CQF Ruler, but that in turn is just using a specific configuration of the evaluator.
ravi.kuchi (Aug 04 2021 at 14:08):
@Bryn Rhodes , I tried that tool as well,I changed the datasource to another server (http://test.fhir.org/r4) but it does not seem to pick the data from the new server, I saw the parameters it was sending in the developer tools and it does not reflect the server that I have changed to:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "code",
"valueString": "library TestArtifact version '1'\n\nusing FHIR version '4.0.0'\n\ninclude \"FHIRHelpers\" version '4.0.0' called FHIRHelpers\n\ncodesystem \"SNOMED\": 'http://snomed.info/sct'\ncodesystem \"CONDCLINSTATUS\": 'http://terminology.hl7.org/CodeSystem/condition-clinical'\ncodesystem \"CONDVERSTATUS\": 'http://terminology.hl7.org/CodeSystem/condition-ver-status'\n\ncode \"Essential hypertension (disorder) code\": '59621000' from \"SNOMED\" display 'Essential hypertension (disorder)'\ncode \"Malignant hypertensive chronic kidney disease (disorder) code\": '285831000119108' from \"SNOMED\" display 'Malignant hypertensive chronic kidney disease (disorder)'\ncode \"Condition Active code\": 'active' from \"CONDCLINSTATUS\" display 'Active'\ncode \"Condition Confirmed code\": 'confirmed' from \"CONDVERSTATUS\" display 'Confirmed'\n\nconcept \"Condition Active\": { \"Condition Active code\" } display 'Active'\nconcept \"Condition Confirmed\": { \"Condition Confirmed code\" } display 'Confirmed'\n\ncontext Patient\n\ndefine \"AgeRange-548\":\n AgeInYears() >= 60 and AgeInYears() <= 85\n\ndefine \"Essential hypertension (disorder)\":\n exists(ActiveCondition([Condition: \"Essential hypertension (disorder) code\"]))\n\ndefine \"Malignant hypertensive chronic kidney disease (disorder)\":\n exists(Confirmed([Condition: \"Malignant hypertensive chronic kidney disease (disorder) code\"]))\n\ndefine \"MeetsInclusionCriteria\":\n \"AgeRange-548\"\n and \"Essential hypertension (disorder)\"\n\ndefine \"MeetsExclusionCriteria\":\n \"Malignant hypertensive chronic kidney disease (disorder)\"\n\ndefine \"InPopulation\":\n \"MeetsInclusionCriteria\" and not \"MeetsExclusionCriteria\"\n\ndefine \"Recommendation\":\n if \"InPopulation\" then ''\n else null\n\n\ndefine \"Rationale\":\n if \"InPopulation\" then null\n else null\n\ndefine \"Errors\":\n null\n\n\ndefine function Confirmed(CondList List<Condition>):\n CondList C where C.verificationStatus ~ \"Condition Confirmed code\"\n\ndefine function ActiveCondition(CondList List<Condition>):\n CondList C\n where C.clinicalStatus ~ \"Condition Active code\"\n and C.abatement is null\n"
},
{
"name": "patientId",
"valueString": "P48"
},
null,
{
"name": "context",
"valueString": "Patient"
},
{
"name": "terminologyServiceUri",
"valueString": "https://cql-sandbox.alphora.com/cqf-ruler-r4/fhir"
},
{
"name": "terminologyUser"
},
{
"name": "terminologyPass"
}
]
}
ravi.kuchi (Aug 04 2021 at 14:15):
Here is the service definition in cqf-ruler, it does not have parameters to change dataSource, so may be that is the limitation
@SuppressWarnings("unchecked")
@Operation(name = "$cql")
public Bundle evaluate(@OperationParam(name = "code") String code,
@OperationParam(name = "patientId") String patientId,
@OperationParam(name = "periodStart") String periodStart,
@OperationParam(name = "periodEnd") String periodEnd,
@OperationParam(name = "productLine") String productLine,
@OperationParam(name = "terminologyServiceUri") String terminologyServiceUri,
@OperationParam(name = "terminologyUser") String terminologyUser,
@OperationParam(name = "terminologyPass") String terminologyPass,
@OperationParam(name = "context") String contextParam,
@OperationParam(name = "executionResults") String executionResults,
@OperationParam(name = "parameters") Parameters parameters) {
ravi.kuchi (Aug 04 2021 at 14:17):
It would be great if this operation could accept a dataSource so we can plug in any FHIR server and run CQL against the data
Alexander Kiel (Aug 04 2021 at 16:06):
ravi.kuchi said:
Thanks for the input Alexander Kiel , I am aware that Smile also has support to $evaluate-measure but I am looking at $evaluate so I can execute the CQL statements captured in a Library.
Do you mean http://hl7.org/fhir/2018jan/operation-servicedefinition-evaluate.html? I know, you are on STU3 but it seems that ServiceDefinition is no longer part of R4. Sorry that I can't help.
ravi.kuchi (Aug 04 2021 at 17:57):
There are two operations $cql and $evaluate that are used in cqf-ruler that allows you to execute CQL statements in a Library against a FHIR server and they provide outcome for each of the statements. I find this feature powerful and useful especially in Decision Supporting Systems where we have rules for Prior Authorization
Alexander Kiel (Aug 04 2021 at 18:18):
Ok. How is this different from $evaluate-measure? Do you have a Measure in play with $evaluate or $cql? What are the possible result formats? In $evaluate-measure it's only a MeasureReport with various poluation and stratifier counts.
ravi.kuchi (Aug 04 2021 at 18:21):
Checkout examples at https://cql-runner.dataphoria.org/
you can run arbitrary cql
Alexander Kiel (Aug 04 2021 at 18:23):
Ok I know already about it. But this is not a standarized API in FHIR. In your use case we liked to build cohorts (populations) to $evaluate-measure was a good fit for us. But yes, you can do many many more things with CQL.
Dave Carlson (Aug 04 2021 at 21:43):
Library $evaluate operation is defined in the published CPG IG: https://build.fhir.org/ig/HL7/cqf-recommendations/OperationDefinition-cpg-library-evaluate.html
Alexander Kiel (Aug 05 2021 at 07:31):
@Dave Carlson Thanks. This looks good.
dsh (Aug 05 2021 at 16:00):
Alexander Kiel said:
I'm the main developer of Blaze, I FHIR Server that also has an internal CQL engine. If evaluation performance is important to you, my first tests between HAPI and Blaze show that Blaze is about 1000x faster.
Blaze looks very good specially with Quality Reporting UI, I tried the basic CQL example of COVID patients and it worked flawlessly.
@Alexander Kiel as Blaze is standalone and cannot be embedded in HAPI, I would like to understand how to accomplish the data sync between HAPI server and Blaze CQL engine. This sync is needed for a more real time reporting and analytics. Any pointers are much appreciated.
On a different note, does Blaze support GraphQL ? If so, what GraphQL capabilities does it have? Is it even possible to do population health queries (i.e. count of COVID-19 patients) using GraphQL in Blaze ?
Alexander Kiel (Aug 05 2021 at 19:45):
@dsh I'm glad you like the Blaze so far.
I would like to understand how to accomplish the data sync between HAPI server and Blaze CQL engine.
You can use subscriptions to sync the resources from HAPI to Blaze. I have started a documentation here. I would be interested if that works for you. Especially regarding the referential integrity.
On a different note, does Blaze support GraphQL ?
Unfortunately no. But feel free to open an issue with your use-case.
Is it even possible to do population health queries (i.e. count of COVID-19 patients) using GraphQL in Blaze ?
IMHO, quality reporting using CQL is a perfect fir for doing population health queries. Blaze is used as backend for the Sample Locator were you can do exactly that.
Richard Stanley (Aug 05 2021 at 20:50):
Hi @Alexander Kiel This looks super interesting! I'm just now playing around with Blaze but I'm seeing 'Referential integrity violated' errors on a relatively simple bundle (here: https://pastebin.com/ZAxmVEhM). This seems odd. Am I missing something on importing data that is different from HAPI? I've tried transaction bundles with PUTs as well. I've also tried the blazectl tool (nice use of Go btw) and it only loads one or two of the initial entries (Patient and Organization).
Alexander Kiel (Aug 06 2021 at 19:34):
@Richard Stanley I'm very happy that you liked Blaze so far. Referencing resources in batch bundles is problematic, because all requests in a batch should be without dependencies:
For a batch, there SHALL be no interdependencies between the different entries in the Bundle that cause change on the server. The success or failure of one change SHOULD not alter the success or failure or resulting content of another change. -- https://www.hl7.org/fhir/http.html#brules
I would recommend to always use a transaction bundle for changes. However, if I change the bundle type to transaction, the Location Location-HIVSimple
can't be created because the managingOrganization
reference points to Organization/Organization-HIVSimple
which will not be the identity of the Organization you also create in this bundle, because you use POST. At POST the server will generate the ID. However, if you use the fullUrl of the bundle entries as references, you can reference resources even if they will be assigned different IDs from the server. The bundle https://gist.github.com/alexanderkiel/c8bd1568efa39ebf187461623ed37e54 works with Blaze.
I tried the same with HAPI and your bundle as transaction bundle works correctly with HAPI but my version with the fullUrl references do not work. I will read the section on resolving references in bundles tomorrow again. I had this before. I'm not sure if my interpretation of the spec is right. I would be happy if you could help me here.
Richard Stanley (Aug 06 2021 at 19:40):
Thanks @Alexander Kiel this is super helpful. I would not be surprised that the issue comes down to me not being great at FHIR :) I'll have a go!
Richard Stanley (Aug 11 2021 at 00:10):
Hi @Alexander Kiel I'm troubleshooting an issue when issuing the $evaluate-measure operation to Blaze:
{"issue":[{"severity":"error","code":"value","diagnostics":"Could not load source for library FHIRCommon, version 4.0.1...
I can confirm that the CQL source is in the Library, which is on the server. Have you seen this before in Blaze? I see other issues with Publisher building/referencing proper CQL in Library resources but I wanted to check if this could be a Blaze thing.
Alexander Kiel (Aug 11 2021 at 08:54):
@Richard Stanley Do you reference the FHIRCommon library from your library? Currently Blaze doesn't support library references except for some hard codes functions from FHIRHelpers.
Richard Stanley (Aug 11 2021 at 15:36):
That's exactly right. I'm referencing another CQL/Library. Thanks for the clarification!
Richard Stanley (Aug 11 2021 at 15:38):
Quick point of clarification. Is FHIR Helpers (and Model-Info) required to be put on the server or is it there already? I've been PUTting them but if its not necessary then I can relax that requirement.
Alexander Kiel (Aug 12 2021 at 11:06):
Yes, it's not required to upload model-info and FHIRHelpers. Unlike in HAPI were it is required. Overall, since Blaze itself only support R4 in the moment, the model is constraint to R4 too. If you need more functions in FHIRHelpers, I can implement them without problem.
Richard Stanley (Aug 12 2021 at 18:27):
Thanks @Alexander Kiel I'm getting further. Curious if you have advice on this, I'm seeing an odd error, "error","code":"not-found", on a simple CQL file with $evaluate-measure.
Edit: I'm being dumb, wasn't paying attention to url encoding. :)
Alexander Kiel (Aug 12 2021 at 18:46):
@Richard Ok that was a simple 404, or? If you have suggestions for better error messages, I‘ll implement them.
Richard Stanley (Aug 13 2021 at 22:47):
@Alexander Kiel Is the 'subject' parameter supported on $evaluate-measure at this time? I see an error with it.
$ curl -sXPOST 'http://localhost:8080/fhir/Measure/BlazeStratifierTest/$evaluate-measure?periodStart=1970&periodEnd=2030&subject=C6Z4H2E5VIJ7BPCU'
java.util.concurrent.CompletionException: java.lang.IllegalArgumentException: No matching clause: subject
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(Unknown Source)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(Unknown Source)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Alexander Kiel (Aug 14 2021 at 20:18):
@Richard Stanley No it's not supported. Can you please write an issue?
Richard Stanley (Aug 14 2021 at 20:27):
Yep, will do! Thanks
Last updated: Apr 12 2022 at 19:14 UTC