New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Créer un cache des sections pour accélérer l’export #32

Closed
Seb35 opened this Issue Feb 27, 2017 · 11 comments

Comments

Projects
None yet
4 participants
@Seb35
Member

Seb35 commented Feb 27, 2017

L’étape d’export vers Git est celle qui prend le plus de temps (jusqu’à 85h pour le code du travail qui comprend 1600 versions). Entre autres pistes qui peuvent être suivies pour améliorer cette performance, il peut être testé la chose suivante : en observant que seule une petite partie du texte est modifiée d’une version à l’autre (en général quelques articles), il pourrait être mis en cache chacune des sections du texte et réutiliser cela à la version suivante si ça n’est pas modifié.

Ce cache serait "hiérarchique" comme les sections :

  • si la partie réglementaire n’est pas modifiée, la réutiliser telle quelle,
  • si seul le titre I du livre I de la partie législative est modifié, réutiliser tous les autres livres ainsi que tous les autres titres du livre I.

Ce cache pourrait ou non être conservé d’une exécution à l’autre (soit reprise sur erreur, soit nouvelle livraison, soit nouveau format de sortie), aussi il faudrait que la clé du cache comprenne au moins :

  • le texte LEGITEXT
  • la section LEGISCTA
  • le format de sortie (les différents switches "historique", "dialecte", "organisation", voire d’autres)
  • possiblement la date de la base LEGI
  • possiblement les articles LEGIARTI
@Changaco

This comment has been minimized.

Member

Changaco commented Mar 20, 2017

Pour l'optimisation de l'export vers Git tu devrais regarder la vidéo http://videos2016.capitoledulibre.org/technique/garnier-entrer-dans-les-entrailles-de-git.mp4, elle montre comment se passer des appels à la commande git que tu utilises actuellement.

Si tu crées toi-même les objets Git l'export sera plus rapide car il y aura moins d'I/O, et tu pourras implémenter les mises à jour incrémentales plus facilement.

Cependant il restera quand même pas mal d'I/O sur des millions de petits fichiers, le seul moyen d'être vraiment rapide serait de générer directement un pack Git, mais pour ça il faudrait descendre un peu plus profond dans les entrailles de Git.

@fgallaire

This comment has been minimized.

Member

fgallaire commented Mar 21, 2017

@Seb35 je n'avais pas vu que tu faisais directement des appels au binaire Git. Le moyen normalement le plus performant serait d'utiliser une librairie Git écrite en Python comme GitPython basée sur GitDB et utilisée par legit, ou Dulwich utilisée par Launchpad.

pygit2 est un binding Python pour libgit2 qui est écrite en C, donc peut-être plus performante. Il faudrait faire des tests...

@fgallaire

This comment has been minimized.

Member

fgallaire commented Mar 22, 2017

En fait GitPython requiert Git. Donc on a trois choix techniques différents à bencher :

  • GitPython, binding Python pour Git en C (comme ce que tu fais mais peut-être en plus optimisé)
  • pygit2, binding Python pour libgit2 en C
  • Dulwich, 100% Python (avec Gittle comme surcouche possible)

Un premier test simple de GitPython est possible sans trop d'efforts, en réutilisant tes commandes Git :
http://gitpython.readthedocs.io/en/stable/tutorial.html#using-git-directly

@fgallaire

This comment has been minimized.

Member

fgallaire commented Mar 22, 2017

@eraviart utilise libgit2 dans Legit.jl
@steeve utilise une lib maison git-fast-import-go pour envoyer toutes les données vers la commande Git git fast-import.

@Seb35

This comment has been minimized.

Member

Seb35 commented Feb 2, 2018

Pour la partie liée spécifiquement à Git, voir #51, cette issue ne traitera pas cette partie.

@fenollp

This comment has been minimized.

fenollp commented Feb 3, 2018

Je doute qu'execve git depuis python soit un probleme (surement pas 10% de la raison que le calcul prenne 85h).
Pour savoir si c'est une question d'IO faut voir le gain qu'un tmpfs peut donner. C'est surement le plus simple gain de perf possible.
Utiliser pypy plutot qu'un python non JIT peut etre bien aussi.

@Seb35

This comment has been minimized.

Member

Seb35 commented Feb 3, 2018

Comme dit précédemment, cette issue ne traite pas des IOs, voir #51. Cette issue est sur le cache logique de sections.

@Seb35

This comment has been minimized.

Member

Seb35 commented Feb 4, 2018

J’ai commencé à implémenter cette issue vendredi, mais ça ne fonctionne qu’à moitié : ça rendait toujours le même texte ou, après amélioration, il manque encore des changements de texte d’une version à l’autre.

Cela est dû au fait qu’une même section LEGISCTA comprent plusieurs parties à l’intérieur avec des dates de vigueur différentes, il n’est donc pas possible de mettre en cache simplement une section (contrairement aux articles où les changements font changer de numéro LEGIARTI). Ensuite, j’ai ajouté une date de fin lors du 1er calcul complet, cela fonctionne pour le 1er calcul complet et la version suivante, mais ça commence à ne plus fonctionner à la 3e car il faut recalculer la prochaine date d’expiration d’une section à partir de toutes les dates d’expiration des sous-section.

