Dalam
artikel sebelumnya, kami mempertimbangkan pendekatan untuk membuat csv dari xml pada database yang diterbitkan oleh FIAS. Parsing didasarkan pada parser DOM, yang memuat seluruh file ke dalam memori sebelum diproses, yang menyebabkan kebutuhan untuk membagi file besar mengingat keterbatasan jumlah RAM. Kali ini disarankan untuk melihat seberapa bagus parser SAX dan membandingkan kecepatannya dengan parser DOM. File database FIAS terbesar, rumah, berukuran 27,5 GB, akan digunakan sebagai subjek uji.
Entri
Kami dipaksa untuk segera mengganggu publik yang paling dihormati - segera gagal memberi makan file database FIX houses ke parser SAX. Parser lumpuh dengan kesalahan "tidak terbentuk dengan baik (token tidak valid)". Dan awalnya ada kecurigaan bahwa file database rusak. Namun, setelah memotong database menjadi beberapa bagian kecil, ditemukan bahwa keberangkatan disebabkan oleh perubahan kode untuk nomor rumah dan / atau bangunan. Artinya, tag STRUCNUM atau HOUSENUM datang di rumah-rumah dengan surat yang ditulis dalam penyandian aneh (bukan UTF-8 dan bukan ANSI, di mana dokumen itu sendiri dibentuk):

Pada saat yang sama, jika pengodean ini diluruskan dengan menjalankan file melalui fungsi remove_non_ascii, catatan mengambil bentuk:

File seperti itu juga tidak diserap oleh parser, karena karakter tambahan.
Saya harus mengingat ekspresi reguler dan membersihkan file sebelum memuatnya ke parser.
Pertanyaan: mengapa tidak mungkin untuk membuat database normal, yang ditata untuk pekerjaan memperoleh bayangan retoris.
Untuk menyelaraskan kemampuan awal parser, kami menghapus fragmen uji dari inkonsistensi di atas.
Kode untuk menghapus file database sebelum memuatnya ke parser:
Kodefrom 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)
Kode menerjemahkan karakter non_ascii menjadi normal dalam file xml dan kemudian menghapus "" yang tidak perlu atas nama bangunan dan rumah.
Parser sax
Untuk memulai, ambil file xml kecil (58,8 MB), kami berencana untuk mendapatkan txt atau csv di output, nyaman untuk diproses lebih lanjut dalam panda atau excel.
Kode 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:
Setelah menjalankan program, kami mendapatkan nilai dari kamus python:

Waktu pimpin: 5-6 detik.
Pengurai DOM
Kami memproses file yang sama dengan terlebih dahulu memuatnya secara keseluruhan ke dalam memori. Ini persis metode yang digunakan parser DOM.
Kode 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)
Pimpin waktu 2-3 detik.
Memenangkan parser DOM?
File yang lebih besar
File kecil tidak sepenuhnya mencerminkan kenyataan. Mari kita ambil file yang lebih besar dari 353 MB (setelah dibersihkan, seperti yang ditunjukkan di atas).
Hasil bahu:
Pengurai SAX: 0: 00: 32.090836 - 32 dtk
Pengurai DOM: 0: 00: 16.630951 - 16 dtk
Perbedaannya adalah 2 kali kecepatan. Namun, ini tidak mengurangi keunggulan utama SAX parser - kemampuan untuk memproses file besar tanpa terlebih dahulu memuatnya ke dalam memori.
Masih disesalkan bahwa keuntungan ini tidak berlaku untuk basis data FIAS, karena pekerjaan pendahuluan dengan pengkodean diperlukan.
File untuk pembersihan awal pengkodean:
- 353 MB dalam
arsip .
File DB yang dimurnikan untuk pengujian parser:
- 353 MB dalam
arsip .