2019-12-04 23:54:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* @module
|
|
|
|
|
* Fonctions de requêtage des données d’exemple.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {termTypes} from '../model.js';
|
|
|
|
|
import * as data from './data.js';
|
2019-11-27 05:49:19 +00:00
|
|
|
|
|
2019-11-27 08:33:03 +00:00
|
|
|
|
/**
|
2019-12-04 04:20:06 +00:00
|
|
|
|
* Recherche l’ensemble des maladies liées par une relation « a pour symptôme »
|
2019-12-03 22:00:21 +00:00
|
|
|
|
* avec un ensemble de termes donné.
|
2019-11-27 08:33:03 +00:00
|
|
|
|
*
|
2019-12-03 22:00:21 +00:00
|
|
|
|
* @param query Ensemble de termes attendus.
|
|
|
|
|
* @return Liste des maladies correspondantes.
|
2019-11-27 08:33:03 +00:00
|
|
|
|
*/
|
2019-12-03 22:00:21 +00:00
|
|
|
|
export const diseasesBySymptoms = async query =>
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-04 04:20:06 +00:00
|
|
|
|
let allMatches = [];
|
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
if (!query.length)
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-04 04:20:06 +00:00
|
|
|
|
// Si aucun terme dans la requête, tout correspond
|
2019-12-04 23:54:44 +00:00
|
|
|
|
allMatches = Object.values(data.terms).map(({id}) => id);
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
2019-12-04 04:20:06 +00:00
|
|
|
|
else
|
2019-12-03 22:00:21 +00:00
|
|
|
|
{
|
2019-12-04 04:20:06 +00:00
|
|
|
|
// Marqueurs indiquant pour chaque terme l’ensemble des éléments de la
|
|
|
|
|
// requête qu’il a pour symptôme au travers d’une relation directe ou
|
|
|
|
|
// transitive
|
|
|
|
|
const matchingSymptoms = {};
|
|
|
|
|
|
|
|
|
|
// Réalise un parcours en profondeur du graphe en partant de chaque terme
|
|
|
|
|
// de la requête pour marquer les résultats
|
|
|
|
|
for (let queryTerm of query)
|
2019-12-03 22:00:21 +00:00
|
|
|
|
{
|
2019-12-04 04:20:06 +00:00
|
|
|
|
const stack = [queryTerm.id];
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-04 04:20:06 +00:00
|
|
|
|
while (stack.length)
|
|
|
|
|
{
|
|
|
|
|
const current = stack.pop();
|
2019-12-04 23:54:44 +00:00
|
|
|
|
const neighbors = data.symptomOf.filter(
|
2019-12-04 04:20:06 +00:00
|
|
|
|
([from]) => from === current
|
|
|
|
|
).map(
|
|
|
|
|
([, to]) => to
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (let neighbor of neighbors)
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-04 04:20:06 +00:00
|
|
|
|
if (!(neighbor in matchingSymptoms))
|
|
|
|
|
{
|
|
|
|
|
matchingSymptoms[neighbor] = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!matchingSymptoms[neighbor].includes(queryTerm.id))
|
|
|
|
|
{
|
|
|
|
|
matchingSymptoms[neighbor].push(queryTerm.id);
|
|
|
|
|
stack.push(neighbor);
|
|
|
|
|
}
|
2019-11-27 08:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
2019-12-04 04:20:06 +00:00
|
|
|
|
|
|
|
|
|
// Seuls les termes ayant été visités par tous les éléments de la
|
|
|
|
|
// requête sont des résultats valides
|
|
|
|
|
allMatches = Object.entries(matchingSymptoms).filter(
|
|
|
|
|
([, matches]) => matches.length === query.length
|
|
|
|
|
).map(
|
|
|
|
|
([id]) => id
|
|
|
|
|
);
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 04:20:06 +00:00
|
|
|
|
// On ne garde que les maladies
|
|
|
|
|
return allMatches.map(
|
2019-12-04 23:54:44 +00:00
|
|
|
|
id => data.terms[id]
|
2019-12-04 04:20:06 +00:00
|
|
|
|
).filter(
|
2019-12-04 23:54:44 +00:00
|
|
|
|
term => term.types.includes(termTypes.disease)
|
2019-12-03 22:00:21 +00:00
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
2019-12-04 04:20:06 +00:00
|
|
|
|
* Récupère tous les termes liés à un ensemble de termes par une relation « a
|
|
|
|
|
* pour symptôme », directe ou transitive.
|
2019-12-03 22:00:21 +00:00
|
|
|
|
*
|
|
|
|
|
* @param terms Ensemble de termes initiaux.
|
|
|
|
|
* @return Termes de `terms` ainsi que leurs voisins par la relation symptôme.
|
|
|
|
|
*/
|
|
|
|
|
export const exploreSymptoms = async terms =>
|
|
|
|
|
{
|
|
|
|
|
// Voisins des termes de la requête
|
|
|
|
|
const selected = terms.map(({id}) => id);
|
|
|
|
|
|
|
|
|
|
// Fait un parcours en profondeur issu de chaque résultat pour obtenir
|
2019-12-04 04:20:06 +00:00
|
|
|
|
// tous les voisins directs ou transitifs par la relation « a pour
|
|
|
|
|
// symptôme »
|
2019-12-03 22:00:21 +00:00
|
|
|
|
const stack = [...selected];
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
while (stack.length)
|
|
|
|
|
{
|
|
|
|
|
const current = stack.pop();
|
2019-12-04 23:54:44 +00:00
|
|
|
|
const neighbors = data.hasSymptom.filter(
|
2019-12-03 22:00:21 +00:00
|
|
|
|
([from]) => from === current
|
|
|
|
|
).map(
|
|
|
|
|
([, to]) => to
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (let neighbor of neighbors)
|
|
|
|
|
{
|
|
|
|
|
if (!selected.includes(neighbor))
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
selected.push(neighbor);
|
|
|
|
|
stack.push(neighbor);
|
2019-11-27 08:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
2019-11-27 05:49:19 +00:00
|
|
|
|
|
2019-12-04 23:54:44 +00:00
|
|
|
|
return selected.map(id => data.terms[id]);
|
2019-12-03 22:00:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calcule le sous-graphe issu d’un ensemble de termes.
|
|
|
|
|
*
|
|
|
|
|
* @param terms Ensemble de termes à mettre dans le sous-graphe.
|
|
|
|
|
* @return Objet contenant les nœuds et les arêtes du graphe.
|
|
|
|
|
*/
|
|
|
|
|
export const symptomsSubgraph = async terms =>
|
|
|
|
|
{
|
|
|
|
|
const termsIds = terms.map(({id}) => id);
|
|
|
|
|
|
|
|
|
|
// Construction du graphe constitué des éléments sélectionnés et des
|
|
|
|
|
// arêtes qui les lient
|
|
|
|
|
const nodes = {};
|
|
|
|
|
const edges = [];
|
|
|
|
|
|
|
|
|
|
for (let term of terms)
|
|
|
|
|
{
|
|
|
|
|
nodes[term.id] = term;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sélection des arêtes liant les nœuds sélectionnés
|
2019-12-04 23:54:44 +00:00
|
|
|
|
for (let [from, to] of data.hasSymptom)
|
2019-12-03 22:00:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (
|
|
|
|
|
termsIds.includes(from)
|
|
|
|
|
&& termsIds.includes(to)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
edges.push([from, to]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {nodes, edges};
|
|
|
|
|
};
|