2016-03-16 3 views
1

У меня есть большие XML-файлы (~ 1 Гб) с этой структурой:Синтаксический большой XML-файл Java

<?xml version="1.0" encoding="UTF-8"?> 
<GenoExchange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ncbi.nlm.nih.gov/SNP/geno" xsi:schemaLocation="http://www.ncbi.nlm.nih.gov/SNP/geno ftp://ftp.ncbi.nlm.nih.gov/snp/specs/genoex_1_5.xsd" dbSNPBuildNo="146" reportId="MT" reportType="chromosome"> 
    <Population popId="638" handle="TSC-CSHL" locPopId="TSC_42_AA"> 
     <popClass self="NORTH AMERICA"/> 
    </Population> 
<SnpInfo rsId="1041870" observed="C/T"> 
     <SnpLoc genomicAssembly="107:GRCh38.p2" geneId="4512" geneSymbol="COX1" chrom="MT" start="6150" locType="2" rsOrientToChrom="fwd" contigAllele="T" contig="NC_012920:1"/> 
     <SsInfo ssId="1508548" locSnpId="TSC0349089" ssOrientToRs="fwd"> 
      <ByPop popId="1303" sampleSize="184"> 
       <AlleleFreq allele="T" freq="1"/> 
       <AlleleFreq allele="C" freq="0"/> 
      </ByPop> 
     </SsInfo> 
    </SnpInfo> 
<SnpInfo rsId="1029293" observed="C/T"> 
     <SnpLoc genomicAssembly="107:GRCh38.p2" geneId="4512" geneSymbol="COX1" chrom="MT" start="6307" locType="2" rsOrientToChrom="fwd" contigAllele="C" contig="NC_012920:1"/> 
     <SsInfo ssId="1494519" locSnpId="TSC0254145" ssOrientToRs="fwd"> 
      <ByPop popId="639" sampleSize="82"> 
       <AlleleFreq allele="T" freq="0"/> 
       <AlleleFreq allele="C" freq="1"/> 
      </ByPop> 
      <ByPop popId="1303" sampleSize="184"> 
       <AlleleFreq allele="T" freq="0"/> 
       <AlleleFreq allele="C" freq="1"/> 
      </ByPop> 
     </SsInfo> 
    </SnpInfo> 

Я хочу, чтобы найти конкретный RSID, например RSID = «1029293» и извлечь всю информацию внутри этот узел. Я не хочу запускать весь файл. Я только хочу найти этот идентификатор, извлечь эту информацию и завершить итерацию. Из того, что я прочитал, лучше, если я использую синтаксические анализаторы SAX или Stax. Я использую SAX, это мой код:

class UserHandler extends DefaultHandler { 

    String rsID = null; 
    String i = "1029293";  

    @Override 
    public void startElement(String uri, 
     String localName, String qName, Attributes attributes) throws SAXException { 

     if (qName.equalsIgnoreCase("SnpInfo")) { 
     rsID = attributes.getValue("rsId"); 
      //System.out.println("value: " + rsID); 
     } 
     if((i).equals(rsID) && 
     qName.equalsIgnoreCase("SnpInfo")){ 
     System.out.println("Start Element: " + qName + " " + rsID); 
     }  

     if ((i).equals(rsID) && qName.equalsIgnoreCase("SsInfo")) { 
      String a = attributes.getValue("ssId"); 
      System.out.println("SSID: " + a); 
     } 

     if ((i).equals(rsID) && qName.equalsIgnoreCase("ByPop")) { 
      String p = attributes.getValue("popId"); 
      System.out.println("POPID: " + p); 
     } 
     if ((i).equals(rsID) && qName.equalsIgnoreCase("AlleleFreq")) { 
      String p = attributes.getValue("allele"); 
      String f = attributes.getValue("freq"); 
      System.out.println("ALLELE: " + p + " FREQ: " + f); 
     } 
     if ((i).equals(rsID) && qName.equalsIgnoreCase("GTypeFreq")) { 
      String p = attributes.getValue("gtype"); 
      String f = attributes.getValue("freq"); 
      System.out.println("GTYPE: " + p + " FREQ: " + f); 
     } 
    } 

