2014-10-11 11 views
15

Hiện tại, tôi đang cố gắng sử dụng SAX Parser nhưng khoảng 3/4 thông qua tệp nó hoàn toàn bị đóng băng, tôi đã thử phân bổ bộ nhớ nhiều hơn nhưng không nhận được bất kỳ cải tiến nào.Làm thế nào để phân tích các tệp XML lớn (50 GB) trong Java

Có cách nào để tăng tốc độ này không? Một phương pháp tốt hơn?

Tước nó vào xương trần, vì vậy bây giờ tôi có mã sau và khi chạy trong dòng lệnh, nó vẫn không đi nhanh như tôi muốn.

Chạy nó với "java -Xms-4096m -Xmx8192m -jar reader.jar" tôi nhận được một giới hạn GC overhead vượt xung quanh bài viết 700000

chính:

public class Read { 
    public static void main(String[] args) {  
     pages = XMLManager.getPages(); 
    } 
} 

XMLManager

public class XMLManager { 
    public static ArrayList<Page> getPages() { 

    ArrayList<Page> pages = null; 
    SAXParserFactory factory = SAXParserFactory.newInstance(); 

    try { 

     SAXParser parser = factory.newSAXParser(); 
     File file = new File("..\\enwiki-20140811-pages-articles.xml"); 
     PageHandler pageHandler = new PageHandler(); 

     parser.parse(file, pageHandler); 
     pages = pageHandler.getPages(); 

    } catch (ParserConfigurationException e) { 
     e.printStackTrace(); 
    } catch (SAXException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 


    return pages; 
    }  
} 

PageHandler

public class PageHandler extends DefaultHandler{ 

    private ArrayList<Page> pages = new ArrayList<>(); 
    private Page page; 
    private StringBuilder stringBuilder; 
    private boolean idSet = false; 

    public PageHandler(){ 
     super(); 
    } 

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

     stringBuilder = new StringBuilder(); 

     if (qName.equals("page")){ 

      page = new Page(); 
      idSet = false; 

     } else if (qName.equals("redirect")){ 
      if (page != null){ 
       page.setRedirecting(true); 
      } 
     } 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) throws SAXException { 

     if (page != null && !page.isRedirecting()){ 

      if (qName.equals("title")){ 

       page.setTitle(stringBuilder.toString()); 

      } else if (qName.equals("id")){ 

       if (!idSet){ 

        page.setId(Integer.parseInt(stringBuilder.toString())); 
        idSet = true; 

       } 

      } else if (qName.equals("text")){ 

       String articleText = stringBuilder.toString(); 

       articleText = articleText.replaceAll("(?s)<ref(.+?)</ref>", " "); //remove references 
       articleText = articleText.replaceAll("(?s)\\{\\{(.+?)\\}\\}", " "); //remove links underneath headings 
       articleText = articleText.replaceAll("(?s)==See also==.+", " "); //remove everything after see also 
       articleText = articleText.replaceAll("\\|", " "); //Separate multiple links 
       articleText = articleText.replaceAll("\\n", " "); //remove new lines 
       articleText = articleText.replaceAll("[^a-zA-Z0-9- \\s]", " "); //remove all non alphanumeric except dashes and spaces 
       articleText = articleText.trim().replaceAll(" +", " "); //convert all multiple spaces to 1 space 

       Pattern pattern = Pattern.compile("([\\S]+\\s*){1,75}"); //get first 75 words of text 
       Matcher matcher = pattern.matcher(articleText); 
       matcher.find(); 

       try { 
        page.setSummaryText(matcher.group()); 
       } catch (IllegalStateException se){ 
        page.setSummaryText("None"); 
       } 
       page.setText(articleText); 

      } else if (qName.equals("page")){ 

       pages.add(page); 
       page = null; 

      } 
     } else { 
      page = null; 
     } 
    } 

    @Override 
    public void characters(char[] ch, int start, int length) throws SAXException { 
     stringBuilder.append(ch,start, length); 
    } 

    public ArrayList<Page> getPages() { 
     return pages; 
    } 
} 
+0

Bạn có chắc chắn rằng những gì "đóng băng" (muốn cho chúng tôi biết thêm chi tiết về điều đó có nghĩa gì cho tình huống của bạn không?) Là trình phân tích cú pháp SAX thay vì một cái gì đó trong mã của bạn? Bạn có giữ các đối tượng trong bộ nhớ bất cứ nơi nào trong ứng dụng của bạn? – Tim

+0

