Java 高效的SAX处理

Java 高效的SAX处理,java,xml,performance,xml-parsing,sax,Java,Xml,Performance,Xml Parsing,Sax,我有一系列包含邮政编码及其相应纬度和经度的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 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>
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秒以下为佳。到目前为止,我已经成功地将加载时间减少了一半以下

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

Q:有人对更高效的SAX处理有任何其他建议吗?

如果您可以将要检索地理位置的所有邮政编码传递给您的处理程序,处理程序可以一次性检索它们。 执行此操作的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;
  }
}
import java.util.HashMap;
导入java.util.List;
导入java.util.Map;
导入org.xml.sax.Attributes;
导入org.xml.sax.SAXException;
导入org.xml.sax.helpers.DefaultHandler;
公共类SAXDemo扩展了DefaultHandler{
私有地图后处理;
静态类位置{
弦纬度;
弦经度;
}
公共SAXDemo(列出后代码){
this.postalCodeMap=newhashmap();
for(字符串postalCodeToLookFor:postalCodes){
this.postalCodeMap.put(postalcodeookfor,new Location());
}
}
@凌驾
public void startElement(字符串uri、字符串localName、字符串qName、属性)引发SAXException{
字符串postCodeOfElem=attributes.getValue(“postcode”);
if(postCodeOfElem!=null&&this.postalCodeMap.containsKey(postCodeOfElem)){
Location loc=this.postalCodeMap.get(postCodeOfElem);
loc.latitude=attributes.getValue(“纬度”);
loc.longitude=attributes.getValue(“经度”);
}
}
公共位置getLocationForPostalCode(字符串postalCode){
返回此.postalCodeMap.get(postalCode);
}
公共地图getAllFoundGeoLocations(){
返回此.postalCodeMap;
}
}
在这里,您将字符串列表传递给处理程序的构造函数,然后让处理程序用所有XML数据解析文档。
解析完成后,所有检索到的地理位置都可以在
postalCodeMap

中找到。如果内存不是这里的关键要求,那么该文件的dom树(可能使用JAXB或XStream等现代技术)可以通过读取一次文件,然后访问内存中的所有内容来加快速度。这可以大大提高性能(以更高的内存消耗为代价)。您可以使用Apache Tika并使用正则表达式来获取该值使用数据库而不是XML文件?我想我可以使用嵌入式数据库,但我正在删除实体实例的当前SQL数据库不是我要处理的。至于DOM,该软件最终将不得不运行在只有2gb RAM的标准台式机上,因此在内存中存储260万个元素可能是需要避免的。另一种想法是,如果可以对要查找其邮政编码的实体进行预排序,并对xml数据进行排序,您可以通过sax解析器一次提取所有相关的地理位置。这也应该比为每一个实体重新分析整个结构要快很多,这真是个天才。我要看看我是否能让它工作。我的项目花了很多时间才让它工作,我不得不将所有邮政编码XML编译成一个包含250万个元素的大文件。之前只运行整个项目花了整整1分钟,其中大部分被SAX解析占用。现在,整个项目在10秒内完成。嘿,很高兴听到它有帮助!
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;
  }
}