7
votes

Travailler avec un très énorme fichier XML en C #

J'ai ce très énorme fichier XML de taille 2.8 Go. C'est la vidage des articles de la Wikipedia polonais. La taille de ce fichier est très problématique pour moi. La tâche consiste à recherche ce fichier pour une grande quantité de données. Tout ce que j'ai, c'est des titres des articles. Je pensais que je pouvais trier ces titres et utiliser une boucle linéaire dans le fichier. L'idée n'est pas si mauvaise, mais les articles sont pas triés par ordre alphabétique. Ils sont triés par ID, que je ne connais pas a priori .

Donc, ma deuxième pensée était de faire un index de ce fichier. Pour stocker dans d'autres lignes de fichier (ou de base de données) au format suivant: Titre; id; index (peut-être sans identifiant). Je suis mon autre question que j'ai demandé de l'aide. L'hypothèse était que si j'avais l'index de la balise nécessaire, je pourrais utiliser simplement une méthode simple recherche pour déplacer le curseur dans le fichier sans lire tout contenu, etc. Pour plus de fichiers, je pense que cela pourrait fonctionner correctement. Mais sur mon ordinateur (ordinateur portable, C2D Proc, Win7, VS2008), j'ai une erreur que l'application ne répond pas.

Dans mon programme, je lis chaque ligne de fichier et vérifie s'il contient une étiquette dont j'ai besoin. Je compte également tous les octets que j'ai lu et enregistrez des lignes dans le format mentionné ci-dessus. Ainsi, pendant que le programme d'indexation est suspendu. Mais jusque-là, le fichier d'index de résultat est de 36,2 Mo et le dernier indice est comme 2 872 765 202 (b) tandis que le fichier XML entier est de 3 085 439 630 b de long.

Ma troisième pensée était de diviser le fichier en pièces plus petites. Pour être précis en 26 morceaux (il y a 26 lettres en langue latine), chacune ne contenant que des entrées à partir de la même lettre, par exemple. Dans A.XML toutes les entrées que les titres commencent à "une" lettre ". Les derniers fichiers seraient comme des dizaines de MB, max à environ 200 Mo, je pense. Mais il y a le même problème avec la lecture du fichier entier.

lire le fichier que j'ai utilisé probablement le moyen le plus rapide: en utilisant streamreader . J'ai lu quelque part que streamreader et xmlreader classe à partir de system.xml sont les méthodes les plus rapides. StreamReader Même plus rapidement que xmlreader . Il est évident que je ne peux pas charger tout ce fichier en mémoire. J'ai installé seulement 3 Go de RAM et Win7 prend comme 800 MB-1GB lorsqu'il est entièrement chargé.

Donc, je demande de l'aide. Quel est le meilleur à faire. Le point est que la recherche Ce fichier XML doit être rapide. Doit être plus rapide puis télécharger des pages Wikipedia simples au format HTML. Je ne suis même pas sûr que cela soit possible.

peut-être charger tout le contenu nécessaire dans la base de données? Peut-être que ce serait plus rapide? Mais je devrai encore lire le fichier entier au moins une fois.

Je ne suis pas sûr de quelques limites d'environ 1 longueur d'interrogation, mais je vais mettre ici également un échantillon de mon code source d'indexation. xxx

meilleures salutations et merci à l'avance,

ventus

EDIT: Lien vers ce Dump http://download.wikimedia.org/plwiki/20100629/


3 commentaires

S'il vous plaît n'oubliez pas que j'ai même un problème de lecture de l'ensemble du fichier. Cela prend tellement de temps avec le code ci-dessus, que vs pense que quelque chose ne va pas ici et arrête une exécution supplémentaire après un certain temps. Comment éviter ça?


D'ACCORD. J'ai finalement réussi à analyser tout le fichier et à transférer son contenu à la base de données SQLite. DB J'aime 2,81 Go, donc cela soulève des problèmes de performance. Mais c'est pour une autre question. J'ai utilisé le code ci-dessus, dans ma question, légèrement modifié. Il a fallu beaucoup de temps pour indexer ce dossier, «cause de mon manque de connaissance de l'utilisation de SQLite. Merci pour des réponses.


Chaque fois que vous traitez de ce montant de données brutes non indexées, cela prendra du temps pour traiter. Mais au moins vous devez seulement le faire une fois. Maintenant que c'est un dB, vous pouvez obtenir des résultats en quelques secondes. Bonne chance.


10 Réponses :


7
votes

Eh bien .... Si vous voulez le chercher, je vous recommande vivement de trouver un meilleur moyen que de traiter le fichier lui-même. Je suggère que vous méritez de la mettre dans une base de données bien normalisée et indexée et faites votre recherche là-bas. Tout ce que vous faites, vous ferez effectivement dupliquer exactement ce que fait une base de données.

Cela prendra ce temps, cependant. xmltextreader est probablement votre meilleur choix, il fonctionne un nœud à la fois. LINQ to XML devrait également être un traitement assez efficace, mais je ne l'ai pas essayé avec un fichier volumineux et je ne peux donc pas commenter.

Puis-je demander: Où est venu cet énorme fichier XML? Il existe peut-être un moyen de faire face à la situation à la source, plutôt qu'avant de devoir traiter un fichier de 3 Go.


3 commentaires

+1, bien qu'il ait mentionné la source (droite?): "C'est la vidage des articles de Wikipedia polonais."


XMLTExtreader n'est qu'une extension de la classe XMLreader afin que la vitesse soit la même. LINQ to XML est plus lent que XML (texte) lecteur. Ça c'est sûr


@Ventus, bien linq à xml pourrait être utilisé pour diffuser, LennilObel.WordPress.com/2009/09/02/... , ce qui peut être ce que Randolpho signifiait.



0
votes

XMLReader sera rapide mais vous avez besoin Pour vérifier s'il est assez rapide dans votre scénario. Supposons que nous recherchions une valeur située dans un nœud appelé élément : xxx


0 commentaires

0
votes

Je ferais cela:

1) briser le XML dans des fichiers plus petits. Par exemple, si le XML ressemble à cela, je créerais un fichier de fichier par numéro d'article avec un nom correspondant à l'attribut de titre. Si le titre n'est pas unique, je ne voudrais que numéroter les fichiers.

Comme c'est beaucoup de fichiers, je les briserais dans des sous-répertoires avec chacun ne comportant pas plus de 1 000 fichiers. xxx

2) Créez une table d'index avec les noms de fichier et les colonnes que vous souhaitez rechercher sur.

3) en option, vous pouvez stocker Les fragments XML dans la base de données au lieu de sur le disque dur. Le type Varcharchar (Max) de SQL Server est bon pour cela.


6 commentaires

Pourquoi stocker le XML cru? Il devrait simplement analyser XML et stocker les données dans la base de données comme base de données.


Même si le XML est suffisamment propre pour stocker comme tables relationnelles, vous ne devez probablement pas stocker les données que vous avez réellement l'intention de rechercher. N'importe quoi de plus et vous ne faites que gaspiller de l'espace et susceptibles de causer des problèmes de performance.


Le problème est que j'ai besoin de stocker alors une très grande quantité de données. Tout le monde sait que le député de Wiki aura beaucoup de texte. Et j'ai besoin de récupérer ce texte. Alors, stockera tous ces nœuds de texte dans la base de données gagnent une recherche plus rapide?


Recherchez-vous dans l'ensemble de l'article ou juste des titres? Si vous ne faites que les titres, l'indice de base de données correct fera cela rapidement. Si tout l'article, vous devriez alors regarder quelque chose comme la recherche de texte complète de SQL Server. Même SQL Server Express inclut cela, mais je ne sais pas comment l'utiliser.


J'ai besoin de rechercher des titres, puis pour le titre particulier, obtenez le contenu de la page. C'est tout ce que je veux réaliser.


Dans ce cas, votre table de base de données aurait deux colonnes, titre et nom de fichier . Le nom de fichier indiquerait au petit fichier XML que j'ai parlé à l'étape 1. Utilisez la base de données pour rechercher le ou les fichiers suivants, puis chargez chacun du disque dur.



6
votes

Eh bien, s'il convient avec vos exigences, je voudrais d'abord importer ce XML dans une RDM comme SQL Server, puis interroger sur ce serveur SQL.

Avec les bons index (index de texte intégral si vous souhaitez effectuer une recherche dans beaucoup de texte), il devrait être assez rapide ...

Cela réduirait beaucoup les frais généraux provenant de l'analyse du fichier XML par les bibliothèques ...


4 commentaires

Merci, mais je ne sais pas si j'aurai accès à tout moteur de stockage du tout.


@Ventus. C'est le seul moyen sain d'aller. Jetez un coup d'œil à SQLite, derby ou à une autre solution de DB intégrée.


Il y a aussi SQL Compact 3.5 ... qui est une sorte de serveur SQL basé sur des fichiers qui n'a besoin que de la fonction .NET 3.5 et ci-dessus pour fonctionner ... Je ne l'ai jamais utilisé, donc je ne suis pas sûr de savoir comment il tarife la vitesse sage ... sqllite a la réputation d'être assez rapide et il y a des cours ado.net pour elle autour ...


Enfin, j'ai exporté tout le contenu nécessaire à la base de données SQLITE. Mais le sujet est toujours sur le point de travailler avec d'énormes XML. Ensuite, DB n'est pas XML (sauf si vous utilisez une base de données XML). +1 un pour vous kharlos :)



2
votes

J'aime l'idée de créer un index - vous obtenez votre code super simple et vous n'avez pas besoin de dépendances horribles telles que des bases de données :)

SO - Créez un index où vous stockez les éléments suivants

[contenu à la recherche]: [Décalage d'octet au début du nœud XML contenant le contenu]

Pour capturer le décalage des octets, vous devez créer votre propre flux sur le fichier d'entrée et créer un lecteur à partir de celui-ci. Vous interrogerez la position sur chaque lecteur.Lead (..). Un exemple d'enregistrement d'index serait:

"est maintenant l'hiver de notre mécontentement": 554353

Cela signifie que l'entrée dans le fichier XML contenant "est maintenant l'hiver de notre mécontentement" est au nœud de la position de l'octet 554 353. Remarque: je serais tenté de coder la partie de recherche de l'index de manière à ne pas entrer en collision avec les séparateurs que vous utilisez.

Pour lire l'index, vous numérisez via l'index sur disque (c'est-à-dire que vous ne vous soulevez pas la charge en mémoire) à la recherche de l'enregistrement approprié. Une fois trouvé, vous aurez le décalage des octets. Maintenant, créez un nouveau flux via le fichier .xml et définissez la position de l'octet offset - Créez un nouveau lecteur et lisez le document à partir de ce point.


2 commentaires

À propos de l'index, dans ma question, j'ai écrit que je voulais en faire un. Le problème était que ce fichier est si énorme que le programme a raccroché. Mais je pense que je vais essayer avec lire () méthode. La lecture du bloc de données de taille fixe peut être plus rapide que readline () . Vaut la peine de vérifier :)


L'idée générale de ma proposition est que vous ne lisez à tout moment une infime fraction de l'index et du fichier de données. Le XMLReader lira un fichier de n'importe quelle taille tout en utilisant une très petite quantité de mémoire - où êtes-vous suspendu?



0
votes

Dumpez-le dans un indice de solr et utilisez-le pour le chercher. Vous pouvez exécuter SOLR en tant que moteur de recherche autonome et un seul bit de script pour boucler sur le fichier et jeter chaque article dans l'index. Solr vous donne ensuite une recherche de texte complète sur les champs que vous avez décidé d'indexer ...


0 commentaires

0
votes

Le seul moyen de pouvoir rechercher rapidement cela est de le stocker dans une base de données, comme les autres l'ont suggéré. Si une base de données n'est pas une option, alors elle va prendre beaucoup de temps, sans aucun doute. Ce que je ferais, c'est créer une application multithread. Créez des threads de travailleurs qui vont lire dans les données et le coller dans une filet de cordes. Avoir comme 5 threads faisant cette segmentation via tout le fichier (un fil de départ commencera donc au début, le deuxième thread démarre 1/5 du chemin dans le fichier, le troisième thread va 2/5 de la voie, etc etc. ). Pendant ce temps, ayez un autre fil qui lit la file d'attente String et cherche tout ce que vous recherchez. Ensuite, avez le fil dequenure une fois que c'est fait. Cela prendra un certain temps, mais cela ne devrait pas planter ni manger des tonnes de mémoire.

Si vous trouvez que cela mange beaucoup de mémoire, définissez une limite sur le nombre d'éléments que la file d'attente peut contenir et que les threads se suspendent jusqu'à ce que la taille de la file d'attente soit inférieure à ce seuil.


5 commentaires

La lecture XML multi-threadé va être non triviale? Il est peut-être préférable de conserver le filetage unique de la déchiquetage XML et de regarder multi-fileter le reste.


@chibacité Ce n'est pas si difficile. Regardez ici: C-Sharpcorner.com/uploadfile/jbailo/... ou ici: C-Sharpcorner.com/uploadfile/mmehta/...


Pas d'infraction, mais je ne pense pas que vous lisiez cet article correctement dans le contexte de la question.


@Chilbacity Vous avez peut-être raison. Peut-être que le fil unique est la voie à suivre. Je ne voulais tout simplement pas voir son interface enfermer.


Quoi qu'il en soit, l'indexation des données est la seule façon sain d'aller. C'est pas beaucoup de données ...



1
votes

Vous pouvez stocker le fichier dans Couchdb. J'ai écrit un script python pour le faire:

code = '''
  function(doc) { 
   if(doc.title.indexOf("Brzeg") > -1) {
    emit(doc._id, doc);
   }

  }
  '''
results = db.query(code)


0 commentaires

0
votes

Vous pouvez utiliser XML DataType de SQL Server qui prend en charge jusqu'à 2 Go de données XML. Et vous pouvez interroger directement XML en l'utilisant.

Reportez-vous ceci. http://technet.microsoft.com/fr- US / Bibliothèque / MS189887 (V = SQL.105) .aspx

J'espère que cela vous aide!


0 commentaires

0
votes

Je connais cette question // la réponse est vieille. Mais j'ai récemment résolu ce problème moi-même et j'ai trouvé personnellement j'utiliserais json.net (Newtonking). Qui est aussi simple que la désémarification des résultats du document XML aux objets C #.

Maintenant, mes documents (résultats) ne sont que quelques-uns de milliards de MB (en moyenne 5 Mo pour le moment) mais je peux voir cette croissance avec l'indice SOLR. Comme il se trouve, je reçois des résultats rapides.

Une discussion sur Codépex en référence à la performance.


0 commentaires