Analisador Python SAX vs analisador DOM python. Casas FIAS Parsim

Em um artigo anterior, consideramos uma abordagem para criar csv a partir de xml em um banco de dados publicado pelo FIAS. A análise foi baseada no analisador DOM, que carrega o arquivo inteiro na memória antes do processamento, o que levou à necessidade de dividir arquivos grandes em vista da quantidade limitada de RAM. Desta vez, é sugerido verificar o quão bom o analisador SAX é e comparar sua velocidade com o analisador DOM. O maior dos arquivos de banco de dados FIAS, casas, com 27,5 GB de tamanho, será usado como objeto de teste.

Entrada


Somos forçados a incomodar imediatamente o público mais respeitado - falhar imediatamente ao alimentar o analisador SAX, o arquivo de banco de dados do FIAS abrigará. O analisador trava com o erro "não está bem formado (token inválido)". E, inicialmente, havia suspeitas de que o arquivo do banco de dados estava quebrado. No entanto, depois de cortar o banco de dados em várias partes pequenas, verificou-se que as partidas foram causadas por uma codificação alterada para números de casas e / ou edifícios. Ou seja, as tags STRUCNUM ou HOUSENUM encontraram casas com uma letra escrita em uma codificação estranha (não UTF-8 e não ANSI, na qual o próprio documento foi formado):



Ao mesmo tempo, se essa codificação for corrigida executando o arquivo através da função remove_non_ascii, o registro assumirá o formato:



Esse arquivo também não foi absorvido pelo analisador, devido a caracteres extras.

Eu tive que lembrar de expressões regulares e limpar o arquivo antes de carregá-lo no analisador.
Pergunta: por que é impossível criar um banco de dados normal, definido para o trabalho, adquire um tom retórico.

Para alinhar os recursos iniciais dos analisadores, limpamos o fragmento de teste das inconsistências acima.

Código para limpar o arquivo do banco de dados antes de carregá-lo no analisador:

Código
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) 


O código converte caracteres não_ascii para normal no arquivo xml e remove o "" desnecessário nos nomes de edifícios e casas.

Analisador de saxofone


Para começar, pegue um pequeno arquivo xml (58,8 MB), planejamos obter txt ou csv na saída, conveniente para processamento adicional em pandas ou excel.

Código
 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) 


Depois de executar o programa, obtemos os valores do dicionário python:



Prazo de execução: 5-6 seg.

Analisador DOM


Nós processamos o mesmo arquivo primeiro carregando-o totalmente na memória. Esse é exatamente o método que o analisador DOM usa.

Código
 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) 


Lead time 2-3 seg.
Ganhando um analisador DOM?

Arquivos maiores


Arquivos pequenos não refletem completamente a realidade. Vamos pegar um arquivo com mais de 353 MB (após a limpeza, como indicado acima).

Resultados do ombro:

Analisador SAX: 0: 00: 32.090836 - 32 seg
Analisador DOM: 0: 00: 16.630951 - 16 seg

A diferença é 2 vezes a velocidade. No entanto, isso não prejudica a principal vantagem do analisador SAX - a capacidade de processar arquivos grandes sem primeiro carregá-los na memória.
Resta lamentar que essa vantagem não seja aplicável ao banco de dados FIAS, pois é necessário um trabalho preliminar com codificações.

Arquivo para limpeza preliminar de codificações:
- 353 MB no arquivo .

Arquivo de banco de dados purificado para testes do analisador:
- 353 MB no arquivo .

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


All Articles