-
Notifications
You must be signed in to change notification settings - Fork 0
/
customModule.js
167 lines (151 loc) · 6.35 KB
/
customModule.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
const ParsingClient = require('sparql-http-client/ParsingClient');
const jaro = require("wink-jaro-distance");
const fs = require("fs");
class CustomModule {
constructor() {
//Retrieving the configuration file
this.configuration = JSON.parse(fs.readFileSync('./conf.json').toString());
this.endpoint = this.configuration.endpoint;
this.entities = {};
if("entity" in this.configuration)
this.entities = this.configuration["entity"];
this.symptoms = {};
if("symptoms" in this.entities)
this.symptoms = this.entities["symptoms"];
this.properties = {};
if("property" in this.configuration)
this.properties = this.configuration["property"];
}
//Returns all the symptoms in the configuration file
getSymptoms() {
return this.symptoms;
}
getSymptomsClass() {
return "symptom class" in this.entities
}
getDiseaseClass() {
return "disease class" in this.entities;
}
//Return the URI of the Entity named entityName
getEntityURI(entityName) {
let result = null;
if(entityName in this.entities)
result = this.entities[entityName].url;
if(entityName in this.symptoms)
result = this.symptoms[entityName].url;
return result;
}
//Return the URI of the Property named propertyName
getPropertyURI(propertyName) {
return propertyName in this.properties ? this.properties[propertyName].url : null;
}
//Submits the SPARQL query to the endpoint defined in the configuration file
async submitQuery(query) {
const client = new ParsingClient({
endpointUrl: 'https://query.wikidata.org/sparql',
headers: {
'user-agent': 'MedBot/1.0'
}
});
const bindings = await client.query.select(query);
let result = [];
bindings.forEach(row =>
Object.entries(row).forEach(([key, value]) => result.push(value.value) )
)
return result;
}
// Creates the query that gets the disease that matches the symptomCodes
async getDiseases(recognizedSymptoms, rejectedSymptoms) {
//Retrieving the properties and entities URIs
//Retrieving the symptoms URIs
let symptomsURIs = "";
for (let r in recognizedSymptoms) {
let URI = this.getEntityURI(recognizedSymptoms[r]);
symptomsURIs += symptomsURIs === "" ? "<" + URI + ">" : " , <" + URI + ">";
}
let rejectedURIs = [];
for (let r in rejectedSymptoms) {
let URI = this.getEntityURI(rejectedSymptoms[r]);
rejectedURIs.push(`<${URI}>`);
}
let symptomProperty = this.getPropertyURI("symptom or sign");
if(!symptomProperty)
return [];
//Query construction
let query = `SELECT DISTINCT ?diseaseLabel (COUNT(?symptom) AS ?symptomsCount) WHERE {
?disease <${symptomProperty}> ${symptomsURIs} ;
rdfs:label ?diseaseLabel ;
<${symptomProperty}> ?symptom` ;
let instanceOfProperty = this.getPropertyURI("instance of");
if(!instanceOfProperty) {
if (this.getDiseaseClass()) {
let diseaseClass = this.getEntityURI("disease class");
if (!diseaseClass)
return [];
query += ` ; <${instanceOfProperty}> <${diseaseClass}>`;
}
if (this.getSymptomsClass()) {
let symptomClass = this.getEntityURI("symptom class");
if (!symptomClass)
return [];
query += ` . ?symptom <${instanceOfProperty}> <${symptomClass}>`;
}
}
query += ` . FILTER(LANGMATCHES(LANG(?diseaseLabel), 'en'))`;
for(let r in rejectedURIs) {
query += ` . FILTER NOT EXISTS {?disease <${symptomProperty}> ${rejectedURIs[r]}}`
}
query += `} GROUP BY (?diseaseLabel)
ORDER BY(?symptomsCount)`;
let response = await this.submitQuery(query);
let diseases = [];
for(let i = 0; i < response.length; i = i + 2) {
diseases.push(response[i]);
}
let filteredDiseases = [];
for(let d in diseases)
if (!filteredDiseases.includes(diseases[d]) && !filteredDiseases.includes(diseases[d].toLowerCase()))
filteredDiseases.push(diseases[d]);
return filteredDiseases;
}
/* Creates the query that gets the symptoms of a disease labeled diseaseName,
then return it minus the ones in symptomList */
async getMissingSymptoms(diseaseName, symptomList) {
//Retrieving the properties and entities URIs
let symptomProperty = this.getPropertyURI("symptom or sign");
if(!symptomProperty)
return [];
//Query construction
let query = `SELECT DISTINCT ?symptomsLabel WHERE {
?disease rdfs:label "${diseaseName}"@en ;
<${symptomProperty}> ?symptoms . `;
if(this.getSymptomsClass()){
let instanceOfProperty = this.getPropertyURI("instance of");
let symptomClass = this.getEntityURI("symptom class");
if(!instanceOfProperty || !symptomClass)
return [];
query += `?symptoms <${instanceOfProperty}> <${symptomClass}> ;
rdfs:label ?symptomsLabel . `;
}
query += `FILTER(LANGMATCHES(LANG(?symptomsLabel), 'en'))`;
for(let s in symptomList) {
`FILTER NOT EXISTS { ?symptoms rdfs:label '${symptomList[s]}'@en} }`;
}
query += `}`;
let response = await this.submitQuery(query);
//Filtering the results removing the input symptoms and the duplicates
let result = [];
validation: for(let r in response) {
let symptom = response[r].toLowerCase();
for (let s in symptomList)
if (jaro(symptomList[s], symptom).similarity > 0.8)
continue validation;
for (let rs in result)
if (jaro(result[rs], symptom).similarity > 0.8)
continue validation;
result.push(symptom);
}
return result;
}
}
module.exports = CustomModule