2017-07-31 4 views
3

J'extrais de gros blocs à partir de fichiers XML en utilisant XPath. Mes fichiers xml sont volumineux, ils proviennent de PubMed. Un exemple de mon type de fichier est:La meilleure façon d'extraire un gros bloc xml du grand fichier xml

ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/medline17n0001.xml.gz

Ainsi, en utilisant

Node result = (Node)xPath.evaluate("PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]", doc, XPathConstants.NODE); 

Je reçois l'article avec PMIDtoSearch, de sorte que son parfait. Mais cela prend beaucoup de temps. Je dois le faire environ 800 000 fois, donc avec cette solution, il faudrait plus de deux mois. Certains blocs ont plus de 400 lignes et chaque fichier xml contient plus de 4 millions de lignes.

J'ai aussi essayé une solution comme cette fonction getElementsByTagName mais cela prend presque le même temps.

Savez-vous comment améliorer la solution?

Merci.

+0

VTD-XML est l'analyseur XML ultime pour cela, je vais contribuer un morceau de code pour vous bientôt. –

+0

J'écrirais XQuery pour récupérer ce GZIP, le décompresser et le stocker dans exist-db. Ensuite, écrivez Xquery contre ce document stocké. –

Répondre

3

Je pris votre document et chargé dans exist-db alors exécuté votre requête, essentiellement ceci:

xquery version "3.0"; 
let $medline := '/db/Medline/Data' 
let $doc := 'medline17n0001.xml' 
let $PMID := request:get-parameter("PMID", "") 
let $article := doc(concat($medline,'/',$doc))/PubmedArticleSet/PubmedArticle[MedlineCitation/PMID=$PMID] 
return 
$article 

Le document est retourné en 400 millisecondes à partir d'un serveur distant. Si je renforçais ce serveur, je m'attendrais à moins que cela et il pourrait gérer plusieurs demandes simultanées. Ou si vous aviez tout local encore plus vite.

Essayez vous-même, je suis parti les données dans un serveur de test (et rappelez-vous ceci est interrogation à distance à un serveur de micro Amazon en Californie):

http://54.241.15.166/get-article2.xq?PMID=8

http://54.241.15.166/get-article2.xq?PMID=6

http://54.241.15.166/get-article2.xq?PMID=1

Et bien sûr, tout ce document est là. Vous pouvez simplement modifier cette requête en PMID = 667 ou 999 ou autre et récupérer le fragment de document cible.

0

Ceci est le code qui fait l'interrogation xpath .. sur mon ordinateur portable, les résultats semblent décents .. il a fallu à peu près 1 seconde indépendamment de la valeur pmid. Comment avez-vous l'intention d'extraire le texte. Je peux mettre à jour le code pour le cibler.

public static void main(String[] args) throws VTDException{ 
     VTDGen vg = new VTDGen(); 
     if (!vg.parseFile("d:\\xml\\medline17n0001.xml", false)) 
      return; 
     VTDNav vn = vg.getNav(); 
     AutoPilot ap = new AutoPilot(vn); 
     System.out.println("nesting level"+vn.getNestingLevel()); 
     String PMIDtoSearch = "30000"; 
     ap.selectXPath("/PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]"); 
     System.out.println("====>"+ap.getExprString()); 
     int i=0,count=0; 
     System.out.println(" token count ====> "+ vn.getTokenCount()); 
     while((i=ap.evalXPath())!=-1){ 
      count++; 
      System.out.println("string ====>"+vn.toString(i)); 
     } 
     System.out.println(" count ===> "+count); 
    } 
2

Comme le suggère @KevinBrown, une base de données pourrait bien être la bonne réponse. Mais s'il s'agit d'un processus ponctuel, il existe probablement des solutions qui fonctionnent beaucoup plus rapidement que les vôtres, mais qui ne nécessitent pas la complexité d'apprendre à configurer une base de données XML. Dans l'approche que vous utilisez, il existe deux coûts principaux: l'analyse des documents XML pour créer un arbre en mémoire, puis la recherche dans le document en mémoire pour trouver une valeur d'ID particulière. Je suppose que le coût d'analyse est probablement supérieur d'un ordre de grandeur au coût de la recherche.

Donc, il y a deux ingrédients pour obtenir une bonne performance pour cela:

  • d'abord, vous devez vous assurer que vous analysez que chaque document source une fois (au lieu d'une fois par requête). Vous ne nous en avez pas assez dit pour que je sache si vous faites déjà cela.Deuxièmement, si vous récupérez plusieurs blocs de données à partir d'un seul document, vous voulez le faire sans effectuer de recherche en série pour chacun d'entre eux. La meilleure façon d'y parvenir est d'utiliser un processeur de requêtes qui construit un index pour optimiser la requête (comme Saxon-EE). Vous pouvez également créer des index "manuellement", par exemple en utilisant des mappes XQuery 3.1 ou en utilisant la fonctionnalité xsl: key dans XSLT.

+0

C'est un bon point. Cette collection de données que je connais. Il s'agit d'environ 21 000 Mo de données. Si c'est pour le traiter une fois, peut-être. Là encore, je peux tricher car j'ai une super image de serveur Amazon avec exist-db et beaucoup plus chargée que je peux lancer en 5 minutes. –