Changed observation indexing to bypass hibernate search and removed Observation indexing tables.
This commit is contained in:
parent
60e420aaa3
commit
6e507bf642
|
@ -24,11 +24,6 @@ import ca.uhn.fhir.context.*;
|
|||
import ca.uhn.fhir.jpa.dao.data.IObservationIndexedCodeCodingSearchParamDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IObservationIndexedSearchParamLastNDao;
|
||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedCategoryCodeableConceptEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedCategoryCodingEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodingEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||
|
@ -59,6 +54,11 @@ public class ObservationLastNIndexPersistSvc {
|
|||
|
||||
public void indexObservation(IBaseResource theResource) {
|
||||
|
||||
if (myElasticsearchSvc == null) {
|
||||
// Elasticsearch is not enabled and therefore no index needs to be updated.
|
||||
return;
|
||||
}
|
||||
|
||||
List<IBase> subjectReferenceElement = mySearchParameterExtractor.extractValues("Observation.subject", theResource);
|
||||
String subjectId = subjectReferenceElement.stream()
|
||||
.map(refElement -> mySearchParameterExtractor.extractReferenceLinkFromResource(refElement, "Observation.subject"))
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IObservationIndexedCodeCodeableConceptSearchParamDao extends JpaRepository<ObservationIndexedCodeCodeableConceptEntity, Long> {
|
||||
@Query("" +
|
||||
"SELECT t FROM ObservationIndexedCodeCodeableConceptEntity t " +
|
||||
"WHERE t.myCodeableConceptId = :codeableConceptId" +
|
||||
"")
|
||||
ObservationIndexedCodeCodeableConceptEntity findByCodeableConceptId(@Param("codeableConceptId") String theCodeableConceptId);
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IObservationIndexedSearchParamLastNDao extends JpaRepository<ObservationIndexedSearchParamLastNEntity, Long>{
|
||||
@Query("" +
|
||||
"SELECT t FROM ObservationIndexedSearchParamLastNEntity t " +
|
||||
"WHERE t.myIdentifier = :identifier" +
|
||||
"")
|
||||
ObservationIndexedSearchParamLastNEntity findByIdentifier(@Param("identifier") String theIdentifier);
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ import org.shadehapi.elasticsearch.action.DocWriteResponse;
|
|||
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
||||
import org.shadehapi.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.shadehapi.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
import org.shadehapi.elasticsearch.action.index.IndexRequest;
|
||||
import org.shadehapi.elasticsearch.action.index.IndexResponse;
|
||||
import org.shadehapi.elasticsearch.action.search.SearchRequest;
|
||||
|
@ -539,8 +540,104 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
|||
return codes;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean performIndex(String theIndexName, String theDocumentId, String theIndexDocument, String theDocumentType) throws IOException {
|
||||
@Override
|
||||
public ObservationJson getObservationDocument(String theDocumentID) {
|
||||
if (theDocumentID == null) {
|
||||
throw new InvalidRequestException("Require non-null document ID for observation document query");
|
||||
}
|
||||
SearchRequest theSearchRequest = buildSingleObservationSearchRequest(theDocumentID);
|
||||
ObservationJson observationDocumentJson = null;
|
||||
try {
|
||||
SearchResponse observationDocumentResponse = executeSearchRequest(theSearchRequest);
|
||||
SearchHit[] observationDocumentHits = observationDocumentResponse.getHits().getHits();
|
||||
if (observationDocumentHits.length > 0) {
|
||||
// There should be no more than one hit for the identifier
|
||||
String observationDocument = observationDocumentHits[0].getSourceAsString();
|
||||
observationDocumentJson = objectMapper.readValue(observationDocument, ObservationJson.class);
|
||||
}
|
||||
|
||||
} catch (IOException theE) {
|
||||
throw new InvalidRequestException("Unable to execute observation document query for ID " + theDocumentID, theE);
|
||||
}
|
||||
|
||||
return observationDocumentJson;
|
||||
}
|
||||
|
||||
private SearchRequest buildSingleObservationSearchRequest(String theObservationIdentifier) {
|
||||
SearchRequest searchRequest = new SearchRequest(OBSERVATION_INDEX);
|
||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
||||
boolQueryBuilder.must(QueryBuilders.termQuery(OBSERVATION_IDENTIFIER_FIELD_NAME, theObservationIdentifier));
|
||||
searchSourceBuilder.query(boolQueryBuilder);
|
||||
searchSourceBuilder.size(1);
|
||||
|
||||
searchRequest.source(searchSourceBuilder);
|
||||
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeJson getObservationCodeDocument(String theCodeSystemHash, String theText) {
|
||||
if(theCodeSystemHash == null && theText == null) {
|
||||
throw new InvalidRequestException("Require a non-null code system hash value or display value for observation code document query");
|
||||
}
|
||||
SearchRequest theSearchRequest = buildSingleObservationCodeSearchRequest(theCodeSystemHash, theText);
|
||||
CodeJson observationCodeDocumentJson = null;
|
||||
try {
|
||||
SearchResponse observationCodeDocumentResponse = executeSearchRequest(theSearchRequest);
|
||||
SearchHit[] observationCodeDocumentHits = observationCodeDocumentResponse.getHits().getHits();
|
||||
if (observationCodeDocumentHits.length > 0) {
|
||||
// There should be no more than one hit for the code lookup.
|
||||
String observationCodeDocument = observationCodeDocumentHits[0].getSourceAsString();
|
||||
observationCodeDocumentJson = objectMapper.readValue(observationCodeDocument, CodeJson.class);
|
||||
}
|
||||
|
||||
} catch (IOException theE) {
|
||||
throw new InvalidRequestException("Unable to execute observation code document query hash code or display", theE);
|
||||
}
|
||||
|
||||
return observationCodeDocumentJson;
|
||||
}
|
||||
|
||||
private SearchRequest buildSingleObservationCodeSearchRequest(String theCodeSystemHash, String theText) {
|
||||
SearchRequest searchRequest = new SearchRequest(OBSERVATION_CODE_INDEX);
|
||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
||||
if (theCodeSystemHash != null) {
|
||||
boolQueryBuilder.must(QueryBuilders.termQuery("codingcode_system_hash", theCodeSystemHash));
|
||||
} else {
|
||||
boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("text", theText));
|
||||
}
|
||||
|
||||
searchSourceBuilder.query(boolQueryBuilder);
|
||||
searchSourceBuilder.size(1);
|
||||
|
||||
searchRequest.source(searchSourceBuilder);
|
||||
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrUpdateObservationIndex(String theDocumentId, ObservationJson theObservationDocument){
|
||||
try {
|
||||
String documentToIndex = objectMapper.writeValueAsString(theObservationDocument);
|
||||
return performIndex(OBSERVATION_INDEX, theDocumentId, documentToIndex, ElasticsearchSvcImpl.OBSERVATION_DOCUMENT_TYPE);
|
||||
} catch (IOException theE) {
|
||||
throw new InvalidRequestException("Unable to persist Observation document " + theDocumentId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrUpdateObservationCodeIndex(String theCodeableConceptID, CodeJson theObservationCodeDocument) {
|
||||
try {
|
||||
String documentToIndex = objectMapper.writeValueAsString(theObservationCodeDocument);
|
||||
return performIndex(OBSERVATION_CODE_INDEX, theCodeableConceptID, documentToIndex, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE);
|
||||
} catch (IOException theE) {
|
||||
throw new InvalidRequestException("Unable to persist Observation Code document " + theCodeableConceptID);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean performIndex(String theIndexName, String theDocumentId, String theIndexDocument, String theDocumentType) throws IOException {
|
||||
IndexResponse indexResponse = myRestHighLevelClient.index(createIndexRequest(theIndexName, theDocumentId, theIndexDocument, theDocumentType),
|
||||
RequestOptions.DEFAULT);
|
||||
|
||||
|
@ -556,11 +653,27 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
|||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObservationDocument(String theDocumentId) {
|
||||
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(OBSERVATION_INDEX);
|
||||
deleteByQueryRequest.setQuery(QueryBuilders.termQuery(OBSERVATION_IDENTIFIER_FIELD_NAME, theDocumentId));
|
||||
try {
|
||||
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
||||
} catch (IOException theE) {
|
||||
throw new InvalidRequestException("Unable to delete Observation " + theDocumentId);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void deleteAllDocuments(String theIndexName) throws IOException {
|
||||
public void deleteAllDocumentsForTest(String theIndexName) throws IOException {
|
||||
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(theIndexName);
|
||||
deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
|
||||
myRestHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void refreshIndex(String theIndexName) throws IOException {
|
||||
myRestHighLevelClient.indices().refresh(new RefreshRequest(theIndexName), RequestOptions.DEFAULT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import ca.uhn.fhir.rest.param.ReferenceParam;
|
|||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -22,7 +21,6 @@ import org.hl7.fhir.r4.model.DateTimeType;
|
|||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -40,11 +38,8 @@ import java.util.GregorianCalendar;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
|
|
@ -87,22 +87,29 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
|||
@Test
|
||||
public void testIndexObservationSingle() {
|
||||
indexSingleObservation();
|
||||
List<ObservationIndexedSearchParamLastNEntity> persistedObservationEntities = myResourceIndexedObservationLastNDao.findAll();
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.setLastNMax(10);
|
||||
List<ObservationJson> persistedObservationEntities = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
||||
assertEquals(1, persistedObservationEntities.size());
|
||||
ObservationIndexedSearchParamLastNEntity persistedObservationEntity = persistedObservationEntities.get(0);
|
||||
ObservationJson persistedObservationEntity = persistedObservationEntities.get(0);
|
||||
assertEquals(SINGLE_SUBJECT_ID, persistedObservationEntity.getSubject());
|
||||
assertEquals(SINGLE_OBSERVATION_PID, persistedObservationEntity.getIdentifier());
|
||||
assertEquals(SINGLE_EFFECTIVEDTM, persistedObservationEntity.getEffectiveDtm());
|
||||
|
||||
String observationCodeNormalizedId = persistedObservationEntity.getCodeNormalizedId();
|
||||
String observationCodeNormalizedId = persistedObservationEntity.getCode_concept_id();
|
||||
|
||||
List<ObservationIndexedCodeCodeableConceptEntity> persistedObservationCodes = myCodeableConceptIndexedSearchParamNormalizedDao.findAll();
|
||||
assertEquals(1, persistedObservationCodes.size());
|
||||
ObservationIndexedCodeCodeableConceptEntity persistedObservationCode = persistedObservationCodes.get(0);
|
||||
// Check that we can retrieve code by hash value.
|
||||
String codeSystemHash = persistedObservationEntity.getCode_coding_code_system_hash();
|
||||
CodeJson persistedObservationCode = elasticsearchSvc.getObservationCodeDocument(codeSystemHash, null);
|
||||
assertNotNull(persistedObservationCode);
|
||||
assertEquals(observationCodeNormalizedId, persistedObservationCode.getCodeableConceptId());
|
||||
assertEquals(SINGLE_OBSERVATION_CODE_TEXT, persistedObservationCode.getCodeableConceptText());
|
||||
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
// Also confirm that we can retrieve code by text value.
|
||||
persistedObservationCode = elasticsearchSvc.getObservationCodeDocument(null, SINGLE_OBSERVATION_CODE_TEXT);
|
||||
assertNotNull(persistedObservationCode);
|
||||
|
||||
searchParameterMap = new SearchParameterMap();
|
||||
ReferenceParam subjectParam = new ReferenceParam("Patient", "", SINGLE_SUBJECT_ID);
|
||||
searchParameterMap.add(Observation.SP_SUBJECT, new ReferenceAndListParam().addAnd(new ReferenceOrListParam().addOr(subjectParam)));
|
||||
TokenParam categoryParam = new TokenParam(CATEGORYFIRSTCODINGSYSTEM, FIRSTCATEGORYFIRSTCODINGCODE);
|
||||
|
@ -174,11 +181,13 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
|||
@Test
|
||||
public void testIndexObservationMultiple() {
|
||||
indexMultipleObservations();
|
||||
assertEquals(100, myResourceIndexedObservationLastNDao.count());
|
||||
assertEquals(2, myCodeableConceptIndexedSearchParamNormalizedDao.count());
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.setLastNMax(100);
|
||||
List<ObservationJson> observationDocuments = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
||||
assertEquals(100, observationDocuments.size());
|
||||
|
||||
// Check that all observations were indexed.
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
||||
|
||||
searchParameterMap.setLastNMax(10);
|
||||
|
@ -271,12 +280,15 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
|||
@Test
|
||||
public void testDeleteObservation() {
|
||||
indexMultipleObservations();
|
||||
assertEquals(100, myResourceIndexedObservationLastNDao.count());
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.setLastNMax(100);
|
||||
List<ObservationJson> observationDocuments = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
||||
assertEquals(100, observationDocuments.size());
|
||||
// Check that fifth observation for fifth patient has been indexed.
|
||||
ObservationIndexedSearchParamLastNEntity observation = myResourceIndexedObservationLastNDao.findByIdentifier("55");
|
||||
ObservationJson observation = elasticsearchSvc.getObservationDocument("55");
|
||||
assertNotNull(observation);
|
||||
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
||||
searchParameterMap.setLastNMax(10);
|
||||
List<String> observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, myFhirCtx, 200);
|
||||
|
@ -292,8 +304,11 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
|||
testObservationPersist.deleteObservationIndex(entity);
|
||||
|
||||
// Confirm that observation was deleted.
|
||||
assertEquals(99, myResourceIndexedObservationLastNDao.count());
|
||||
observation = myResourceIndexedObservationLastNDao.findByIdentifier("55");
|
||||
searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.setLastNMax(100);
|
||||
observationDocuments = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
||||
assertEquals(99, observationDocuments.size());
|
||||
observation = elasticsearchSvc.getObservationDocument("55");
|
||||
assertNull(observation);
|
||||
|
||||
observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, myFhirCtx, 200);
|
||||
|
@ -413,5 +428,4 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
|
||||
private final Map<String, Map<String, List<Date>>> createdPatientObservationMap = new HashMap<>();
|
||||
|
||||
private FhirContext myFhirContext = FhirContext.forR4();
|
||||
private final FhirContext myFhirContext = FhirContext.forR4();
|
||||
|
||||
|
||||
@BeforeClass
|
||||
|
@ -53,8 +53,8 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
|
||||
@After
|
||||
public void after() throws IOException {
|
||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX);
|
||||
elasticsearchSvc.deleteAllDocumentsForTest(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||
elasticsearchSvc.deleteAllDocumentsForTest(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -317,23 +317,21 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
String codeJson2Document = ourMapperNonPrettyPrint.writeValueAsString(codeJson2);
|
||||
|
||||
// Create CodeableConcepts for two categories, each with three codings.
|
||||
List<Coding> category1 = new ArrayList<>();
|
||||
// Create three codings and first category CodeableConcept
|
||||
category1.add(new Coding("http://mycodes.org/fhir/observation-category", "test-heart-rate", "test-heart-rate display"));
|
||||
category1.add(new Coding("http://myalternatecodes.org/fhir/observation-category", "test-alt-heart-rate", "test-alt-heart-rate display"));
|
||||
category1.add(new Coding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-heart-rate", "test-2nd-alt-heart-rate display"));
|
||||
List<CodeableConcept> categoryConcepts1 = new ArrayList<>();
|
||||
CodeableConcept categoryCodeableConcept1 = new CodeableConcept().setText("Test Codeable Concept Field for first category");
|
||||
categoryCodeableConcept1.setCoding(category1);
|
||||
List<CodeJson> categoryConcepts1 = new ArrayList<>();
|
||||
CodeJson categoryCodeableConcept1 = new CodeJson();
|
||||
categoryCodeableConcept1.setCodeableConceptText("Test Codeable Concept Field for first category");
|
||||
categoryCodeableConcept1.addCoding("http://mycodes.org/fhir/observation-category", "test-heart-rate", "test-heart-rate display");
|
||||
categoryCodeableConcept1.addCoding("http://myalternatecodes.org/fhir/observation-category", "test-alt-heart-rate", "test-alt-heart-rate display");
|
||||
categoryCodeableConcept1.addCoding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-heart-rate", "test-2nd-alt-heart-rate display");
|
||||
categoryConcepts1.add(categoryCodeableConcept1);
|
||||
// Create three codings and second category CodeableConcept
|
||||
List<Coding> category2 = new ArrayList<>();
|
||||
category2.add(new Coding("http://mycodes.org/fhir/observation-category", "test-vital-signs", "test-vital-signs display"));
|
||||
category2.add(new Coding("http://myalternatecodes.org/fhir/observation-category", "test-alt-vitals", "test-alt-vitals display"));
|
||||
category2.add(new Coding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-vitals", "test-2nd-alt-vitals display"));
|
||||
List<CodeableConcept> categoryConcepts2 = new ArrayList<>();
|
||||
CodeableConcept categoryCodeableConcept2 = new CodeableConcept().setText("Test Codeable Concept Field for second category");
|
||||
categoryCodeableConcept2.setCoding(category2);
|
||||
List<CodeJson> categoryConcepts2 = new ArrayList<>();
|
||||
CodeJson categoryCodeableConcept2 = new CodeJson();
|
||||
categoryCodeableConcept2.setCodeableConceptText("Test Codeable Concept Field for second category");
|
||||
categoryCodeableConcept2.addCoding("http://mycodes.org/fhir/observation-category", "test-vital-signs", "test-vital-signs display");
|
||||
categoryCodeableConcept2.addCoding("http://myalternatecodes.org/fhir/observation-category", "test-alt-vitals", "test-alt-vitals display");
|
||||
categoryCodeableConcept2.addCoding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-vitals", "test-2nd-alt-vitals display");
|
||||
categoryConcepts2.add(categoryCodeableConcept2);
|
||||
|
||||
for (int patientCount = 0; patientCount < 10; patientCount++) {
|
||||
|
@ -349,14 +347,14 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
|
||||
if (entryCount % 2 == 1) {
|
||||
observationJson.setCategories(categoryConcepts1);
|
||||
observationJson.setCode(codeableConceptField1);
|
||||
observationJson.setCode(codeJson1);
|
||||
observationJson.setCode_concept_id(codeableConceptId1);
|
||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX, codeableConceptId1, codeJson1Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
||||
assertTrue(elasticsearchSvc.createOrUpdateObservationCodeIndex(codeableConceptId1, codeJson1));
|
||||
} else {
|
||||
observationJson.setCategories(categoryConcepts2);
|
||||
observationJson.setCode(codeableConceptField2);
|
||||
observationJson.setCode(codeJson2);
|
||||
observationJson.setCode_concept_id(codeableConceptId2);
|
||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX, codeableConceptId2, codeJson2Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
||||
assertTrue(elasticsearchSvc.createOrUpdateObservationCodeIndex(codeableConceptId2, codeJson2));
|
||||
}
|
||||
|
||||
Calendar observationDate = new GregorianCalendar();
|
||||
|
@ -364,8 +362,7 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
Date effectiveDtm = observationDate.getTime();
|
||||
observationJson.setEffectiveDtm(effectiveDtm);
|
||||
|
||||
String observationDocument = ourMapperNonPrettyPrint.writeValueAsString(observationJson);
|
||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX, identifier, observationDocument, ElasticsearchSvcImpl.OBSERVATION_DOCUMENT_TYPE));
|
||||
assertTrue(elasticsearchSvc.createOrUpdateObservationIndex(identifier, observationJson));
|
||||
|
||||
if (createdPatientObservationMap.containsKey(subject)) {
|
||||
Map<String, List<Date>> observationCodeMap = createdPatientObservationMap.get(subject);
|
||||
|
@ -392,11 +389,8 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException theE) {
|
||||
theE.printStackTrace();
|
||||
}
|
||||
elasticsearchSvc.refreshIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||
elasticsearchSvc.refreshIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX);
|
||||
|
||||
}
|
||||
|
||||
|
@ -404,7 +398,7 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
|||
public void testLastNNoParamsQuery() {
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.setLastNMax(1);
|
||||
List<ObservationJson> observations = elasticsearchSvc.executeLastNWithAllFields(searchParameterMap, myFhirContext);
|
||||
List<ObservationJson> observations = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirContext);
|
||||
|
||||
assertEquals(2, observations.size());
|
||||
|
||||
|
|
|
@ -294,8 +294,7 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
|||
codeableConceptField.addCoding(new Coding(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE, CODEFIRSTCODINGDISPLAY));
|
||||
indexedObservation.setCode(codeableConceptField);
|
||||
|
||||
String observationDocument = ourMapperNonPrettyPrint.writeValueAsString(indexedObservation);
|
||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX, RESOURCEPID, observationDocument, ElasticsearchSvcImpl.OBSERVATION_DOCUMENT_TYPE));
|
||||
assertTrue(elasticsearchSvc.createOrUpdateObservationIndex(RESOURCEPID, indexedObservation));
|
||||
|
||||
CodeJson observationCode = new CodeJson(codeableConceptField, OBSERVATIONSINGLECODEID);
|
||||
String codeDocument = ourMapperNonPrettyPrint.writeValueAsString(observationCode);
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
@Embeddable
|
||||
public class ObservationIndexedCategoryCodeableConceptEntity {
|
||||
|
||||
@Field(name = "text")
|
||||
private String myCodeableConceptText;
|
||||
|
||||
@IndexedEmbedded(depth=2, prefix = "coding")
|
||||
@OneToMany(mappedBy = "myCodeableConceptId", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private Set<ObservationIndexedCategoryCodingEntity> myObservationIndexedCategoryCodingEntitySet;
|
||||
|
||||
public ObservationIndexedCategoryCodeableConceptEntity(String theCodeableConceptText) {
|
||||
setCodeableConceptText(theCodeableConceptText);
|
||||
}
|
||||
|
||||
public void setObservationIndexedCategoryCodingEntitySet(Set<ObservationIndexedCategoryCodingEntity> theObservationIndexedCategoryCodingEntitySet) {
|
||||
myObservationIndexedCategoryCodingEntitySet = theObservationIndexedCategoryCodingEntitySet;
|
||||
}
|
||||
|
||||
public void setCodeableConceptText(String theCodeableConceptText) {
|
||||
myCodeableConceptText = theCodeableConceptText;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.util.CodeSystemHash;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Embeddable
|
||||
public class ObservationIndexedCategoryCodingEntity {
|
||||
|
||||
@Field (name = "code", analyze = Analyze.NO)
|
||||
private String myCode;
|
||||
@Field (name = "system", analyze = Analyze.NO)
|
||||
private String mySystem;
|
||||
@Field (name = "code_system_hash", analyze = Analyze.NO)
|
||||
private String myCodeSystemHash;
|
||||
@Field (name = "display")
|
||||
private String myDisplay;
|
||||
|
||||
public ObservationIndexedCategoryCodingEntity(String theSystem, String theCode, String theDisplay) {
|
||||
myCode = theCode;
|
||||
mySystem = theSystem;
|
||||
myCodeSystemHash = String.valueOf(CodeSystemHash.hashCodeSystem(theSystem, theCode));
|
||||
myDisplay = theDisplay;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.hibernate.search.annotations.DocumentId;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Indexed(index = "code_index")
|
||||
@Embeddable
|
||||
@Table(name = "HFJ_SPIDX_LASTN_CODE_CONCEPT")
|
||||
public class ObservationIndexedCodeCodeableConceptEntity {
|
||||
|
||||
public static final int MAX_LENGTH = 200;
|
||||
|
||||
@Id
|
||||
@DocumentId(name = "codeable_concept_id")
|
||||
@Column(name="CODEABLE_CONCEPT_ID", length = MAX_LENGTH)
|
||||
private String myCodeableConceptId;
|
||||
|
||||
@Field(name = "text")
|
||||
@Column(name = "CODEABLE_CONCEPT_TEXT", nullable = true, length = MAX_LENGTH)
|
||||
private String myCodeableConceptText;
|
||||
|
||||
@IndexedEmbedded(depth=2, prefix = "coding")
|
||||
@JoinColumn(name = "CODEABLE_CONCEPT_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_CONCEPT_CODE"))
|
||||
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private ObservationIndexedCodeCodingEntity myObservationIndexedCodeCodingEntity;
|
||||
|
||||
public ObservationIndexedCodeCodeableConceptEntity() {
|
||||
|
||||
}
|
||||
|
||||
public ObservationIndexedCodeCodeableConceptEntity(String theCodeableConceptText, String theCodeableConceptId) {
|
||||
setCodeableConceptText(theCodeableConceptText);
|
||||
setCodeableConceptId(theCodeableConceptId);
|
||||
}
|
||||
|
||||
public void addCoding(ObservationIndexedCodeCodingEntity theObservationIndexedCodeCodingEntity) {
|
||||
myObservationIndexedCodeCodingEntity = theObservationIndexedCodeCodingEntity;
|
||||
}
|
||||
|
||||
public String getCodeableConceptId() {
|
||||
return myCodeableConceptId;
|
||||
}
|
||||
|
||||
public void setCodeableConceptId(String theCodeableConceptId) {
|
||||
myCodeableConceptId = theCodeableConceptId;
|
||||
}
|
||||
|
||||
public String getCodeableConceptText() {
|
||||
return myCodeableConceptText;
|
||||
}
|
||||
|
||||
public void setCodeableConceptText(String theCodeableConceptText) {
|
||||
myCodeableConceptText = theCodeableConceptText;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.hibernate.search.annotations.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Index;
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "HFJ_LASTN_OBSERVATION", indexes = {
|
||||
@Index(name = "IDX_LASTN_OBSERVATION_RESID", columnList = "RESOURCE_IDENTIFIER", unique = true)
|
||||
})
|
||||
@Indexed(index = "observation_index")
|
||||
public class ObservationIndexedSearchParamLastNEntity {
|
||||
|
||||
public static final int MAX_LENGTH = 200;
|
||||
|
||||
@Id
|
||||
@SequenceGenerator(name = "SEQ_LASTN", sequenceName = "SEQ_LASTN")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_LASTN")
|
||||
@Column(name = "LASTN_ID")
|
||||
private Long myId;
|
||||
|
||||
@Field(name = "subject", analyze = Analyze.NO)
|
||||
@Column(name = "LASTN_SUBJECT_ID", nullable = true, length = MAX_LENGTH)
|
||||
private String mySubject;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "CODEABLE_CONCEPT_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_OBSERVATION_CODE_FK"))
|
||||
@IndexedEmbedded(depth = 2, prefix = "codeconcept")
|
||||
private ObservationIndexedCodeCodeableConceptEntity myObservationCode;
|
||||
|
||||
@Field(name = "codeconceptid", analyze = Analyze.NO)
|
||||
@Column(name = "CODEABLE_CONCEPT_ID", nullable = false, updatable = false, insertable = false, length = MAX_LENGTH)
|
||||
private String myCodeNormalizedId;
|
||||
|
||||
@IndexedEmbedded(depth = 2, prefix = "categoryconcept")
|
||||
@Transient
|
||||
private Set<ObservationIndexedCategoryCodeableConceptEntity> myCategoryCodeableConcepts;
|
||||
|
||||
@Field(name = "effectivedtm", analyze = Analyze.NO)
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "LASTN_EFFECTIVE_DATETIME", nullable = true)
|
||||
private Date myEffectiveDtm;
|
||||
|
||||
@DocumentId(name = "identifier")
|
||||
@Column(name = "RESOURCE_IDENTIFIER", nullable = false, length = MAX_LENGTH)
|
||||
private String myIdentifier;
|
||||
|
||||
public ObservationIndexedSearchParamLastNEntity() {
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return mySubject;
|
||||
}
|
||||
|
||||
public void setSubject(String theSubject) {
|
||||
mySubject = theSubject;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return myIdentifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(String theIdentifier) {
|
||||
myIdentifier = theIdentifier;
|
||||
}
|
||||
|
||||
public void setEffectiveDtm(Date theEffectiveDtm) {
|
||||
myEffectiveDtm = theEffectiveDtm;
|
||||
}
|
||||
|
||||
public Date getEffectiveDtm() {
|
||||
return myEffectiveDtm;
|
||||
}
|
||||
|
||||
public void setCodeNormalizedId(String theCodeNormalizedId) {
|
||||
myCodeNormalizedId = theCodeNormalizedId;
|
||||
}
|
||||
|
||||
public String getCodeNormalizedId() {
|
||||
return myCodeNormalizedId;
|
||||
}
|
||||
|
||||
|
||||
public void setObservationCode(ObservationIndexedCodeCodeableConceptEntity theObservationCode) {
|
||||
myObservationCode = theObservationCode;
|
||||
}
|
||||
|
||||
public void setCategoryCodeableConcepts(Set<ObservationIndexedCategoryCodeableConceptEntity> theCategoryCodeableConcepts) {
|
||||
myCategoryCodeableConcepts = theCategoryCodeableConcepts;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue