【问题标题】:Efficient SAX Handling高效的 SAX 处理
【发布时间】:2013-09-07 20:35:23
【问题描述】:

我有一系列包含邮政编码及其相应纬度和经度的 XML,就像这样;

<?xml version="1.0"?>
<postcodes>
    <entry postcode='AB1 0AA' latitude='7.101478' longitude='2.242852' />
    <entry postcode='AB1 0AB' latitude='7.201458' longitude='2.122952' />
</postcodes>

XML 被拆分为以某个字母开头的邮政编码,因此字母表中的每个字母都有一个 XML。它们之间有英国的每个邮政编码,这意味着这些 XML 文件中最大的有 300,000 个entry 元素。

我正在遍历 Entity 对象的列表,以通过 SAX 放置它们的邮政编码,以针对每个邮政编码检索 longitudelatitude 值。所以,如果我有 2000 个实体对象,我会让 SAX 处理程序运行 2000 次来检索这些值。下面的循环代码;

em = emf.createEntityManager();

    for (Integer id : siteID){ 
            site = em.find(SiteTable.class, id);
            if(site != null && site.getPostcode() != null && !site.getPostcode().equals("")){
                XMLPositionRetriever.runXMLQuery(site.getPostcode()); 
            }
            else{
                System.out.println("The site and/or postcode against this Instruction does not exist.");
            }
     }
em.close();

site.getPostcode() 在处理程序中变为postcodeToFind。下面使用的唯一 SAX 处理程序方法的代码;

@Override 
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    if (postcodeToFind.equals(attributes.getValue("postcode"))){
        System.out.println("The postcode '"+postcodeToFind+"', has a latitude of "+attributes.getValue("latitude")+" and a longitude of "+attributes.getValue("longitude"));
        throw new SAXException();   
    }      
}

目前这很耗时(2000 次搜索只需要不到 4 分钟),但我需要加快加载时间。最好在 30 秒以下。到目前为止,我已经设法将加载时间减少了一半以下;

  • 将 Handler 必须运行的次数减少到必要的次数(通过减少需要检查的实体数量)。
  • 一旦找到我需要的数据,让 startElement() 方法抛出异常,这样它就不会不必要地继续搜索。
  • 将 XML 文件分成更小的文件(每个字母对应一个),以便处理程序检查每个文件的元素更少。

问:是否有人对更有效的 SAX 处理有任何其他建议?

【问题讨论】:

  • 如果内存不是这里的关键要求,那么该文件的 dom 树(可能使用 JAXB 或 XStream 等现代技术)可以通过读取文件一次然后访问内存中的所有内容来加快速度。这可以大大提高性能(以更高的内存消耗为代价)
  • 您可以使用 Apache Tika 并使用正则表达式来获取该值
  • 使用数据库而不是 XML 文件?
  • 我想我可以使用一个嵌入式数据库,但我正在拉出实体实例的当前 SQL 数据库不是我要搞砸的。至于 DOM,这个软件最终将不得不在只有 2gb 内存的标准桌面上运行,因此可能要避免在内存中存储 260 万个元素。
  • 在另一个想法中,如果您可以对要查找邮政编码的实体进行预排序并且对 xml 数据进行排序,则可以在 sax 解析器中一次性提取所有相关的地理位置。这也应该比为每个实体重新解析整个结构要快很多。

标签: java xml performance xml-parsing sax


【解决方案1】:

如果您可以将要检索地理位置的所有邮政编码传递给您的处理程序,则处理程序可以一次性检索它们。 执行此操作的 SAXHandler 可能如下所示:

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXDemo extends DefaultHandler {

  private Map<String, Location> postalCodeMap;

  static class Location {
    String latitude;

    String longitude;
  }

  public SAXDemo(List<String> postalCodes) {
    this.postalCodeMap = new HashMap<String, SAXDemo.Location>();
    for (String postalCodeToLookFor : postalCodes) {
      this.postalCodeMap.put(postalCodeToLookFor, new Location());
    }
  }

  @Override
  public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    String postCodeOfElem = attributes.getValue("postcode");
    if (postCodeOfElem != null && this.postalCodeMap.containsKey(postCodeOfElem)) {
      Location loc = this.postalCodeMap.get(postCodeOfElem);
      loc.latitude = attributes.getValue("latitude");
      loc.longitude = attributes.getValue("longitude");
    }
  }

  public Location getLocationForPostalCode(String postalCode) {
    return this.postalCodeMap.get(postalCode);
  }

  public Map<String, Location> getAllFoundGeoLocations() {
    return this.postalCodeMap;
  }
}

在这里,您将一个字符串列表传递给处理程序的构造函数,然后让处理程序使用您的所有 XML 数据解析文档。 解析完成后,所有检索到的地理位置都可以在postalCodeMap中找到

【讨论】:

  • 那是该死的天才。我要看看能不能让它工作。
  • 我的项目花了很多时间才能让它工作,我不得不将所有邮政编码 XML 编译成一个包含 250 万个元素的大文件。之前运行整个项目需要整整 1 分钟,其中大部分时间都被 SAX 解析占用了。现在,整个项目在 10 秒内运行。
  • 嘿,很高兴听到它有帮助!
猜你喜欢
  • 2013-03-02
  • 2011-05-29
  • 2023-02-09
  • 2014-03-16
  • 2017-02-24
  • 2016-05-26
  • 2011-08-15
  • 2011-11-16
  • 1970-01-01
相关资源
最近更新 更多