Commit 72f224e3 authored by Georg Fette's avatar Georg Fette
Browse files

- reduced the model structure of openEHR queries in cypher

parent f1f098a9
......@@ -33,6 +33,21 @@ public class Concept {
public String parent;
@Override
public boolean equals(Object anObj) {
if (anObj instanceof Concept) {
Concept aC2 = (Concept) anObj;
return name.equals(aC2.name);
} else {
return false;
}
}
@Override
public int hashCode() {
return name.hashCode();
}
// for serialization
private Concept() {
}
......
......@@ -46,9 +46,9 @@ public class Archetype2ModelConverter {
this.model = aModel;
Collection<File> files = FileUtilsUniWue.listFiles(rootArchDir, true);
for (File aFile : files) {
// if (!aFile.getName().matches("openEHR-EHR-CLUSTER.laboratory_test_analyte.v1.adl")) {
// continue;
// }
// if (!aFile.getName().matches("openEHR-EHR-INSTRUCTION.care_plan_request.v0.adl")) {
// continue;
// }
System.out.println(aFile.getName());
String fileString = FileUtilsUniWue.file2String(aFile);
convertArchetype2StructureDef(rootArchDir, fileString);
......@@ -116,6 +116,10 @@ public class Archetype2ModelConverter {
Set<String> types = new HashSet<String>();
for (CObject aChildObj : anAttr.getChildren()) {
String childRmTypeName = getRmTypeName(aChildObj);
if (childRmTypeName.equals("String")) {
// somehow all primitive types are lowercased, but only String is uppercase
childRmTypeName = "string";
}
types.add(childRmTypeName);
}
return types;
......@@ -155,6 +159,10 @@ public class Archetype2ModelConverter {
private void processAttributeOfComplexObject(Concept concept, CAttribute anAttr)
throws ParseException, Exception {
for (CObject aChildObj : anAttr.getChildren()) {
if (aChildObj instanceof ArchetypeSlot) {
// lets skip the archetypes slots at the beginning. Let's see when we will neede them
continue;
}
String rmAttributeName = anAttr.getRmAttributeName();
boolean isArrayFlag = isArray(aChildObj);
String nodeID = aChildObj.getNodeId();
......@@ -176,25 +184,6 @@ public class Archetype2ModelConverter {
processObject(aChildObj);
}
}
// Set<String> primitiveTypeFields = getPrimitiveTypeFields(anAttr);
// if (primitiveTypeFields.size() > 0) {
// for (CObject aChildObj : anAttr.getChildren()) {
// String rmAttributeName = anAttr.getRmAttributeName();
// boolean isArrayFlag = isArray(aChildObj);
// ConceptField newValueElem = concept.addField(rmAttributeName,
// new ArrayList<String>(primitiveTypeFields), isArrayFlag);
// }
// } else {
// for (CObject aChildObj : anAttr.getChildren()) {
// String rmAttributeName = anAttr.getRmAttributeName();
// boolean isArrayFlag = isArray(aChildObj);
// ConceptField newValueElem = concept.addField(rmAttributeName,
// new ArrayList<String>(primitiveTypeFields), isArrayFlag);
// processObject(aChildObj);
// String cleanedOntName = getCleanedOntName(aChildObj);
// // concept.name = cleanedOntName;
// }
// }
}
/*
......
......@@ -9,6 +9,7 @@ import ca.uhn.fhir.context.FhirContext;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.model.Concept;
import de.uniwue.model.ConceptField;
import de.uniwue.model.Model;
import de.uniwue.model.FHIR.StructureDef2ModelConverter;
......@@ -41,8 +42,8 @@ public class OpenEHRModelInitializer extends Model {
STRING = getConcept("string");
}
public static Model loadModel() throws IOException {
String modelJSONFilePath = "classpath:models/openEHR/openEHR_model.json";
public static Model loadModel(String filename) throws IOException {
String modelJSONFilePath = "classpath:models/openEHR/" + filename;
String modelJSONString = ResourceUtil.loadFileAsString(modelJSONFilePath);
Model model = fromJSON(modelJSONString, OpenEHRModelInitializer.class);
return model;
......@@ -53,30 +54,53 @@ public class OpenEHRModelInitializer extends Model {
initializer.createModelFileFromStructureDefs();
}
private void transformObjectIDToStringFields(Model aModel) {
Concept objectIDConcept = aModel.getConcept("OBJECT_ID");
Concept dataValueConcept = aModel.getConcept("DATA_VALUE");
Concept dvOrderedConcept = aModel.getConcept("DV_ORDERED");
Concept dvCodedTextConcept = aModel.getConcept("DV_CODED_TEXT");
// ArrayList<String> x = new ArrayList<String>();
// for (Concept aConc : aModel.getConcepts()) {
// if (aConc.name.toLowerCase().contains("activity-running")) {
// x.add(aConc.name);
// }
// }
for (Concept aConc : aModel.getConcepts()) {
for (ConceptField aField : aConc.getFields()) {
for (String aType : aField.possibleTypes.toArray(new String[0])) {
Concept aFieldConcept = aModel.getConcept(aType);
if (aFieldConcept.inheritsFrom(objectIDConcept)
|| (aFieldConcept.inheritsFrom(dataValueConcept) && !aFieldConcept.inheritsFrom(dvOrderedConcept)
&& !aFieldConcept.inheritsFrom(dvCodedTextConcept))) {
aField.possibleTypes.remove(aType);
aField.possibleTypes.add("string");
}
}
}
}
}
public void createModelFileFromStructureDefs() throws Exception {
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter strDefConverter = new StructureDef2ModelConverter(ctx);
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
strDefConverter.convertStructureDefsBundle(profileTypesPath);
Concept rootConcept = null;
for (Concept aConc : strDefConverter.model.getConcepts()) {
if (!Character.isLowerCase(aConc.name.charAt(0))) {
strDefConverter.model.removeConcept(aConc);
}
if (aConc.name.equals("Element")) {
rootConcept = aConc;
}
}
Concept rootConcept = new Concept("Element", strDefConverter.model);
new Concept(rootConcept, "DomainResource");
new Concept(rootConcept, "base64binary");
new Concept(rootConcept, "string");
new Concept(rootConcept, "boolean");
new Concept(rootConcept, "integer");
new Concept(rootConcept, "decimal");
new Concept(rootConcept, "dateTime");
String structureDefsDir = "classpath:models/openEHR/StructureDefs_openEHR_RM";
Resource resource = ResourceUtil.getResource(structureDefsDir);
strDefConverter.convertStructureDefsDir(resource.getFile());
Archetype2ModelConverter archTypeConverster = new Archetype2ModelConverter();
String archetypeDefsDir = "classpath:models/openEHR/Archetypes";
Resource archDefsDirResource = ResourceUtil.getResource(archetypeDefsDir);
archTypeConverster.convertArchetypes2StructureDefs(archDefsDirResource.getFile(),
strDefConverter.model);
archTypeConverster.convertArchetypes2StructureDefs(archDefsDirResource.getFile(), strDefConverter.model);
transformObjectIDToStringFields(strDefConverter.model);
String json = strDefConverter.model.toJSON();
FileUtilsUniWue.saveString2File(json, new File("D:\\tmp\\openEHR_model.json"));
FileUtilsUniWue.saveString2File(json, new File("C:\\tmp\\openEHR_model.json"));
}
}
......@@ -75,6 +75,20 @@ public class OperatorType {
IsComparatorOp
}
@Override
public boolean equals(Object aType) {
if (aType instanceof OperatorType) {
return name.equals(((OperatorType) aType).name);
} else {
return false;
}
}
@Override
public int hashCode() {
return name.hashCode();
}
protected OperatorType(String name, Concept[] parameterTypes, Concept returnType,
InterfaceFlags[] interfaceFlags, Integer minParams, Integer maxParams) {
this.name = name;
......
......@@ -211,9 +211,10 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
private String writePrimitive(Primitive prim) {
String result;
if (prim.dataType == getModel().STRING) {
// unfortunetely the two concept models can differ, but the concept should be the same
if (prim.dataType.equals(getModel().STRING)) {
result = "'" + prim.value + "'";
} else if (prim.dataType == getModel().DATETIME) {
} else if (prim.dataType.equals(getModel().DATETIME)) {
PrimitiveDateTime pdt = (PrimitiveDateTime) prim;
result = writeDateTime(pdt);
} else {
......
......@@ -46,7 +46,7 @@ public class Test_AQL_2_AQL {
}
private void initialize() throws IOException {
Model model = OpenEHRModelInitializer.loadModel();
Model model = OpenEHRModelInitializer.loadModel("openEHR_model.json");
langManager = new AQLLanguageManager(model);
}
......
......@@ -4,11 +4,12 @@ import java.io.IOException;
import org.junit.Test;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.models.OpenEHRModelInitializer;
import de.uniwue.query.cypher.CypherLanguageManager;
import de.uniwue.query.openEHR2.AQLLanguageManager;
public class Test_AQL_2_Cypher {
private AQLLanguageManager aqlLangManager;
......@@ -19,7 +20,7 @@ public class Test_AQL_2_Cypher {
public static void main(String[] args) throws IOException, QueryParseException {
Test_AQL_2_Cypher test = new Test_AQL_2_Cypher();
// test.debugTest();
// test.debugTest();
test.testAQL_2_Cypher();
}
......@@ -27,7 +28,7 @@ public class Test_AQL_2_Cypher {
initialize();
QueryManager queryManager = new QueryManager();
for (MultiQuery aMultiQuery : queryManager.queries) {
if (aMultiQuery.name.equals("query_AQL_2_Cypher_2Attrs_ReturnAttrs")) {
if (aMultiQuery.name.equals("query_AQL_2_Cypher_ehrID")) {
processQuery(aMultiQuery);
}
}
......@@ -48,11 +49,36 @@ public class Test_AQL_2_Cypher {
return queryManager;
}
private void replaceModel(QueryOperator query) {
for (QueryOperator anOp : query.getOpsRecursive()) {
anOp.setModel(cypherLangManager.graph_2_system_mapper.getModel());
}
}
private void replaceAcessToValuesOfIDsAndDataValues(QueryOperator query) {
Concept objectIDConcept = query.getModel().getConcept("OBJECT_ID");
Concept dataValueConcept = query.getModel().getConcept("DATA_VALUE");
Concept dvOrderedConcept = query.getModel().getConcept("DV_ORDERED");
Concept dvCodedTextConcept = query.getModel().getConcept("DV_CODED_TEXT");
for (QueryOperator anOp : query.getOpsRecursive()) {
Concept dataType = anOp.getDataType();
if (dataType.inheritsFrom(objectIDConcept) || (dataType.inheritsFrom(dataValueConcept)
&& !dataType.inheritsFrom(dvOrderedConcept) && !dataType.inheritsFrom(dvCodedTextConcept))) {
if ((anOp.parent.type == OperatorType.FIELD)
&& anOp.parent.getParameters().get(1).asPrimitive().value.equals("value")) {
anOp.parent.parent.replaceParameter(anOp.parent, anOp);
}
}
}
}
private void initialize() throws IOException {
// just to initialize the operators
Model model = OpenEHRModelInitializer.loadModel();
Model model = OpenEHRModelInitializer.loadModel("openEHR_model.json");
aqlLangManager = new AQLLanguageManager(model);
cypherLangManager = new CypherLanguageManager(model, true);
Model reducedModel = OpenEHRModelInitializer.loadModel("openEHR_model_reduced.json");
cypherLangManager = new CypherLanguageManager(reducedModel, true);
OperatorType.doTypeChecking = false;
}
......@@ -60,9 +86,10 @@ public class Test_AQL_2_Cypher {
System.out.println("Processing query '" + aMultiQuery + "'");
String originalQuery = aMultiQuery.system2QueryString.get(aqlLangManager.getSystem());
QueryOperator query = aqlLangManager.parse(originalQuery);
replaceAcessToValuesOfIDsAndDataValues(query);
replaceModel(query);
String graphString = query.toString();
String desiredGraphStringResult = aMultiQuery.system2QueryString
.get(QueryMapper.graphSystemName);
String desiredGraphStringResult = aMultiQuery.system2QueryString.get(QueryMapper.graphSystemName);
if (!graphString.equals(desiredGraphStringResult)) {
throw new RuntimeException("query strings not equal");
}
......@@ -77,8 +104,8 @@ public class Test_AQL_2_Cypher {
public void testAQL_2_Cypher() throws IOException, QueryParseException {
initialize();
QueryManager queryManager = getQueryManager("working_AQL_2_Cypher");
System.out.println("Translating queries from " + aqlLangManager.getSystem() + " to "
+ cypherLangManager.getSystem());
System.out
.println("Translating queries from " + aqlLangManager.getSystem() + " to " + cypherLangManager.getSystem());
for (MultiQuery aMultiQuery : queryManager.queries) {
processQuery(aMultiQuery);
}
......
......@@ -96,7 +96,7 @@ public class Test_AQL_2_i2b2_2_AQL {
}
private void initialize() throws IOException {
Model model = OpenEHRModelInitializer.loadModel();
Model model = OpenEHRModelInitializer.loadModel("openEHR_model.json");
i2b2LangManager = new I2B2LanguageManager(model);
aqlLangManager = new AQLLanguageManager(model);
graphTransformer_aql_2_i2b2 = new AQL_2_I2B2_QueryGraphTransformer(
......
......@@ -70,15 +70,15 @@ QUERY(
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:CLUSTER), (A)-[*]->(C:CLUSTER), (B)-[:items]->(D:ELEMENT), (B)-[:items]->(E:ELEMENT), (E)-[:value]->(F:DATA_VALUE), (C)-[:items]->(G:ELEMENT), (C)-[:items]->(H:ELEMENT), (H)-[:value]->(I:DATA_VALUE)
(A:EHR), (A)-[*]->(B:CLUSTER), (A)-[*]->(C:CLUSTER), (B)-[:items]->(D:ELEMENT), (B)-[:items]->(E:ELEMENT), (C)-[:items]->(F:ELEMENT), (C)-[:items]->(G:ELEMENT)
WHERE
D.value = 'Natrium_g_dl' AND
G.value = 'H_moglobin_g_dl' AND
F.value = 'H_moglobin_g_dl' AND
D.archetype_node_id = 'at0024' AND
G.archetype_node_id = 'at0024' AND
F.archetype_node_id = 'at0024' AND
B.archetype_node_id = 'openEHR-EHR-CLUSTER.laboratory_test_analyte.v1' AND
C.archetype_node_id = 'openEHR-EHR-CLUSTER.laboratory_test_analyte.v1' AND
E.archetype_node_id = 'at0001' AND
H.archetype_node_id = 'at0001'
G.archetype_node_id = 'at0001'
RETURN
F as NA, I as HAE
\ No newline at end of file
E.value as NA, G.value as HAE
\ No newline at end of file
......@@ -56,13 +56,13 @@ QUERY(
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:CLUSTER), (A)-[*]->(C:CLUSTER), (A)-[:ehr_id]->(D:HIER_OBJECT_ID), (B)-[:items]->(E:ELEMENT), (C)-[:items]->(F:ELEMENT)
(A:EHR), (A)-[*]->(B:CLUSTER), (A)-[*]->(C:CLUSTER), (B)-[:items]->(D:ELEMENT), (C)-[:items]->(E:ELEMENT)
WHERE
E.value = 'Natrium_g_dl' AND
F.value = 'H_moglobin_g_dl' AND
D.value = 'Natrium_g_dl' AND
E.value = 'H_moglobin_g_dl' AND
D.archetype_node_id = 'at0024' AND
E.archetype_node_id = 'at0024' AND
F.archetype_node_id = 'at0024' AND
B.archetype_node_id = 'openEHR-EHR-CLUSTER.laboratory_test_analyte.v1' AND
C.archetype_node_id = 'openEHR-EHR-CLUSTER.laboratory_test_analyte.v1'
RETURN
D as e_ehr_id
A.ehr_id as e_ehr_id
......@@ -37,13 +37,10 @@ QUERY(
EQUALS(
FIELD(
FIELD(
FIELD(
ALIAS_REF('a'),
'archetype_details'
),
'template_id'
ALIAS_REF('a'),
'archetype_details'
),
'value'
'template_id'
),
'template.v1'
)
......@@ -55,10 +52,10 @@ QUERY(
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:COMPOSITION), (B)-[:content]->(C:EVALUATION), (B)-[:archetype_details]->(D:ARCHETYPED), (C)-[:data]->(E:ITEM_TREE), (E)-[:items]->(F:ELEMENT), (D)-[:template_id]->(G:TEMPLATE_ID)
(A:EHR), (A)-[*]->(B:COMPOSITION), (B)-[:content]->(C:EVALUATION), (B)-[:archetype_details]->(D:ARCHETYPED), (C)-[:data]->(E:ITEM_TREE), (E)-[:items]->(F:ELEMENT)
WHERE
F.value = 'Männlich' AND
G.value = 'template.v1' AND
D.template_id = 'template.v1' AND
F.archetype_node_id = 'at0022' AND
E.archetype_node_id = 'at0002' AND
C.archetype_node_id = 'openEHR-EHR-EVALUATION.gender.v1' AND
......
*AQL
SELECT e/ehr_id
FROM EHR e
CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1]
*Graph
QUERY(
FILTER(
ITERATE('EHR') as e,
EXISTS(CONTAINS_TYPE(
ALIAS_REF('e'),
'COMPOSITION',
'openEHR-EHR-COMPOSITION.encounter.v1'
) as c)
),
RETURN(FIELD(
ALIAS_REF('e'),
'ehr_id'
) out 'e/ehr_id')
)
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:COMPOSITION)
WHERE
B.archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'
RETURN
A.ehr_id as e_ehr_id
\ No newline at end of file
......@@ -48,20 +48,17 @@ QUERY(
)
),
RETURN(FIELD(
FIELD(
ALIAS_REF('e'),
'ehr_id'
),
'value'
) out 'e/ehr_id/value')
ALIAS_REF('e'),
'ehr_id'
))
)
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:COMPOSITION), (A)-[:ehr_status]->(C:EHR_STATUS), (A)-[:ehr_id]->(D:HIER_OBJECT_ID), (B)-[*]->(E:ADMIN_ENTRY), (C)-[:subject]->(F:PARTY_SELF), (F)-[:external_ref]->(G:PARTY_REF)
(A:EHR), (A)-[*]->(B:COMPOSITION), (A)-[:ehr_status]->(C:EHR_STATUS), (B)-[*]->(D:ADMIN_ENTRY), (C)-[:subject]->(E:PARTY_SELF), (E)-[:external_ref]->(F:PARTY_REF)
WHERE
(NOT EXISTS ((B)-[:content]->(:ADMIN_ENTRY{archetype_node_id:'openEHR-EHR-ADMIN_ENTRY.discharge_summary.v0'})) OR NOT(G.namespace = 'CEC')) AND
(NOT EXISTS ((B)-[:content]->(:ADMIN_ENTRY{archetype_node_id:'openEHR-EHR-ADMIN_ENTRY.discharge_summary.v0'})) OR NOT(F.namespace = 'CEC')) AND
B.archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1' AND
E.archetype_node_id = 'openEHR-EHR-ADMIN_ENTRY.admission.v0'
D.archetype_node_id = 'openEHR-EHR-ADMIN_ENTRY.admission.v0'
RETURN
D.value as e_ehr_id_value
\ No newline at end of file
A.ehr_id
\ No newline at end of file
......@@ -41,20 +41,17 @@ QUERY(
)
),
RETURN(FIELD(
FIELD(
ALIAS_REF('e'),
'ehr_id'
),
'value'
) out 'e/ehr_id/value')
ALIAS_REF('e'),
'ehr_id'
))
)
*Cypher
MATCH
(A:EHR), (A)-[*]->(B:COMPOSITION), (A)-[:ehr_status]->(C:EHR_STATUS), (A)-[:ehr_id]->(D:HIER_OBJECT_ID), (B)-[*]->(E:ADMIN_ENTRY), (C)-[:subject]->(F:PARTY_SELF), (F)-[:external_ref]->(G:PARTY_REF)
(A:EHR), (A)-[*]->(B:COMPOSITION), (A)-[:ehr_status]->(C:EHR_STATUS), (B)-[*]->(D:ADMIN_ENTRY), (C)-[:subject]->(E:PARTY_SELF), (E)-[:external_ref]->(F:PARTY_REF)
WHERE
NOT(G.namespace = 'CEC') AND
NOT(F.namespace = 'CEC') AND
B.archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1' AND
E.archetype_node_id = 'openEHR-EHR-ADMIN_ENTRY.admission.v0'
D.archetype_node_id = 'openEHR-EHR-ADMIN_ENTRY.admission.v0'
RETURN
D.value as e_ehr_id_value
\ No newline at end of file
A.ehr_id
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment