From c86e46b19651a2196df96fa9343c3ac8ccd15cf5 Mon Sep 17 00:00:00 2001 From: ianmarshall Date: Mon, 8 Jun 2020 18:08:02 -0400 Subject: [PATCH] Add documentation and remove requirement for max parameter (defaulted to 1 now). --- .../ca/uhn/hapi/fhir/docs/files.properties | 1 + .../ca/uhn/hapi/fhir/docs/server_jpa/lastn.md | 41 +++++++++++++++++++ .../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 3 -- ...seJpaResourceProviderObservationDstu3.java | 4 +- .../BaseJpaResourceProviderObservationR4.java | 4 +- .../BaseJpaResourceProviderObservationR5.java | 4 +- .../search/lastn/ElasticsearchSvcImpl.java | 15 +++++-- .../lastn/ObservationCodeIndexSchema.json | 4 +- .../fhir/jpa/dao/r4/BaseR4SearchLastN.java | 1 - 9 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/lastn.md diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties index dc5fe3ad700..73ba427f9c4 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties @@ -47,6 +47,7 @@ page.server_jpa.search=Search page.server_jpa.performance=Performance page.server_jpa.upgrading=Upgrade Guide page.server_jpa.diff=Diff Operation +page.server_jpa.lastn=LastN Operation section.server_jpa_empi.title=JPA Server: EMPI page.server_jpa_empi.empi=Enterprise Master Patient Index diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/lastn.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/lastn.md new file mode 100644 index 00000000000..dc8c65c1dfc --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/lastn.md @@ -0,0 +1,41 @@ +# LastN Operation + +HAPI FHIR 5.1.0 introduced preliminary support for the `$lastn` operation described [here](http://hl7.org/fhir/observation-operation-lastn.html). + +This implementation of the `$lastn` operation requires an external Elasticsearch server implementation which is used to implement the indexes required by this operation. The following sections describe the current functionality supported by this operation and the configuration needed to enable this operation. + +# Functional Overview and Parameters + +As described in the [FHIR specification](http://hl7.org/fhir/observation-operation-lastn.html), the `$lastn` can be used to retrieve the most recent or last n=number of observations for one or more subjects. This implementation supports the following search parameters: + +* `subject=` or `patient=`: Identifier(s) of patient(s) to return Observation resources for. If not specified, returns most recent observations for all patients. +* `category=`: One or more category code search parameters used to filter Observations. +* `Observation.code=`: One or more `Observation.code` search parameters use to filter and group observations. If not specified, returns most recent observations for all `Observation.code` values. +* `date=`: Date search parameters used to filter Observations by `Observation.effectiveDtm`. +* `max=`: The maximum number of observations to return for each `Observation.code`. If not specified, returns only the most recent observation in each group. + +# Limitations + +Search parameters other than those listed above are currently not supported. + +The grouping of Observation resources by `Observation.code` means that the `$lastn` operation will not work in cases where `Observation.code` has more than one coding. + +# Deployment and Configuration + +The `$lastn` operation is disabled by default. The operation can be enabled by setting the DaoConfig#setLastNEnabled property (see [JavaDoc](/hapi-fhir/apidocs/hapi-fhir-jpaserver-api/ca/uhn/fhir/jpa/api/config/DaoConfig.html#setLastNEnabled(boolean))). + +In addition, the Elasticsearch client service, `ElasticsearchSvcImpl` will need to be instantiated with parameters specifying how to connect to the Elasticsearch server, for e.g.: + +```java + @Bean() + public ElasticsearchSvcImpl elasticsearchSvc() { + String elasticsearchHost = "localhost"; + String elasticsearchUserId = "elastic"; + String elasticsearchPassword = "changeme"; + int elasticsearchPort = 9301; + + return new ElasticsearchSvcImpl(elasticsearchHost, elasticsearchPort, elasticsearchUserId, elasticsearchPassword); + } +``` + +See the [JavaDoc](/hapi-fhir/apidocs/hapi-fhir-jpaserver-base/ca/uhn/fhir/jpa/search/lastn/IElasticsearchSvc.html) for more information regarding the Elasticsearch client service. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index ad463873cbe..dd65fbb430b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -311,9 +311,6 @@ public class SearchBuilder implements ISearchBuilder { throw new InvalidRequestException("LastN operation is not enabled on this service, can not process this request"); } } - if(myParams.getLastNMax() == null) { - throw new InvalidRequestException("Max parameter is required for $lastn operation"); - } List lastnResourceIds = myIElasticsearchSvc.executeLastN(myParams, myContext, theMaximumResults); for (String lastnResourceId : lastnResourceIds) { pids.add(myIdHelperService.resolveResourcePersistentIds(myRequestPartitionId, myResourceName, lastnResourceId)); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java index bbbff175c47..80d34042c92 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java @@ -89,7 +89,9 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider if (theSubject != null) { paramMap.add(Observation.SP_SUBJECT, theSubject); } - paramMap.setLastNMax(theMax.getValue()); + if (theMax != null) { + paramMap.setLastNMax(theMax.getValue()); + } if (theCount != null) { paramMap.setCount(theCount.getValue()); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java index 1d9874f8803..af5eb9938a2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java @@ -88,7 +88,9 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4< if (theSubject != null) { paramMap.add(Observation.SP_SUBJECT, theSubject); } - paramMap.setLastNMax(theMax.getValue()); + if(theMax != null) { + paramMap.setLastNMax(theMax.getValue()); + } if (theCount != null) { paramMap.setCount(theCount.getValue()); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java index 530392b15f2..125a4a4c945 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java @@ -89,7 +89,9 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5< if (theSubject != null) { paramMap.add(Observation.SP_SUBJECT, theSubject); } - paramMap.setLastNMax(theMax.getValue()); + if (theMax != null) { + paramMap.setLastNMax(theMax.getValue()); + } if (theCount != null) { paramMap.setCount(theCount.getValue()); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/lastn/ElasticsearchSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/lastn/ElasticsearchSvcImpl.java index 7730e863ee4..0a5619059f8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/lastn/ElasticsearchSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/lastn/ElasticsearchSvcImpl.java @@ -97,7 +97,6 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc { private final String GROUP_BY_CODE = "group_by_code"; private final String OBSERVATION_IDENTIFIER_FIELD_NAME = "identifier"; - public ElasticsearchSvcImpl(String theHostname, int thePort, String theUsername, String thePassword) { myRestHighLevelClient = ElasticsearchRestClientFactory.createElasticsearchHighLevelRestClient(theHostname, thePort, theUsername, thePassword); @@ -175,7 +174,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc { break; } SearchRequest myLastNRequest = buildObservationsSearchRequest(subject, theSearchParameterMap, theFhirContext, - createObservationSubjectAggregationBuilder(theSearchParameterMap.getLastNMax(), topHitsInclude)); + createObservationSubjectAggregationBuilder(getMaxParameter(theSearchParameterMap), topHitsInclude)); try { SearchResponse lastnResponse = executeSearchRequest(myLastNRequest); searchResults.addAll(buildObservationList(lastnResponse, setValue, theSearchParameterMap, theFhirContext, @@ -186,7 +185,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc { } } else { SearchRequest myLastNRequest = buildObservationsSearchRequest(theSearchParameterMap, theFhirContext, - createObservationCodeAggregationBuilder(theSearchParameterMap.getLastNMax(), topHitsInclude)); + createObservationCodeAggregationBuilder(getMaxParameter(theSearchParameterMap), topHitsInclude)); try { SearchResponse lastnResponse = executeSearchRequest(myLastNRequest); searchResults.addAll(buildObservationList(lastnResponse, setValue, theSearchParameterMap, theFhirContext, @@ -198,6 +197,14 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc { return searchResults; } + private int getMaxParameter(SearchParameterMap theSearchParameterMap) { + if (theSearchParameterMap.getLastNMax() == null) { + return 1; + } else { + return theSearchParameterMap.getLastNMax(); + } + } + private List getSubjectReferenceCriteria(String thePatientParamName, String theSubjectParamName, SearchParameterMap theSearchParameterMap) { List subjectReferenceCriteria = new ArrayList<>(); @@ -231,7 +238,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc { return referenceList; } - private CompositeAggregationBuilder createObservationSubjectAggregationBuilder(int theMaxNumberObservationsPerCode, String[] theTopHitsInclude) { + private CompositeAggregationBuilder createObservationSubjectAggregationBuilder(Integer theMaxNumberObservationsPerCode, String[] theTopHitsInclude) { CompositeValuesSourceBuilder subjectValuesBuilder = new TermsValuesSourceBuilder("subject").field("subject"); List> compositeAggSubjectSources = new ArrayList<>(); compositeAggSubjectSources.add(subjectValuesBuilder); diff --git a/hapi-fhir-jpaserver-base/src/main/resources/ca/uhn/fhir/jpa/search/lastn/ObservationCodeIndexSchema.json b/hapi-fhir-jpaserver-base/src/main/resources/ca/uhn/fhir/jpa/search/lastn/ObservationCodeIndexSchema.json index 9387f7b901e..acedddf3490 100644 --- a/hapi-fhir-jpaserver-base/src/main/resources/ca/uhn/fhir/jpa/search/lastn/ObservationCodeIndexSchema.json +++ b/hapi-fhir-jpaserver-base/src/main/resources/ca/uhn/fhir/jpa/search/lastn/ObservationCodeIndexSchema.json @@ -12,13 +12,13 @@ "type" : "keyword" }, "codingdisplay" : { - "type" : "text" + "type" : "keyword" }, "codingsystem" : { "type" : "keyword" }, "text" : { - "type" : "text" + "type" : "keyword" } } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseR4SearchLastN.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseR4SearchLastN.java index 314b082edc6..390efd1e7ac 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseR4SearchLastN.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseR4SearchLastN.java @@ -208,7 +208,6 @@ public class BaseR4SearchLastN extends BaseJpaTest { public void testLastNNoPatients() { SearchParameterMap params = new SearchParameterMap(); - params.setLastNMax(1); params.setLastN(true); Map requestParameters = new HashMap<>();