    @Override 
    public void endElement(String uri, 
     String localName, String qName) throws SAXException { 
     if (qName.equalsIgnoreCase("SnpInfo")) { 
     if((i).equals(rsID) 
      && qName.equalsIgnoreCase("SnpInfo")) 
      System.out.println("End Element: " + qName); 
     } 
     } 
} 
public class XMLParser { 

    public static void main(String argv[]) { 
     try { 
      InputStream fileStream = new FileInputStream("/home/xml/gt_chr10.xml.gz"); 
      InputStream gzipStream = new GZIPInputStream(fileStream); 
      SAXParserFactory factory = SAXParserFactory.newInstance(); 
      SAXParser saxParser = factory.newSAXParser(); 
      UserHandler userhandler = new UserHandler(); 
      saxParser.parse(gzipStream, userhandler); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

Моя проблема заключается в том, что мой код просматривает весь файл для ID и занимает более 2 минут каждый раз. У меня не может быть кода, который занимает так много времени. Есть ли лучший подход для этого?

+0

Выбросьте весь код и используйте XPath, поданный SAX или STAX. NB, вы не должны продолжать тестирование для 'i.equals (rsID)' или использовать избыточные круглые скобки. – EJP

+0

Можно ли использовать XPath с SAX или STAX? Я никогда не работал с файлами xml, поэтому единственное, что я знаю, это то, что я нашел в foruns. Но многие говорят, что XPath нуждается в подходе, таком как DOM для работы. – diborbi

+0

Лучший подход - использовать vtd-xml и xpath ... синтаксический анализ занимает около 10 секунд, а xpath занимает менее 5 секунд ... общая задача занимает менее 15 секунд ... это приемлемо? –

ответ

1

Использование STAX дает вам больший контроль при разборе XML, так как вы активно переключаете элементы из потока. Таким образом, вы можете вытащить следующее событие, обрабатывать его и как только вы нашли данные, просто завершает цикл (с использованием флага или даже оператор возврата, если необходимо)

InputStream in = ... 
XMLInputFactory factory = XMLInputFactory.newInstance(); 
XMLEventReader eventReader = factory.createXMLEventReader(in); 

boolean found = false; 
while (!found && eventReader.hasNext()) { 
    XMLEvent event = eventReader.nextEvent(); 
    switch (event.getEventType()) { 
    case XMLStreamConstants.START_ELEMENT: 
     // your logic here 
     // once you found your element, you can terminate the loop 
     found = true; 
     break; 
    case XMLStreamConstants.END_ELEMENT: 
     // your logic here 
     break; 
    } 
} 

(опущена обработка исключений и ресурсов для краткости)

на стороне записки, вы получите некоторую производительность, совмещая if ((i).equals(rsID) && ... в один, с подробно чеками в вложенного МФСА

if ((i).equals(rsID)) { 
    if(qName.equalsIgnoreCase("GTypeFreq")) { 
     ... 
    } 
} 
1

Вы можете бросить исключение в вашем конечном обработчике элемента, чтобы указать анализатор, что она ликвидирует разбор (http://www.ibm.com/developerworks/library/x-tipsaxstop/):

@Override 
    public void endElement(String uri, 
     String localName, String qName) throws SAXException { 
     if (qName.equalsIgnoreCase("SnpInfo")) { 
     if((i).equals(rsID) 
      && qName.equalsIgnoreCase("SnpInfo")) 
      System.out.println("End Element: " + qName); 
      throw SAXException("Element found."); 
     } 
     } 
1

Единственный способ избежать разбора всего файла каждый раз, когда вы его запускаете, - это поместить данные в базу данных XML. Анализ 1Gb-файла займет около минуты, плюс-минус в зависимости от скорости вашего компьютера и от того, какую обработку вы выполняете на каждом узле.

текшего XSLT 3.0 решение просто:

<xsl:transform version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xpath-default-namespace="http://www.ncbi.nlm.nih.gov/SNP/geno"> 
    <xsl:template name="xsl:initial-template"> 
    <xsl:stream href="input.xml"> 
     <xsl:copy-of select="/GenoExchange/SnpInfo[@rsId='1041870'][1]"/> 
    </xsl:stream> 
    </xsl:template> 
</xsl:transform> 

Нет необходимости писать все, что досадные SAX или StAX код.

Я поставил предикат «[1]», чтобы позволить процессору отказаться от поиска, когда он обнаружил первый удар.

+0

Когда я использую это, я всегда получаю сообщение «No element found». – diborbi

+0

Это работает для меня. Возможно, вы забыли указать xsl: initial-template в качестве точки входа, или, возможно, ваш исходный файл не был вызван input.xml, или, возможно, XSLT 3.0 не был включен. –

1

Лучший подход заключается в использовании vtd-xml и xpath ... 1GB XML-файл занимает около 1.5GB кучи пространства и < 10 сек в 3 ~ 4 года старый интел например в processor.see код ниже .. Еще одна вещь, если вы хотите полностью исключить парсинг, вы можете создать формат файла vtd + XML, чтобы любой последующий запрос мог напрямую получить доступ к части индекса vtd, которая может легко утроить или увеличить производительность вашего приложения ...

import com.ximpleware.*; 

    public class simpleXpathSearch{ 
     public static void main(String s[]) throws VTDException,java.io.UnsupportedEncodingException,java.io.IOException{ 
      VTDGen vg = new VTDGen(); 
      vg.setLCLevel(5); 
      if (!vg.parseFile("input.xml", false)) 
       return; 
      VTDNav vn = vg.getNav(); 
      AutoPilot ap = new AutoPilot(vn); 
      ap.selectXPath("/*/*[@rsID='1029293']"); 
      int i=0; 
      while((i=ap.evalXPath())!=-1){ 
       // your code logic here 
      } 
+0

Я пробовал этот пример, и он отлично работает для файлов размером менее 1 ГБ, но для больших файлов я получаю: java.lang.OutOfMemoryError: Java heap space – diborbi

+0

Я не понимаю, как создать vtd-xml без предварительного разбора файла , Поскольку у меня всего 4 ГБ ОЗУ, я не могу разобрать мои файлы. – diborbi

+0

4 ГБ достаточно для этого 1GB-файла, использование памяти vtd-xml составляет всего 1,3 ~ 1,5x. поэтому убедитесь, что вы увеличиваете размер кучи java и используете 64-битный jvm ... –

0

// Основной класс

public static void main(String[] args) { 
    SAXReader.read(); 
} 

// SAXReader

public static void read(){ 
    try { 
     XMLReader processor = XMLReaderFactory.createXMLReader(); 
     processor.setContentHandler(new SAXController()); 
     processor.parse(new InputSource("MyXML.xml")); 
    } catch (SAXException | IOException e) { 
     System.err.println(e.getMessage()); 
    } 
} 

// SAXController

// SAXController расширяет DefaultHandler

private int tab = 0; 

private void tabulation() { 
    for (int i=0; i<tab; i++) 
     System.out.print(" "); 
} 

@Override 
public void startDocument() { 
    tabulation(); 
    System.out.println("Starting XML Document"); 
    tab++; 
} 

@Override 
public void endDocument() { 
    tab--; 
    tabulation(); 
    System.out.println("Ending XML Document"); 
} 

@Override 
public void startElement(String uri, String localName, String qName, Attributes attributes) 
     throws SAXException { 
    tabulation(); 
    System.out.print(localName); 
    if (attributes.getLength()>0) { 
     for (int i=0; i<attributes.getLength(); i++) { 
      System.out.print(attributes.getLocalName(i)+": "+attributes.getValue(i)); 
     } 
    } 
    System.out.println(); 
    tab++; 
} 

@Override 
public void endElement(String uri, String localName, String qName) 
     throws SAXException { 
    tab--; 
    tabulation(); 
    System.out.println(localName); 
} 

@Override 
public void characters(char[] ch, int start, int length) 
     throws SAXException { 
    String content= new String(ch, start, length); 
    content= content.replaceAll("[\t\n]", "").trim(); 
    if (!content.equals("")) { 
     tabulation(); 
     System.out.println(content); 
    } 
}