Fix exception when contained indexing met hibernate search. (#3372)

* Fix exception when contained indexing met hibernate search.
This commit is contained in:
michaelabuckley 2022-02-09 20:27:40 -05:00 committed by GitHub
parent a9348b6c51
commit 3531d9b4fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 12 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 3371
title: "Enhanced Lucene Indexing failed when indexing contained resources.
Contained resources are not indexed in Lucene/Elasticsearch, but this no longer causes an exception."

View File

@ -59,7 +59,7 @@ public class ExtendedLuceneSearchBuilder {
// each and clause may have a different modifier, so split down to the ORs // each and clause may have a different modifier, so split down to the ORs
.flatMap(andList -> andList.getValue().stream()) .flatMap(andList -> andList.getValue().stream())
.flatMap(Collection::stream) .flatMap(Collection::stream)
.anyMatch(this::isParamSupported); .anyMatch(this::isParamTypeSupported);
} }
/** /**
@ -67,7 +67,7 @@ public class ExtendedLuceneSearchBuilder {
* *
* NOTE - keep this in sync with addAndConsumeAdvancedQueryClauses() below. * NOTE - keep this in sync with addAndConsumeAdvancedQueryClauses() below.
*/ */
private boolean isParamSupported(IQueryParameterType param) { private boolean isParamTypeSupported(IQueryParameterType param) {
String modifier = StringUtils.defaultString(param.getQueryParameterQualifier(), EMPTY_MODIFIER); String modifier = StringUtils.defaultString(param.getQueryParameterQualifier(), EMPTY_MODIFIER);
if (param instanceof TokenParam) { if (param instanceof TokenParam) {
switch (modifier) { switch (modifier) {

View File

@ -15,6 +15,7 @@ import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
@ -51,6 +52,7 @@ import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -119,12 +121,10 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
private IBulkDataExportSvc myBulkDataExportSvc; private IBulkDataExportSvc myBulkDataExportSvc;
@Autowired @Autowired
private ITermCodeSystemStorageSvc myTermCodeSystemStorageSvc; private ITermCodeSystemStorageSvc myTermCodeSystemStorageSvc;
private boolean myContainsSettings;
@BeforeEach @BeforeEach
public void beforePurgeDatabase() { public void beforePurgeDatabase() {
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc); purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc);
myDaoConfig.setAdvancedLuceneIndexing(true);
} }
@Override @Override
@ -138,14 +138,16 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
} }
@BeforeEach @BeforeEach
public void enableContains() { public void enableContainsAndLucene() {
myContainsSettings = myDaoConfig.isAllowContainsSearches();
myDaoConfig.setAllowContainsSearches(true); myDaoConfig.setAllowContainsSearches(true);
myDaoConfig.setAdvancedLuceneIndexing(true);
} }
@AfterEach @AfterEach
public void restoreContains() { public void restoreContains() {
myDaoConfig.setAllowContainsSearches(myContainsSettings); DaoConfig defaultConfig = new DaoConfig();
myDaoConfig.setAllowContainsSearches(defaultConfig.isAllowContainsSearches());
myDaoConfig.setAdvancedLuceneIndexing(defaultConfig.isAdvancedLuceneIndexing());
} }
@Test @Test
@ -500,6 +502,48 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
assertThat(message, toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(iIdTypes))); assertThat(message, toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(iIdTypes)));
} }
@Nested
public class WithContainedIndexing {
@BeforeEach
public void enableContains() {
// we don't support chained or contained yet, but turn it on to test we don't blow up.
myDaoConfig.getModelConfig().setIndexOnContainedResources(true);
myDaoConfig.getModelConfig().setIndexOnContainedResourcesRecursively(true);
}
@AfterEach
public void restoreContains() {
ModelConfig defaultModelConfig = new ModelConfig();
myDaoConfig.getModelConfig().setIndexOnContainedResources(defaultModelConfig.isIndexOnContainedResources());
myDaoConfig.getModelConfig().setIndexOnContainedResourcesRecursively(defaultModelConfig.isIndexOnContainedResourcesRecursively());
}
/**
* We were throwing when indexing contained.
* https://github.com/hapifhir/hapi-fhir/issues/3371
*/
@Test
public void ignoreContainedResources_noError() {
// given
String json =
"{" +
"\"resourceType\": \"Observation\"," +
"\"contained\": [{" +
"\"resourceType\": \"Patient\"," +
"\"id\": \"contained-patient\"," +
"\"name\": [{ \"family\": \"Smith\"}]" +
"}]," +
"\"subject\": { \"reference\": \"#contained-patient\" }" +
"}";
Observation o = myFhirCtx.newJsonParser().parseResource(Observation.class, json);
myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless();
// no error.
}
}
@Test @Test
public void testExpandWithIsAInExternalValueSet() { public void testExpandWithIsAInExternalValueSet() {
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
@ -516,7 +560,6 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
} }
@Test @Test
public void testExpandWithFilter() { public void testExpandWithFilter() {
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();

View File

@ -28,6 +28,8 @@ import org.hibernate.search.engine.backend.document.DocumentElement;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.function.BiConsumer;
/** /**
* Collects our lucene extended indexing data. * Collects our lucene extended indexing data.
* *
@ -44,13 +46,22 @@ public class ExtendedLuceneIndexData {
this.myFhirContext = theFhirContext; this.myFhirContext = theFhirContext;
} }
private <V> BiConsumer<String, V> ifNotContained(BiConsumer<String, V> theIndexWriter) {
return (s,v) -> {
// Ignore contained resources for now.
if (!s.contains(".")) {
theIndexWriter.accept(s,v);
}
};
}
public void writeIndexElements(DocumentElement theDocument) { public void writeIndexElements(DocumentElement theDocument) {
HibernateSearchIndexWriter indexWriter = HibernateSearchIndexWriter.forRoot(myFhirContext, theDocument); HibernateSearchIndexWriter indexWriter = HibernateSearchIndexWriter.forRoot(myFhirContext, theDocument);
// TODO MB Use RestSearchParameterTypeEnum to define templates. ourLog.debug("Writing JPA index to Hibernate Search");
mySearchParamStrings.forEach(indexWriter::writeStringIndex);
mySearchParamTokens.forEach(indexWriter::writeTokenIndex); mySearchParamStrings.forEach(ifNotContained(indexWriter::writeStringIndex));
mySearchParamLinks.forEach(indexWriter::writeReferenceIndex); mySearchParamTokens.forEach(ifNotContained(indexWriter::writeTokenIndex));
mySearchParamLinks.forEach(ifNotContained(indexWriter::writeReferenceIndex));
} }
public void addStringIndexData(String theSpName, String theText) { public void addStringIndexData(String theSpName, String theText) {