Legilibre / Archeo-Lex

Pure Histoire de la Loi française – Git + Markdown
https://archeo-lex.fr
Do What The F*ck You Want To Public License
98 stars 17 forks source link

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

Closed Seb35 closed 6 years ago

Seb35 commented 7 years ago

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 :

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 :

Changaco commented 7 years ago

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 commented 7 years ago

@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 commented 7 years ago

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

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 commented 7 years ago

@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 commented 6 years ago

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

fenollp commented 6 years ago

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 commented 6 years ago

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

Seb35 commented 6 years ago

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 commented 6 years ago

Ç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) :

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 commented 6 years ago

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

Seb35 commented 6 years ago

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.