我正在试验StanfordCoreNLP库,我想序列化StanfordCore NLP主管道对象,即使它抛出java.io.NotSerializableException.
完整故事:每当我运行我的实现时,将管道注释器和分类器加载到内存中大约需要15秒。最终进程的内存大约为600MB(在我的情况下,很容易就小到可以存储)。我想在第一次创建这个管道后保存它,这样我以后就可以把它读入内存了。
然而,它抛出了一个NotSerializableException。我试着制作一个实现Serializable的琐碎子类,但StanfordCoreNLP的注释器和分类器属性没有实现这个接口,我不能为它们制作子类。
是否有任何Java库可以序列化未实现Serializable的对象?我想它必须遍历它的属性,并对任何类似的对象执行相同的操作。
我尝试过的序列化代码:
static StanfordCoreNLP pipeline;
static String file = "/Users/ME/Desktop/pipeline.sav";
static StanfordCoreNLP pipeline() {
if (pipeline == null) {
try {
FileInputStream saveFile = new FileInputStream(file);
ObjectInputStream read = new ObjectInputStream(saveFile);
pipeline = (StanfordCoreNLP) read.readObject();
System.out.println("Pipeline loaded from file.");
read.close();
} catch (FileNotFoundException e) {
System.out.println("Cached pipeline not found. Creating new pipeline...");
Properties props = new Properties();
props.put("annotators", "tokenize, ssplit, pos, lemma, ner, parse, dcoref");
pipeline = new StanfordCoreNLP(props);
savePipeline(pipeline);
} catch (IOException e) {
System.err.println(e.getLocalizedMessage());
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
}
}
return pipeline;
}
static void savePipeline(StanfordCoreNLP pipeline) {
try {
FileOutputStream saveFile = new FileOutputStream(file);
ObjectOutputStream save = new ObjectOutputStream(saveFile);
save.writeObject(pipeline);
System.out.println("Pipeline saved to file.");
save.close();
} catch (FileNotFoundException e) {
System.out.println("Pipeline file not found during save.");
} catch (IOException e) {
System.err.println(e.getLocalizedMessage());
}
}
通常,表示数据对象的Stanford NLP类(Tree、LexicalizedParser等)是可序列化的,而表示处理器的类(StanfordCoreNLP、LexicalizedParserQuery、CRFClassifier)则不是。为了实现您的要求,您需要使许多类可序列化,而这些类是不可序列化的,并处理由此产生的任何后果。
然而,我认为你的基本思想是错误的。StanfordCoreNLP在这15秒内加载的东西主要是标准的java序列化对象。NER分类器和语法分析器是标准的序列化java对象。(有几件事不是这种形式的,只是二进制数据,包括POS标记器,主要是出于历史原因。)事实是,用标准Java序列化加载很多对象并没有那么快。。。您可以在网上找到关于Java序列化速度以及替代方案的速度比较的讨论。制作一个包含所有当前序列化对象的新的更大的序列化对象并不能使其更快。(通过将所有内容放在一个连续的数据流中,您可能会获得一小部分收益,但除非您做额外的工作来标记不需要序列化的瞬态字段,否则您几乎肯定会因为序列化数据结构的大小增加而损失。)
相反,我建议解决这个问题的关键是只需支付一次加载系统的费用,然后在处理许多句子时将其保存在内存中。
如果它不可序列化的唯一原因是它没有标记为Serializable
,那么您可以使用一些非默认的序列化策略。例如,您可以尝试Jackson或XStream。
也就是说,如果有充分的理由首先不是Serializable
,那么这些策略很可能会以有趣的方式打破。彻底测试!