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 1g~ et \og pièce 2g. 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)
def exec(self):
 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

def indexe(self, loc_indexations):
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.