2008年2月5日

Stanford Parser加速之HashCode和序列化

现在的Java程序中用到了Stanford Parser,在程序功能完整实现后,我开始对这个Parser的使用进行加速。

由于采用的直接嵌入式的调用,没有遇到命令行调用方式下会遇到的资源重复加载的问题。在主控程序中对Parser采用一个类(A)的静态函数来加载所需资源到该类的静态成员变量上,就得到了一个全局的常驻内存资源。哈哈,第一次采用这种方案来实现全局资源,感觉甚为不错!在类A中另写了一个静态函数来执行句法分析。在对文件的处理循环中的某个特征抽取部分,使用类A的静态句法分析函数,从而实现了全局的调用。

加速方案我采用的主要有两种:

  1. 如果pair的第二个元素和第一个元素位于同一个句子,就只parse一次。
  2. 在类A的parse函数中对已经parse过的句子直接加载parse结果。

第一个方法实现起来非常简单,关键是第二个。尝试了几种解决方案后我最后结合hashcode和序列化方法实现了这个功能。这里记录一下,以备查找。

hashcode是对即将Parse的句子采用.HashCode()方法获得这个对象唯一的整数索引值,将这个索引值对应成文件名即可实现每个句子parse后对应一个唯一的文件。说起来这个hashcode函数还真是很神奇的 :)

序列化是我在Python里面常用的技巧,想来就是将对象存入文件以及从文加载对象两步。基于原理都是一样的。但是看了一下Java中对序列化的介绍后,感觉序列化功能也是有巨大应用功能的。参考了一下如下一段讲述Java序列化方法的文章后完成了我的Parse加速。

3.一般序列化实例
程序名称:SerializationDemo.java
程序主题:实现对象的序列化和反序列化
程序说明:该程序由实例化一个MyClass类的对象开始,该对象有三个实例变量,类型分别为String、int、double,是希望存储和恢复的信息。
import java.io.Serializable;
class MyClass implements Serializable {
    String s;
    int i;
    double d;
    public MyClass(String s, int i, double d) {
        this.s = s;
       this.i = i;
       this.d = d;
    }
    public String toString() {
       return "s=" + s + ";i=" + i + ";d=" + d;
    }
}
要想序列化对象,你必须先创建一个OutputStream,然后把它嵌进ObjectOutputStream。这时,你就能用writeObject ( )方法把对象写入OutputStream了。读的时候,你得把InputStream嵌到ObjectInputStream里面,然后再调用 readObject( )方法。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationDemo {
        public static void main(String args[]) {
       FileInputStream in = null;
       FileOutputStream out = null;
       ObjectInputStream oin = null;
       ObjectOutputStream oout = null;
       MyClass object1 = new MyClass("Hello", -7, 2.7e10);
       System.out.println("object1:" + object1);
       // Object serialization
       try {
           out = new FileOutputStream("serial.txt");
           oout = new ObjectOutputStream(out);
           oout.writeObject(object1);
           oout.close();
       } catch (Exception e) {
           System.out.println("Exception during serialization:" + e);
           System.exit(0);
       }
       // Object deserialization
        try {
           MyClass object2;
           in = new FileInputStream("serial");
           oin = new ObjectInputStream(in);
           object2 = (MyClass) oin.readObject();
           oin.close();
           System.out.println("object2:" + object2);
       } catch (Exception e) {
           System.out.println("Exception during deserialization:" + e);
           System.exit(0);
       } finally {
           // …此处省略
       }
    }
}
结果:
object1:s=Hello;i=-7;d=2.7E10
object2:s=Hello;i=-7;d=2.7E10

 

现在我的程序正在健步如飞的运行着,任何两个一模一样的句子都只会被parse一次。

 

序列化和hashcode搭配起来真是不错~!

1 条评论:

匿名 说...

您好,请问您是如何 在java程序中使用Stanford Parser api的? 我是这样用的

LexicalizedParser lexParser = new LexicalizedParser(“englishPCFG.ser.gz”);
public String parse(String sentence)
{
lexParser.parse(sentence);
String s = lexParser.getBestParse().toString();
return s;
}

,但是,当连续分析了很多句子后(多次调用parse),内存消耗非常大。希望能得到您的帮助。谢谢。我的邮箱lujun59[AT]gmail.com