Im chỉ chạy một số xét nghiệm trên nó vào lúc này, nhưng tôi có một cảm giác nó có thể đã được nhật thực đã được đóng băng lên (Stripoped nó để xương trần và nó sitll đóng băng lên). Chạy nó thông qua dòng lệnh tại thời điểm này, giữ cho bạn được đăng. –

+0

Đã thêm một số mã cơ bản chỉ xuất kết quả đầu ra của người đọc vào trong tệp xml –

Trả lời

24

Mã phân tích cú pháp của bạn có khả năng hoạt động tốt, nhưng khối lượng dữ liệu bạn đang tải có thể quá lớn để giữ trong bộ nhớ trong đó ArrayList.

Bạn cần một số loại đường dẫn để chuyển dữ liệu đến đích thực tế mà không cần lưu trữ tất cả trong bộ nhớ cùng một lúc.

Điều tôi đôi khi làm cho loại tình huống này tương tự như sau.

Tạo một giao diện để xử lý một yếu tố duy nhất:

public interface PageProcessor { 
    void process(Page page); 
} 

Cung cấp một thực hiện này cho PageHandler qua một constructor:

public class Read { 
    public static void main(String[] args) { 

     XMLManager.load(new PageProcessor() { 
      @Override 
      public void process(Page page) { 
       // Obviously you want to do something other than just printing, 
       // but I don't know what that is... 
       System.out.println(page); 
      } 
     }) ; 
    } 

} 


public class XMLManager { 

    public static void load(PageProcessor processor) { 
     SAXParserFactory factory = SAXParserFactory.newInstance(); 

     try { 

      SAXParser parser = factory.newSAXParser(); 
      File file = new File("pages-articles.xml"); 
      PageHandler pageHandler = new PageHandler(processor); 

      parser.parse(file, pageHandler); 

     } catch (ParserConfigurationException e) { 
      e.printStackTrace(); 
     } catch (SAXException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 
} 

Gửi dữ liệu để xử lý này thay vì đặt nó trong danh sách:

public class PageHandler extends DefaultHandler { 

    private final PageProcessor processor; 
    private Page page; 
    private StringBuilder stringBuilder; 
    private boolean idSet = false; 

    public PageHandler(PageProcessor processor) { 
     this.processor = processor; 
    } 

    @Override 
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 
     //Unchanged from your implementation 
    } 

    @Override 
    public void characters(char[] ch, int start, int length) throws SAXException { 
     //Unchanged from your implementation 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) throws SAXException { 
      // Elide code not needing change 

      } else if (qName.equals("page")){ 

       processor.process(page); 
       page = null; 

      } 
     } else { 
      page = null; 
     } 
    } 

} 

Tất nhiên, bạn có thể làm cho giao diện của bạn xử lý nhiều phần của nhiều bản ghi thay vì chỉ một và có các trang thu thập PageHandler cục bộ trong danh sách nhỏ hơn và định kỳ gửi danh sách để xử lý và xóa danh sách.

Hoặc (có lẽ tốt hơn) bạn có thể triển khai giao diện PageProcessor như được định nghĩa ở đây và xây dựng trong logic ở đó đệm dữ liệu và gửi nó để xử lý tiếp theo khối.

+0

Đây là những gì tôi đã làm, 10.000 trang tại một thời điểm hoạt động tốt. –

+0

Tôi vừa bắt đầu xem xét một nhiệm vụ tương tự. Đó có phải là lớp Trang tùy chỉnh không? – Wudang

0

Đây thực sự là vấn đề: pages.add(page);. Trên thực tế, SAX rất thân thiện với bộ nhớ và việc sử dụng bộ nhớ không phụ thuộc vào kích thước của tệp đầu vào.

Chúng tôi đã thiết kế trình tạo mã để tạo mã dựa trên XSD (nếu bạn có sẵn, thì bạn có thể tạo mã đó từ tài liệu nguồn). Sản phẩm này dựa trên SAX và dường như không xử lý các tệp nhiều GB (lớn nhất chúng tôi đã sử dụng là 22GB). Nó thực hiện theo cách tiếp cận được vạch ra bởi Don Roby ở đây. Điều duy nhất bạn cần làm là triển khai giao diện bộ vi xử lý.

Thời gian chạy (java) động cơ sử dụng một tập tin cấu hình (tập tin thuộc tính java) cho phép bạn đăng ký vào các loại đồ bạn quan tâm Nếu bạn muốn có thêm thông tin về vấn đề này, có một cái nhìn ở đây:. http://www.xml2java.net/xml-to-java-data-binding-for-big-data/

Các vấn đề liên quan