Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Mapping Tree #193

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .github/integration-test/synthea-test-mapping/mapping.zip
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.mvn
.idea/
cache
target
/ontology/mapping.zip
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<properties>
<java.version>17</java.version>
<testcontainers.version>1.19.8</testcontainers.version>
<ontology.version>2.2.0</ontology.version>
<ontology.version>3.0.0-test.1</ontology.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -206,9 +206,10 @@
<goal>wget</goal>
</goals>
<configuration>
<url>https://github.com/medizininformatik-initiative/fhir-ontology-generator/raw/v${ontology.version}/example/mii_core_data_set/ontology/mapping.zip</url>
<url>https://github.com/medizininformatik-initiative/fhir-ontology-generator/raw/v${ontology.version}/example/fdpg-ontology/mapping.zip</url>
<outputFileName>mapping.zip</outputFileName>
<outputDirectory>ontology/</outputDirectory>
<skipCache>true</skipCache>
</configuration>
</execution>
</executions>
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/de/medizininformatikinitiative/flare/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import de.medizininformatikinitiative.flare.model.mapping.Mapping;
import de.medizininformatikinitiative.flare.model.mapping.MappingContext;
import de.medizininformatikinitiative.flare.model.mapping.TermCodeNode;
import de.medizininformatikinitiative.flare.model.mapping.MappingTreeBase;
import de.medizininformatikinitiative.flare.model.mapping.MappingTreeModuleRoot;
import de.medizininformatikinitiative.flare.model.sq.ContextualTermCode;