Bref, j’en suis à cet endroit (j’avais sous-estimé la non-simplicité) : je fais un dictionnaire hiérarchique (en mémoire) pour que, en même temps que j’utilise le cache, je calcule la date de fin de vigueur de la section à partir du minimum des autres dates de fin de vigueur des sous-sections.

@Seb35

This comment has been minimized.

Member

Seb35 commented Feb 4, 2018

Ça marche bien mieux en réécrivant proprement la gestion des dates de fin de vigueur. Il me reste encore une exception qui devait d’ailleurs rendre partiellement incorrect certaines versions : les articles morts-nés (MODIFIE_MORT_NE), c’est-à-dire ceux dont la fin de vigueur est antérieure au début de vigueur. Dans ces cas-là, les dates de fin de vigueur d’un article X et de début de vigueur de la version suivante de l’article X ne se suivent pas et ça m’oblige à m’intéresser aux dates de début de vigueur pour ne pas rater certains articles.

Par exemple dans le CPI, la section LEGISCTA000032857229 (I-III-VI) :

  • a été créée par la loi 2016-925 du 7 juillet 2016, les dispositions entrant en vigueur à une date déterminée par décret (qui n’est jamais paru) et au plus tard 6 mois après ladite loi (soit le 7 janvier 2017) ;
  • la section elle-même est donc créée le 9 juillet 2016 mais elle reste vide car les articles ne sont pas encore en vigueur ;
  • ensuite l’ordonnace 2016-1823 du 22 décembre 2016 modifie deux articles (remplacement de mots) alors que lesdits articles ne sont pas encore en vigueur, ils deviennent donc "modifiés morts-nés", avec une fin de vigueur au 24 décembre 2016, et des versions en vigueur à partir de la date de vigueur sont créés ;
  • tous les articles, qu’ils soient en vigueur ou modifiés morts-nés, deviennent en vigueur le 7 janvier 2017 ;
  • sans être certain, j’imagine que dans les livraisons de la base LEGI entre le 9 juillet 2016 et le 7 janvier 2017, les articles non-MODIFIE_MORT_NE devaient être en VIGUEUR_DIFF, c’est-à-dire avoir une date de début à "2222-02-22 date d’entrée en vigueur indéterminée" et une date de fin à "2999-01-01 pas de date de fin de vigueur".

Extrait de legi.sqlite (version 2017-05-01T21:23:51+02:00, un peu vieux donc mais ça ne semble pas avoir changé dans cette section depuis) :

sqlite> SELECT * FROM sommaires WHERE element = 'LEGISCTA000032857229';
LEGITEXT000006069414|LEGISCTA000006146350|LEGISCTA000032857229|2016-07-09|2999-01-01|VIGUEUR||5|section_ta_liens
sqlite> SELECT * FROM sommaires WHERE parent = 'LEGISCTA000032857229';
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000032857367|2017-01-07|2999-01-01|VIGUEUR|L136-1|0|section_ta_liens
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000032857351|2017-01-07|2016-12-24|MODIFIE_MORT_NE|L136-2|1|section_ta_liens
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000033678590|2017-01-07|2999-01-01|VIGUEUR|L136-2|2|section_ta_liens
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000032857358|2017-01-07|2999-01-01|VIGUEUR|L136-3|3|section_ta_liens
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000032857348|2017-01-07|2016-12-24|MODIFIE_MORT_NE|L136-4|4|section_ta_liens
LEGITEXT000006069414|LEGISCTA000032857229|LEGIARTI000033678605|2017-01-07|2999-01-01|VIGUEUR|L136-4|5|section_ta_liens

Seb35 added a commit that referenced this issue Mar 9, 2018

Activation des abstractions
Le format de sortie est géré par différentes abstractions permettant
de générer différents formats de sortie tout en dissociant bien le
code interne :
* syntaxe utilisée : Markdown, etc.
* organisation des fichiers : un fichier unique, un article par
  fichier (sans répertoires), etc.
* versionnement : Git, etc. (#35)

Pour chaque abstraction, une "interface" est proposée. Étant donné
l’ampleur du changement, il est possible que ces interfaces évoluent
dans les semaines qui viennent.

Au passage, un cache de sections (#32) est implémenté pour éviter
de recalculer (récursivement) les sous-sections. La difficulté est
de repérer (récursivement) la plus proche date interne de fin de
vigueur, ce qui est fait en retournant ce résultat avec le texte
de la section pour invalider toutes les sections parentes au-delà
de cette date de fin de vigueur. Le gain de temps de calcul est
environ 30 à 100 (pifométriquement, ça passe d’heures de calcul à
minutes de calcul).

Avec le travail sur le cache de sections a été vérifié de façon
plus fine différentes exceptions sur les dates de vigueur. Entre
autres, l’exception où la date de début de vigueur est 2999-01-01
(=absence de date) notamment utilisée dans les arrêtés. Cela
pourrait corriger #11 et #30.
@Seb35

This comment has been minimized.

Member

Seb35 commented Mar 17, 2018

Après un peu de pratique à utiliser le code introduit il y a une semaine, je considère cette issue comme résolue.

@Seb35 Seb35 closed this Mar 17, 2018

@Seb35

This comment has been minimized.

Member

Seb35 commented Mar 17, 2018

Pour information, je viens de refaire tourner le code du travail. D’après le 1er commentaire de cette issue, le calcul prenant 85h ; aujourd’hui, il a pris 3h, soit un temps divisé par 30.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment