Changed observation indexing to bypass hibernate search and removed Observation indexing tables.

This commit is contained in:
ianmarshall 2020-06-04 13:10:06 -04:00
parent 60e420aaa3
commit 6e507bf642
12 changed files with 175 additions and 428 deletions

View File

@ -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"))

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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 {
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}