import java.io.BufferedInputStream;
Expand Down Expand Up @@ -79,11 +80,11 @@ static double durationSecondsSince(long startNanoTime) {
static MappingContext flareMappingContext(Clock clock) throws Exception {
var mapper = new ObjectMapper();
String ontologyZipFile = "ontology/mapping.zip";
String mappingFile = "ontology/mapping/mapping_fhir.json";
String conceptTreeFile = "ontology/mapping/mapping_tree.json";
String mappingFile = "mapping/fhir/mapping_fhir.json";
String conceptTreeFile = "mapping/mapping_tree.json";

Map<ContextualTermCode, Mapping> mappings = null;
TermCodeNode conceptTree = null;
MappingTreeBase conceptTree = null;

try (FileInputStream fis = new FileInputStream(ontologyZipFile);
BufferedInputStream bis = new BufferedInputStream(fis);
Expand All @@ -94,8 +95,8 @@ static MappingContext flareMappingContext(Clock clock) throws Exception {
mappings = Arrays.stream(mapper.readValue(readZipEntryContent(zis), Mapping[].class))
.collect(Collectors.toMap(Mapping::key, identity()));
} else if (ze.getName().equals(conceptTreeFile)) {
String treeString = readZipEntryContent(zis);
conceptTree = mapper.readValue(treeString, TermCodeNode.class);
conceptTree = new MappingTreeBase(
Arrays.stream(mapper.readValue(readZipEntryContent(zis), MappingTreeModuleRoot[].class)).toList());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
public class MappingContext {

private final Map<ContextualTermCode, Mapping> mappings;
private final TermCodeNode conceptTree;
private final MappingTreeBase conceptTree;
private final Clock clock;

private MappingContext(Map<ContextualTermCode, Mapping> mappings, TermCodeNode conceptTree, Clock clock) {
private MappingContext(Map<ContextualTermCode, Mapping> mappings, MappingTreeBase conceptTree, Clock clock) {
this.mappings = Map.copyOf(mappings);
this.conceptTree = requireNonNull(conceptTree);
this.clock = requireNonNull(clock);
Expand All @@ -37,7 +37,7 @@ private MappingContext(Map<ContextualTermCode, Mapping> mappings, TermCodeNode c
* @param conceptTree a tree of concepts to expand (can be null)
* @return the mapping context
*/
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, TermCodeNode conceptTree) {
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, MappingTreeBase conceptTree) {
return new MappingContext(mappings, conceptTree, Clock.systemDefaultZone());
}

Expand All @@ -49,7 +49,7 @@ public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, TermC
* @param clock a clock that is used for time-related calculations
* @return the mapping context
*/
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, TermCodeNode conceptTree, Clock clock) {
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, MappingTreeBase conceptTree, Clock clock) {
return new MappingContext(mappings, conceptTree, clock);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package de.medizininformatikinitiative.flare.model.mapping;

import de.medizininformatikinitiative.flare.model.sq.ContextualTermCode;

import java.util.List;
import java.util.stream.Stream;

public record MappingTreeBase(List<MappingTreeModuleRoot> moduleRoots) {

public Stream<ContextualTermCode> expand(ContextualTermCode termCode) {
var key = termCode.termCode().code();

return moduleRoots.stream().flatMap(moduleRoot ->
isModuleMatching(termCode, moduleRoot) ? moduleRoot.expand(key) : Stream.empty());
}

private boolean isModuleMatching(ContextualTermCode termCode, MappingTreeModuleRoot moduleRoot) {
return termCode.context().equals(moduleRoot.context()) &&
moduleRoot.system().equals(termCode.termCode().system()) &&
moduleRoot.entries().containsKey(termCode.termCode().code());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.medizininformatikinitiative.flare.model.mapping;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
record MappingTreeModuleEntry(String key, List<String> children) {
@JsonCreator
static MappingTreeModuleEntry fromJson(@JsonProperty("key") String key,
@JsonProperty("children") List<String> children) {
return new MappingTreeModuleEntry(key, children);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.medizininformatikinitiative.flare.model.mapping;


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.medizininformatikinitiative.flare.model.sq.ContextualTermCode;
import de.medizininformatikinitiative.flare.model.sq.TermCode;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.function.Function.identity;

@JsonIgnoreProperties(ignoreUnknown = true)
public record MappingTreeModuleRoot(TermCode context, String system, Map<String, MappingTreeModuleEntry> entries) {
@JsonCreator
static MappingTreeModuleRoot fromJson(@JsonProperty("context") TermCode context,
@JsonProperty("system") String system,
@JsonProperty("entries") List<MappingTreeModuleEntry> entries) {
return new MappingTreeModuleRoot(
context,
system,
entries.stream().collect(Collectors.toMap(MappingTreeModuleEntry::key, identity())));
}

public Stream<ContextualTermCode> expand(String key) {
var newTermCode = new ContextualTermCode(context, new TermCode(system, key, ""));

return Stream.concat(Stream.of(newTermCode), entries.get(key).children().stream().flatMap(this::expand));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Set;

import static de.medizininformatikinitiative.flare.model.translate.Operator.Name.UNION;
import static java.util.Objects.requireNonNull;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import de.medizininformatikinitiative.flare.model.sq.TermCode;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;

import static de.medizininformatikinitiative.flare.Assertions.assertThat;
Expand All @@ -13,36 +14,45 @@
class MappingContextTest {

static final TermCode CONTEXT = TermCode.of("context", "context", "context");
static final String SYSTEM = "sys";
static final ContextualTermCode ROOT = ContextualTermCode.of(CONTEXT, TermCode.of("root", "root", "root"));
static final ContextualTermCode C1 = ContextualTermCode.of(CONTEXT, TermCode.of("foo", "c1", "c1"));
static final ContextualTermCode C11 = ContextualTermCode.of(CONTEXT, TermCode.of("foo", "c11", "c11"));
static final ContextualTermCode C12 = ContextualTermCode.of(CONTEXT, TermCode.of("foo", "c12", "c12"));
static final String C1 = "c1";
static final String C2 = "c2";

private ContextualTermCode contextualTermCodeOf(String code) {
return new ContextualTermCode(MappingContextTest.CONTEXT, new TermCode(MappingContextTest.SYSTEM, code, "display"));
}

@Test
void expandConcept_ConceptNotExpandable() {
var context = MappingContext.of(Map.of(), TermCodeNode.createNormal(ROOT));
var context = MappingContext.of(Map.of(), new MappingTreeBase(List.of(new MappingTreeModuleRoot(CONTEXT, SYSTEM, Map.of()))));

var result = context.expandConcept(ContextualConcept.of(C1));
var result = context.expandConcept(ContextualConcept.of(contextualTermCodeOf(C1)));

assertThat(result).isLeftInstanceOf(ContextualConceptNotExpandableException.class);
}

@Test
void expandConcept_OneConcept() {
var context = MappingContext.of(Map.of(), TermCodeNode.createNormal(ROOT, TermCodeNode.createNormal(C1)));
var context = MappingContext.of(Map.of(), new MappingTreeBase(List.of(
new MappingTreeModuleRoot(CONTEXT, SYSTEM, Map.of(C1, new MappingTreeModuleEntry(C1, List.of()))))));

var result = context.expandConcept(ContextualConcept.of(C1));
var result = context.expandConcept(ContextualConcept.of(contextualTermCodeOf(C1)));

assertThat(result).isRightSatisfying(r -> assertThat(r).containsExactly(C1));
assertThat(result).isRightSatisfying(r -> assertThat(r).containsExactly(contextualTermCodeOf(C1)));
}

@Test
void expandConcept_TwoConcepts() {
var context = MappingContext.of(Map.of(), TermCodeNode.createAbstract(C1, TermCodeNode.createNormal(C11),
TermCodeNode.createNormal(C12)));
var context = MappingContext.of(Map.of(), new MappingTreeBase(List.of(
new MappingTreeModuleRoot(CONTEXT, SYSTEM, Map.of(C1, new MappingTreeModuleEntry(C1, List.of(C2)),
C2, new MappingTreeModuleEntry(C2, List.of()))))));

var result = context.expandConcept(ContextualConcept.of(C1));
var result = context.expandConcept(ContextualConcept.of(contextualTermCodeOf(C1)));

assertThat(result).isRightSatisfying(r -> assertThat(r).containsExactly(C11, C12));
assertThat(result).isRightSatisfying(r -> {
assertThat(r.get(0)).isEqualTo(contextualTermCodeOf(C1));
assertThat(r.get(1)).isEqualTo(contextualTermCodeOf(C2));
});
}
}
Loading
Loading