09Données · Flux XML

xmlstreamer-ng

Streamer de flux XML à isolation des défauts construit sur rypipe, adapté de carlosplanchon/xmlstreamer. Mémoire bornée, récupération conservatrice et échecs partiels explicites.

Une adaptation de carlosplanchon/xmlstreamer basée sur rypipe qui diffuse des flux XML volumineux ou endommagés vers des enregistrements Python sans masquer les éléments corrompus.

Python 3.11+Rust (rypipe-core)Apache ArrowPyO3
Dernier commit du dépôt

Chargement des derniers commits…

Débit parallèle

15,8M lignes/s

Débit

2,12 Go/s

Parallèle borné

10,2M lignes/s

Pic RSS (borné)

202 Mo

01

Problème

Les flux XML volumineux provenant de systèmes distants sont souvent mal formés, mal codés ou interrompus en cours de transit. Un analyseur strict perd l'intégralité du document au profit d'un seul enregistrement brisé ; un analyseur de récupération agressif peut réécrire silencieusement le balisage endommagé dans des enregistrements qui n'ont jamais existé.

xmlstreamer-ng est conçu pour l'espace entre ces deux comportements : livrer chaque élément intact avant et après une corruption localisée, ne jamais inventer d'enregistrements et signaler ce qui a été supprimé au lieu de présenter un traitement incomplet comme un succès.

02

Origine

xmlstreamer-ng est basé sur carlosplanchon/xmlstreamer de Carlos A. Planchón (MIT) et conserve son approche de streaming par élément pour les flux XML volumineux ou endommagés. Le moteur d'analyse repose sur rypipe (rypipe-core), qui fournit le tokenizer d'octets, le splitter, l'analyse par élément et l'exécution Arrow.

03

Pourquoi c'est dur

La reprise doit être conservatrice sans devenir inutile. Les balises séparatrices doivent être reconnues à l'intérieur des commentaires, CDATA, des instructions de traitement et DOCTYPE sans jamais être inventées par eux. La détection de codage doit vaincre une déclaration XML mensongère sans corrompre un UTF-8 valide. La mémoire limitée doit être conservée tandis que les éléments, les sections de balisage et les descripteurs peuvent chacun être plus grands que le tampon de lecture.

Le chemin en colonnes ajoute un deuxième contrat : le même moteur Rust doit produire des lots Arrow sous projection, filtrage et exécution parallèle, avec une sémantique de suppression d'éléments mal formés identique au chemin de streaming.

04

Débit

Derniers benchmarks sur un Ryzen 7 5800X avec un flux de 128 Mio et 951 898 éléments : XmlSource en parallèle (8 threads) atteint 15,8M lignes/s et 2,12 Go/s ; le streaming parallèle borné atteint 10,2M lignes/s et 1,36 Go/s avec 202 Mo de RSS maximal.

05

Résultats du benchmark

Résultats du benchmark
MoteurModeitems/sMo/sRSS max
xmlstreamer-ngXmlSource parallèle (8 threads)15,8M2122,6283 Mo
xmlstreamer-ngParallèle borné (8 threads)10,2M1364,7202 Mo
xmlstreamer-ngXmlSource colonnaire4,6M621,6297 Mo
quick-xml (natif)parse + comptage seulement3,2M433,014 Mo
lxml iterparsedicts par élément304k40,826 Mo
xmlstreamer (original)dicts par élément103k13,834 Mo

Flux synthétique de 128 Mio, 951 898 éléments, médiane de 5 exécutions sur un Ryzen 7 5800X. Les lignes natives ne font que parser et compter ; elles ne construisent pas d'enregistrements.

06

Décisions clés

Deux API, un moteur

StreamInterpreter conserve le contrat de récupération par article ; XmlSource expose la projection, le filtrage et les lots parallèles Arrow à partir du même analyseur Rust.

Comptabilisation des échecs explicites

Les éléments mal formés sont enregistrés et comptés, jamais réparés en silence. Les statistiques de clôture distinguent les dommages causés au flux des éléments supprimés par le filtre de l'appelant.

Reprise conservatrice

La corruption contenue à l'intérieur d'un objet ne laisse tomber que cet objet. Les sections qui ne se ferment jamais sont un choix documenté via Sections(on_limit=...), annoncé avec un avertissement.

07

Garanties

Contracter
Article endommagéDROPPED + WARNED
Voisins validesDELIVERED
Des disques inventésNEVER
MémoireBOUNDED
Encoder les mensongesCONTENT WINS
08

Compromis

  • La balise de séparation ne doit pas s'emboîter à l'intérieur d'elle-même
  • Les éléments sont construits à partir du texte de l'élément et non des attributs XML.
  • Une entrée non fiable et bien formée peut être mieux servie par lxml.iterparse
  • Le API par article est plus lent que l'adaptateur en colonne/parallèle