Avoid multi-term for ElasticSearch (#1717)

* Avoid multi-term for ElasticSearch

* Add changelog

* Remove redundant code
This commit is contained in:
James Agnew 2020-02-18 16:40:44 -05:00 committed by GitHub
parent fba28950ec
commit ab8dfa5a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 243 additions and 3 deletions

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 1717
title: ValueSet expansions containing lists of terms did not correctly expand when backed by
ElasticSearch due to the use of a feature not supported in ES. Thanks to Jens Villadsen for
reporting!

View File

@ -66,6 +66,7 @@ import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery; import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.FullTextEntityManager;
@ -600,11 +601,16 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo
.map(t -> new Term("myCode", t)) .map(t -> new Term("myCode", t))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (codes.size() > 0) { if (codes.size() > 0) {
MultiPhraseQuery query = new MultiPhraseQuery();
query.add(codes.toArray(new Term[0])); BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.setMinimumNumberShouldMatch(1);
for (Term nextCode : codes) {
builder.add(new TermQuery(nextCode), BooleanClause.Occur.SHOULD);
}
luceneQuery = new BooleanQuery.Builder() luceneQuery = new BooleanQuery.Builder()
.add(luceneQuery, BooleanClause.Occur.MUST) .add(luceneQuery, BooleanClause.Occur.MUST)
.add(query, BooleanClause.Occur.MUST) .add(builder.build(), BooleanClause.Occur.MUST)
.build(); .build();
} }

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.hamcrest.Matchers;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -37,8 +38,10 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -146,6 +149,53 @@ public class FhirResourceDaoR4SearchWithElasticSearchTest extends BaseJpaTest {
} }
@Test
public void testExpandVsWithMultiInclude_All() throws IOException {
CodeSystem cs = loadResource(myFhirCtx, CodeSystem.class, "/r4/expand-multi-cs.json");
myCodeSystemDao.update(cs);
ValueSet vs = loadResource(myFhirCtx, ValueSet.class, "/r4/expand-multi-vs-all.json");
ValueSet expanded = myValueSetDao.expand(vs, null);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expanded));
// All codes
List<String> codes = expanded
.getExpansion()
.getContains()
.stream()
.map(t -> t.getCode())
.sorted()
.collect(Collectors.toList());
assertThat(codes.toString(), codes, Matchers.contains("advice", "message", "note", "notification"));
}
@Test
public void testExpandVsWithMultiInclude_Some() throws IOException {
CodeSystem cs = loadResource(myFhirCtx, CodeSystem.class, "/r4/expand-multi-cs.json");
myCodeSystemDao.update(cs);
ValueSet vs = loadResource(myFhirCtx, ValueSet.class, "/r4/expand-multi-vs-all.json");
vs.getCompose().getInclude().get(0).getConcept().remove(0);
vs.getCompose().getInclude().get(0).getConcept().remove(0);
ValueSet expanded = myValueSetDao.expand(vs, null);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expanded));
// All codes
List<String> codes = expanded
.getExpansion()
.getContains()
.stream()
.map(t -> t.getCode())
.sorted()
.collect(Collectors.toList());
assertThat(codes.toString(), codes, Matchers.contains("advice", "note"));
}
private CodeSystem createExternalCs() { private CodeSystem createExternalCs() {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setUrl(URL_MY_CODE_SYSTEM);

View File

@ -0,0 +1,86 @@
{
"resourceType" : "CodeSystem",
"id" : "ehealth-message-category",
"text" : {
"status" : "generated",
"div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h2>MessageCategory</h2><div><p>Message category types</p>\n</div><p>This code system http://ehealth.sundhed.dk/cs/message-category defines the following codes:</p><table class=\"codes\"><tr><td style=\"white-space:nowrap\"><b>Code</b></td><td><b>Display</b></td><td><b>Definition</b></td></tr><tr><td style=\"white-space:nowrap\">message<a name=\"ehealth-message-category-message\"> </a></td><td>Message</td><td/></tr><tr><td style=\"white-space:nowrap\">notification<a name=\"ehealth-message-category-notification\"> </a></td><td>Notification</td><td/></tr><tr><td style=\"white-space:nowrap\">advice<a name=\"ehealth-message-category-advice\"> </a></td><td>Advice</td><td/></tr><tr><td style=\"white-space:nowrap\">note<a name=\"ehealth-message-category-note\"> </a></td><td>Note</td><td/></tr></table></div>"
},
"url" : "http://ehealth.sundhed.dk/cs/message-category",
"version" : "0.6.0",
"name" : "MessageCategory",
"status" : "active",
"experimental" : false,
"date" : "2019-01-29T00:00:00+00:00",
"publisher" : "ehealth.sundhed.dk",
"contact" : [
{
"telecom" : [
{
"system" : "url",
"value" : "http://ehealth.sundhed.dk/terminology"
}
]
}
],
"description" : "Message category types",
"caseSensitive" : true,
"content" : "complete",
"concept" : [
{
"code" : "message",
"display" : "Message",
"designation" : [
{
"language" : "en-US",
"value" : "Message"
},
{
"language" : "da",
"value" : "Besked"
}
]
},
{
"code" : "notification",
"display" : "Notification",
"designation" : [
{
"language" : "en-US",
"value" : "Notification"
},
{
"language" : "da",
"value" : "Notifikation"
}
]
},
{
"code" : "advice",
"display" : "Advice",
"designation" : [
{
"language" : "en-US",
"value" : "Advice"
},
{
"language" : "da",
"value" : "Advisering"
}
]
},
{
"code" : "note",
"display" : "Note",
"designation" : [
{
"language" : "en-US",
"value" : "Note"
},
{
"language" : "da",
"value" : "Note"
}
]
}
]
}

View File

@ -0,0 +1,92 @@
{
"resourceType" : "ValueSet",
"id" : "message-category",
"text" : {
"status" : "generated",
"div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h2>MessageCategory</h2><div><p>The set of possible message types</p>\n</div><p>This value set includes codes from the following code systems:</p><ul><li>Include these codes as defined in <a href=\"CodeSystem-ehealth-message-category.html\"><code>http://ehealth.sundhed.dk/cs/message-category</code></a><table class=\"none\"><tr><td style=\"white-space:nowrap\"><b>Code</b></td><td><b>Display</b></td></tr><tr><td><a href=\"CodeSystem-ehealth-message-category.html#ehealth-message-category-message\">message</a></td><td>Message</td><td/></tr><tr><td><a href=\"CodeSystem-ehealth-message-category.html#ehealth-message-category-notification\">notification</a></td><td>Notification</td><td/></tr><tr><td><a href=\"CodeSystem-ehealth-message-category.html#ehealth-message-category-advice\">advice</a></td><td>Advice</td><td/></tr><tr><td><a href=\"CodeSystem-ehealth-message-category.html#ehealth-message-category-note\">note</a></td><td>Note</td><td/></tr></table></li></ul><p><b>Additional Language Displays</b></p><table class=\"codes\"><tr><td><b>Code</b></td><td><b>Dansk (Danish, da)</b></td><td><b>English (United States) (English (United States), en)</b></td></tr><tr><td>message</td><td>Besked</td><td>Message</td></tr><tr><td>notification</td><td>Notifikation</td><td>Notification</td></tr><tr><td>advice</td><td>Advisering</td><td>Advice</td></tr><tr><td>note</td><td>Note</td><td>Note</td></tr></table></div>"
},
"url" : "http://ehealth.sundhed.dk/vs/message-category",
"version" : "0.0.1",
"name" : "MessageCategory",
"status" : "active",
"experimental" : true,
"date" : "2019-02-08T00:00:00+00:00",
"publisher" : "ehealth.sundhed.dk",
"contact" : [
{
"name" : "FUT",
"telecom" : [
{
"system" : "url",
"value" : "https://digst.dk/digital-service/digital-velfaerd/telemedicin-kol/faelles-udbud-af-telemedicin-fut/"
}
]
}
],
"description" : "The set of possible message types",
"compose" : {
"include" : [
{
"system" : "http://ehealth.sundhed.dk/cs/message-category",
"concept" : [
{
"code" : "message",
"display" : "Message",
"designation" : [
{
"language" : "en-US",
"value" : "Message"
},
{
"language" : "da",
"value" : "Besked"
}
]
},
{
"code" : "notification",
"display" : "Notification",
"designation" : [
{
"language" : "en-US",
"value" : "Notification"
},
{
"language" : "da",
"value" : "Notifikation"
}
]
},
{
"code" : "advice",
"display" : "Advice",
"designation" : [
{
"language" : "en-US",
"value" : "Advice"
},
{
"language" : "da",
"value" : "Advisering"
}
]
},
{
"code" : "note",
"display" : "Note",
"designation" : [
{
"language" : "en-US",
"value" : "Note"
},
{
"language" : "da",
"value" : "Note"
}
]
}
]
}
]
}
}