Analyseur Python SAX vs analyseur DOM python. Maisons Parsim FIAS

Dans un article précédent, nous avons envisagé une approche de création de csv à partir de xml sur une base de données publiée par FIAS. L'analyse était basée sur l'analyseur DOM, qui charge tout le fichier en mémoire avant le traitement, ce qui a conduit à la nécessité de diviser les fichiers volumineux compte tenu de la quantité limitée de RAM. Cette fois, il est proposé de voir à quel point l'analyseur SAX est bon et de comparer sa vitesse avec l'analyseur DOM. Le plus grand des fichiers de la base de données FIAS, des maisons, d'une taille de 27,5 Go, sera utilisé comme sujet de test.

Entrée


Nous sommes obligés de bouleverser immédiatement le public le plus respecté - ne parvenons pas immédiatement à fournir le fichier de base de données des maisons FIX à l'analyseur SAX. L'analyseur se bloque avec l'erreur "pas bien formé (jeton invalide)". Et au départ, on soupçonnait que le fichier de la base de données était cassé. Cependant, après avoir découpé la base de données en plusieurs petites parties, il a été constaté que les départs étaient dus à un changement de codage pour les numéros de maison et / ou de bâtiment. Autrement dit, les balises STRUCNUM ou HOUSENUM sont tombées sur des maisons avec une lettre écrite dans un codage étrange (ni UTF-8 ni ANSI, dans laquelle le document lui-même a été formé):



Dans le même temps, si cet encodage est redressé en exécutant le fichier via la fonction remove_non_ascii, l'enregistrement prend la forme:



Un tel fichier n'a pas non plus été absorbé par l'analyseur, en raison de caractères supplémentaires.

Je devais me souvenir des expressions régulières et nettoyer le fichier avant de le charger dans l'analyseur.
Question: pourquoi il est impossible de créer une base de données normale, qui est conçue pour que le travail acquière une nuance rhétorique.

Pour aligner les capacités de démarrage des analyseurs, nous supprimons le fragment de test des incohérences ci-dessus.

Code pour effacer le fichier de base de données avant de le charger dans l'analyseur:

Code
from datetime import datetime import re from unidecode import unidecode start = datetime.now() f= open('AS_HOUSE.462.xml', 'r',encoding='ANSI') def remove_non_ascii(text): return unidecode(unidecode(text)) for line in f: b=remove_non_ascii(line) for c in re.finditer(r'\w{5}NUM="\d{1,}\"\w\"',b): print(c[0]) c1=c[0][:-3]+c[0][-2] print(c1) b=b.replace(c[0],c1) #    #  f1= open('out.xml', 'w',encoding='ANSI') f1.write(b) f1.close() f.close() print(datetime.now()- start) 


Le code traduit les caractères non_ascii en normal dans le fichier xml, puis supprime les "" inutiles dans les noms des bâtiments et des maisons.

Analyseur de sax


Pour commencer, prenez un petit fichier xml (58,8 Mo), nous prévoyons d'obtenir txt ou csv à la sortie, pratique pour un traitement ultérieur dans pandas ou excel.

Code
 import xml.sax import csv from datetime import datetime start = datetime.now() class EventHandler(xml.sax.ContentHandler): def __init__(self,target): self.target = target def startElement(self,name,attrs): self.target.send(attrs._attrs.values()) def characters(self,text): self.target.send('') def endElement(self,name): self.target.send('') def coroutine(func): def start(*args,**kwargs): cr = func(*args,**kwargs) cr.__next__() return cr return start with open('out.csv', 'a') as f: # example use if __name__ == '__main__': @coroutine def printer(): while True: event = (yield) print(event,file=f) xml.sax.parse("out.xml", EventHandler(printer())) print(datetime.now()- start) 


Après avoir exécuté le programme, nous obtenons les valeurs du dictionnaire python:



Délai d'exécution: 5-6 sec.

Analyseur DOM


Nous traitons le même fichier en le chargeant d'abord dans son intégralité en mémoire. C'est exactement la méthode utilisée par l'analyseur DOM.

Code
 import codecs,os import xml.etree.ElementTree as ET import csv from datetime import datetime parser = ET.XMLParser(encoding="ANSI") tree = ET.parse("out.xml",parser=parser) root = tree.getroot() Resident_data = open('AS_HOUSE.0001.csv', 'a',encoding='ANSI') csvwriter = csv.writer(Resident_data) attr_names = [ 'HOUSEID', 'HOUSEGUID', 'AOGUID', 'HOUSENUM', 'STRUCNUM', 'STRSTATUS', 'ESTSTATUS', 'STATSTATUS', 'IFNSFL', 'IFNSUL', 'TERRIFNSFL', 'TERRIFNSUL', 'OKATO', 'OKTMO', 'POSTALCODE', 'STARTDATE', 'ENDDATE', 'UPDATEDATE', 'COUNTER', 'NORMDOC', 'DIVTYPE', 'REGIONCODE' ] start = datetime.now() object = [] for member in root.findall('House'): object = [member.attrib.get(attr_name, None) for attr_name in attr_names] csvwriter.writerow(object) Resident_data.close() print(datetime.now()- start) 


Délai de livraison 2-3 sec.
Gagner un analyseur DOM?

Fichiers plus volumineux


Les petits fichiers ne reflètent pas pleinement la réalité. Prenons un fichier de plus de 353 Mo (après le nettoyage, comme indiqué ci-dessus).

Résultats d'épaule:

Analyseur SAX: 0: 00: 32.090836 - 32 sec
Analyseur DOM: 0: 00: 16.630951 - 16 sec

La différence est 2 fois la vitesse. Cependant, cela ne diminue pas le principal avantage de l'analyseur SAX - la possibilité de traiter des fichiers volumineux sans d'abord les charger en mémoire.
Il reste à regretter que cet avantage ne soit pas applicable à la base de données FIAS, car un travail préalable de codage est nécessaire.

Dossier de nettoyage préalable des encodages:
- 353 Mo dans les archives .

Fichier DB purifié pour les tests de l'analyseur:
- 353 Mo dans les archives .

Source: https://habr.com/ru/post/fr469995/


All Articles