maintenance.bdg_mathPbs
La contextualisation du dépôt de problèmes consiste à s'assurer que la base en graphe reflète les problèmes et leurs méta-données locales. Ces méta-données sont définies par l'auteur c'est à dire écrites dans le dépôt local. La modification d'une méta-donnée de ce type se fait dans le dépôt et non dans la base en graphe.
Modifié le 05/03/23 @author: remy
La fonction exec()
est appelée lors de l'instanciation de la classe Maquis
. Elle maintient cette cohérence en exécutant des requêtes cypher.
Quelles sont les méta-données définies par l'auteur d'un problème?
- une description
- des index
Un utilisateur autre que l'auteur doit pouvoir aussi associer des méta-données à un problème. La base en graphe reflète une méta-donnée de manière différente selon qu'elle est définie par l'auteur ou par un utilisateur.
La définition de méta-données par un utilisateur n'est pas encore implémentée.
Noeud et description associés à un problème.
L'auteur définit une description d'un problème en l'insérant entre des tags dans le fichier Latex de l'énoncé. Exemple avec le début de Eprob4.tex
%<dscrpt>Lancers de pièces.</dscrpt>
On dispose de deux pièces de monnaie discernables, désignées dans la suite
de l'exercice par \og pièce 1g~ et \og pièce 2g. On ...
Un noeud labélisé Document
est associé au problème prob4
. La description définie dans le code source est la propriété description
du noeud.
Les lignes suivantes présentent la requête cypher pour extraire ce noeud
MATCH (d:Document {typeDoc:"problème", titre:"prob4"}) RETURN d
et le noeud renvoyé
{
"identity": 7214,
"labels": [
"Document"
],
"properties": {
"date": "2018-05-06T21:36:11Z",
"titre": "prob4",
"urlSrcEnon": "https://github.com/nicolair/math-pbs/blob/master/Eprob4.tex",
"typeDoc": "problème",
"urlSrcCorr": "https://github.com/nicolair/math-pbs/blob/master/Cprob4.tex",
"description": "Lancers de pièces.",
"url": "https://maquisdoc-math.fra1.digitaloceanspaces.com/maths-pbs/Aprob4.pdf"
},
"elementId": "7214"
}
Une description insérée par un autre utisateur serait contenue dans la propriété texte
d'un noeud labélisé Commentaire
et relié au document prob4
par une arête labélisée DÉCRIT
. Ceci n'est pas encore implémenté.
Index associés à un problème.
Les index sont définis dans la source LateX par la commande \index
. Lors de la compilation, un fichier .idx
est créé qui permet localement d'associer l'index et le problème. Du côté de la base en graphe, un index est un noeud labelisé Concept
. Une arête labélisée INDEXE
issue du noeud associé au problème pointe vers le noeud associé à l'index.
Si on considère l'arête dans l'autre sens c'est à dire pointant de l'index vers le problème, un index apparait comme un mot-clé.
Un mot-clé défini par un utilisateur sera défini avec une arète dont la source est le noeud représentant le mot et dont la cible est le noeud représentant le problème. Cette fonctionnalité n'est pas encore implémentée et les labels du noeud représentant le mot et de l'arête ne sont pas fixés.
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4La contextualisation du dépôt de problèmes consiste à s'assurer que la base en graphe reflète les problèmes et leurs méta-données locales. Ces méta-données sont définies par l'auteur c'est à dire écrites dans le dépôt local. La modification d'une méta-donnée de ce type se fait dans le dépôt et non dans la base en graphe. 5 6Modifié le 05/03/23 @author: remy 7 8La fonction `exec()` est appelée lors de l'instanciation de la classe `Maquis`. Elle maintient cette cohérence en exécutant des requêtes cypher. 9 10Quelles sont les méta-données définies par l'auteur d'un problème? 11- une description 12- des index 13 14Un utilisateur autre que l'auteur doit pouvoir aussi associer des méta-données à un problème. La base en graphe reflète une méta-donnée de manière différente selon qu'elle est définie par l'auteur ou par un utilisateur. 15 16La définition de méta-données par un utilisateur n'est pas encore implémentée. 17 18#### Noeud et description associés à un problème. 19 20L'auteur définit une description d'un problème en l'insérant entre des tags dans le fichier Latex de l'énoncé. Exemple avec le début de `Eprob4.tex` 21 22 %<dscrpt>Lancers de pièces.</dscrpt> 23 On dispose de deux pièces de monnaie discernables, désignées dans la suite 24 de l'exercice par \og pièce 1\fg~ et \og pièce 2\fg. On ... 25 26Un noeud labélisé `Document` est associé au problème `prob4`. La description définie dans le code source est la propriété `description` du noeud. 27 28Les lignes suivantes présentent la requête cypher pour extraire ce noeud 29 30 MATCH (d:Document {typeDoc:"problème", titre:"prob4"}) RETURN d 31 32et le noeud renvoyé 33 34 { 35 "identity": 7214, 36 "labels": [ 37 "Document" 38 ], 39 "properties": { 40 "date": "2018-05-06T21:36:11Z", 41 "titre": "prob4", 42 "urlSrcEnon": "https://github.com/nicolair/math-pbs/blob/master/Eprob4.tex", 43 "typeDoc": "problème", 44 "urlSrcCorr": "https://github.com/nicolair/math-pbs/blob/master/Cprob4.tex", 45 "description": "Lancers de pièces.", 46 "url": "https://maquisdoc-math.fra1.digitaloceanspaces.com/maths-pbs/Aprob4.pdf" 47 }, 48 "elementId": "7214" 49 } 50 51Une description insérée par un autre utisateur serait contenue dans la propriété `texte` d'un noeud labélisé `Commentaire` et relié au document `prob4` par une arête labélisée `DÉCRIT`. Ceci n'est pas encore implémenté. 52 53#### Index associés à un problème. 54 55Les index sont définis dans la source LateX par la commande `\index`. Lors de la compilation, un fichier `.idx` est créé qui permet localement d'associer l'index et le problème. Du côté de la base en graphe, un index est un noeud labelisé `Concept`. Une arête labélisée `INDEXE` issue du noeud associé au problème pointe vers le noeud associé à l'index. 56 57Si on considère l'arête dans l'autre sens c'est à dire pointant de l'index vers le problème, un index apparait comme un mot-clé. 58Un mot-clé défini par un utilisateur sera défini avec une arète dont la source est le noeud représentant le mot et dont la cible est le noeud représentant le problème. Cette fonctionnalité n'est pas encore implémentée et les labels du noeud représentant le mot et de l'arête ne sont pas fixés. 59 60""" 61import neo4j 62 63def exec(self): 64 """ 65 Exécution des requêtes spécifques de maintenance de la base. 66 - récupération des descriptions dans la base 67 - supprimer dans la base les problèmes absents localement 68 - créer dans la base les problèmes locaux manquants 69 - si description locale et distante différentes, 70 - copier description locale sur distante 71 - afficher les indexations locales 72 73 #### Renvoie 74 75 log: str journal 76 77 """ 78 print("coucou de exec() dans bdg_mathPbs.py") 79 80 data = self.connect_data 81 URI = data['credentials']['URI'] 82 user = data['credentials']['user'] 83 password = data['credentials']['password'] 84 AUTH = (user, password) 85 86 loc_indexations = self.specific_results['indexations'] 87 loc_descriptions = self.specific_results['descriptions'] 88 89 param = {'label' : "Document", 90 'propsF' :"{typeDoc:'problème'}", 91 'propsR' : "n.titre, n.description"} 92 req = self.format_cypher_RETURN(param) 93 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 94 rem_descriptions = session.execute_read(self.do_cypher_tx, req) 95 96 loc_descriptions.sort(key=lambda descrpt: descrpt[0]) 97 rem_descriptions.sort(key=lambda descrpt: descrpt[0]) 98 99 # Nbs de problèmes 100 blabla = "Nbs de pbs. local: {nloc}, base: {nrem}" 101 blabla = blabla.format( 102 nloc=len(loc_descriptions), 103 nrem=len(rem_descriptions)) 104 print(blabla) 105 106 # Noeuds isolés (orphelins) 107 nomsR = [descrpR[0] for descrpR in rem_descriptions] 108 nomsL = [descrpL[0] for descrpL in loc_descriptions] 109 rem_orphs = [] 110 for nom in nomsR: 111 if nom not in nomsL: 112 rem_orphs.append(nom) 113 blabla = "\n Pbs distants sans source locale (à supprimer) : {}" 114 blabla = blabla.format(rem_orphs) 115 print(blabla) 116 for nom in rem_orphs: 117 param = {'label' : "Document"} 118 param['propsF'] = 'typeDoc:"problème", titre:"{titre}"' 119 param['propsF'] = param['propsF'].format(titre=nom) 120 param['propsF'] = '{' + param['propsF'] + '}' 121 req = self.format_cypher_DELETE(param) 122 print(req) 123 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 124 val = session.execute_write(self.do_cypher_tx, req) 125 print(val) 126 127 # Problèmes sans noeud associé 128 loc_orphs = [] 129 for nom in nomsL: 130 if nom not in nomsR: 131 loc_orphs.append(nom) 132 blabla = "\n Pbs locaux sans reflet distant (à écrire) : " 133 blabla = blabla.format(loc_orphs) 134 print(blabla) 135 136 # Descriptions 137 print("\n Descriptions différentes local/base, requête cypher") 138 n = min(len(loc_descriptions), len(rem_descriptions)) 139 blabla = "-------\n" 140 blabla += "LOCAL nom: {nomL} description: {descrpL} \n" 141 blabla += "REMOTE nom: {nomR} description: {descrpR}\n" 142 143 for i in range(n): 144 nomL = loc_descriptions[i][0] 145 descrpL = loc_descriptions[i][1] 146 nomR = rem_descriptions[i][0] 147 descrpR = rem_descriptions[i][1] 148 params = { 149 'nomL': nomL, 150 'descrpL': descrpL, 151 'nomR': nomR, 152 'descrpR': descrpR 153 } 154 155 if nomL == nomR and descrpL != descrpR: 156 print(blabla.format(**params)) 157 param['label'] = 'Document' 158 param['propsF'] = 'typeDoc:"problème", titre:"{titre}"' 159 param['propsF'] = param['propsF'].format(titre=nomR) 160 param['propsF'] = '{' + param['propsF'] + '}' 161 param["propsV"] = 'n.description = "{descrpL}"' 162 param["propsV"] = param["propsV"].format(descrpL=descrpL) 163 req = self.format_cypher_SET(param) 164 print(req) 165 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 166 val = session.execute_write(self.do_cypher_tx, req) 167 print(val) 168 169 # indexations 170 #print("\n Indexations locales") 171 indexe(self,loc_indexations) 172 173 174 log = "" 175 return log 176 177def indexe(self, loc_indexations): 178 ''' 179 Assure que des relations `INDEXE` sont associées aux indexations locales. 180 ''' 181 print("\n coucou de indexe()") 182 data = self.connect_data 183 URI = data['credentials']['URI'] 184 user = data['credentials']['user'] 185 password = data['credentials']['password'] 186 AUTH = (user, password) 187 188 # indexations dans le graphe 189 req = ''' MATCH (p:Document {typeDoc:"problème"}) -[:INDEXE]-> (c:Concept) 190 RETURN "A" + p.titre, c.litteral 191 ''' 192 #print(req) 193 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 194 rem_indexations = session.execute_write(self.do_cypher_tx, req) 195 196 print(rem_indexations) 197 print(loc_indexations) 198 199 # création des indexations manquantes dans le graphe 200 req = ''' MATCH (p:Document {{typeDoc:"problème", titre: "{0}"}}) 201 MERGE (c:Concept {{litteral:"{1}"}}) 202 CREATE (p)-[:INDEXE]->(c) 203 ''' 204 rem_index_orph = [] 205 for index in loc_indexations : 206 if index not in rem_indexations: 207 nom = index[0][1:] 208 concept = index[1] 209 req1 = req.format(nom, concept) 210 print(nom, concept, req1) 211 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 212 val = session.execute_write(self.do_cypher_tx, req1)
64def exec(self): 65 """ 66 Exécution des requêtes spécifques de maintenance de la base. 67 - récupération des descriptions dans la base 68 - supprimer dans la base les problèmes absents localement 69 - créer dans la base les problèmes locaux manquants 70 - si description locale et distante différentes, 71 - copier description locale sur distante 72 - afficher les indexations locales 73 74 #### Renvoie 75 76 log: str journal 77 78 """ 79 print("coucou de exec() dans bdg_mathPbs.py") 80 81 data = self.connect_data 82 URI = data['credentials']['URI'] 83 user = data['credentials']['user'] 84 password = data['credentials']['password'] 85 AUTH = (user, password) 86 87 loc_indexations = self.specific_results['indexations'] 88 loc_descriptions = self.specific_results['descriptions'] 89 90 param = {'label' : "Document", 91 'propsF' :"{typeDoc:'problème'}", 92 'propsR' : "n.titre, n.description"} 93 req = self.format_cypher_RETURN(param) 94 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 95 rem_descriptions = session.execute_read(self.do_cypher_tx, req) 96 97 loc_descriptions.sort(key=lambda descrpt: descrpt[0]) 98 rem_descriptions.sort(key=lambda descrpt: descrpt[0]) 99 100 # Nbs de problèmes 101 blabla = "Nbs de pbs. local: {nloc}, base: {nrem}" 102 blabla = blabla.format( 103 nloc=len(loc_descriptions), 104 nrem=len(rem_descriptions)) 105 print(blabla) 106 107 # Noeuds isolés (orphelins) 108 nomsR = [descrpR[0] for descrpR in rem_descriptions] 109 nomsL = [descrpL[0] for descrpL in loc_descriptions] 110 rem_orphs = [] 111 for nom in nomsR: 112 if nom not in nomsL: 113 rem_orphs.append(nom) 114 blabla = "\n Pbs distants sans source locale (à supprimer) : {}" 115 blabla = blabla.format(rem_orphs) 116 print(blabla) 117 for nom in rem_orphs: 118 param = {'label' : "Document"} 119 param['propsF'] = 'typeDoc:"problème", titre:"{titre}"' 120 param['propsF'] = param['propsF'].format(titre=nom) 121 param['propsF'] = '{' + param['propsF'] + '}' 122 req = self.format_cypher_DELETE(param) 123 print(req) 124 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 125 val = session.execute_write(self.do_cypher_tx, req) 126 print(val) 127 128 # Problèmes sans noeud associé 129 loc_orphs = [] 130 for nom in nomsL: 131 if nom not in nomsR: 132 loc_orphs.append(nom) 133 blabla = "\n Pbs locaux sans reflet distant (à écrire) : " 134 blabla = blabla.format(loc_orphs) 135 print(blabla) 136 137 # Descriptions 138 print("\n Descriptions différentes local/base, requête cypher") 139 n = min(len(loc_descriptions), len(rem_descriptions)) 140 blabla = "-------\n" 141 blabla += "LOCAL nom: {nomL} description: {descrpL} \n" 142 blabla += "REMOTE nom: {nomR} description: {descrpR}\n" 143 144 for i in range(n): 145 nomL = loc_descriptions[i][0] 146 descrpL = loc_descriptions[i][1] 147 nomR = rem_descriptions[i][0] 148 descrpR = rem_descriptions[i][1] 149 params = { 150 'nomL': nomL, 151 'descrpL': descrpL, 152 'nomR': nomR, 153 'descrpR': descrpR 154 } 155 156 if nomL == nomR and descrpL != descrpR: 157 print(blabla.format(**params)) 158 param['label'] = 'Document' 159 param['propsF'] = 'typeDoc:"problème", titre:"{titre}"' 160 param['propsF'] = param['propsF'].format(titre=nomR) 161 param['propsF'] = '{' + param['propsF'] + '}' 162 param["propsV"] = 'n.description = "{descrpL}"' 163 param["propsV"] = param["propsV"].format(descrpL=descrpL) 164 req = self.format_cypher_SET(param) 165 print(req) 166 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 167 val = session.execute_write(self.do_cypher_tx, req) 168 print(val) 169 170 # indexations 171 #print("\n Indexations locales") 172 indexe(self,loc_indexations) 173 174 175 log = "" 176 return log
Exécution des requêtes spécifques de maintenance de la base.
- récupération des descriptions dans la base
- supprimer dans la base les problèmes absents localement
- créer dans la base les problèmes locaux manquants
- si description locale et distante différentes,
- copier description locale sur distante
- afficher les indexations locales
Renvoie
log: str journal
178def indexe(self, loc_indexations): 179 ''' 180 Assure que des relations `INDEXE` sont associées aux indexations locales. 181 ''' 182 print("\n coucou de indexe()") 183 data = self.connect_data 184 URI = data['credentials']['URI'] 185 user = data['credentials']['user'] 186 password = data['credentials']['password'] 187 AUTH = (user, password) 188 189 # indexations dans le graphe 190 req = ''' MATCH (p:Document {typeDoc:"problème"}) -[:INDEXE]-> (c:Concept) 191 RETURN "A" + p.titre, c.litteral 192 ''' 193 #print(req) 194 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 195 rem_indexations = session.execute_write(self.do_cypher_tx, req) 196 197 print(rem_indexations) 198 print(loc_indexations) 199 200 # création des indexations manquantes dans le graphe 201 req = ''' MATCH (p:Document {{typeDoc:"problème", titre: "{0}"}}) 202 MERGE (c:Concept {{litteral:"{1}"}}) 203 CREATE (p)-[:INDEXE]->(c) 204 ''' 205 rem_index_orph = [] 206 for index in loc_indexations : 207 if index not in rem_indexations: 208 nom = index[0][1:] 209 concept = index[1] 210 req1 = req.format(nom, concept) 211 print(nom, concept, req1) 212 with neo4j.GraphDatabase.driver(URI, auth=AUTH).session(database="neo4j") as session: 213 val = session.execute_write(self.do_cypher_tx, req1)
Assure que des relations INDEXE
sont associées aux indexations locales.