如何强制序列化不能被序列化的Java对象?

5
我正在尝试使用Stanford CoreNLP库,并希望序列化主要的StanfordCoreNLP管道对象,但它会抛出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());
    }
}

1
这是我在SO上找到的最佳答案:https://dev59.com/eXVD5IYBdhLWcg3wE3bz#97630(它是对Effective Java的引用) - Rubens Mariuzzo
可能是Java序列化中的非可序列化部分的重复问题。 - Stephen C
2个回答

2
总的来说,Stanford NLP中表示数据对象(Tree、LexicalizedParser等)的类是可序列化的,而表示处理器的类(如StanfordCoreNLP、LexicalizedParserQuery、CRFClassifier)则不是。要实现您要求的内容,您需要使许多不可序列化的类变得可序列化,并处理其中的任何后果。
然而,我认为您的基本思路是错误的。StanfordCoreNLP在这15秒钟内加载的东西主要是标准的Java序列化对象。实体识别分类器和解析器语法是标准的序列化Java对象。(有一些东西不是这个形式,只是二进制数据,包括POS标记器,这在很大程度上是由于历史原因。)事实是,使用标准的Java序列化加载许多对象并不那么快...你可以在网上找到关于Java序列化速度以及与其他替代方案比较速度的讨论。制作一个包含所有当前序列化对象的新的更大的序列化对象也不能使它更快。 (您可能可以通过在一个连续的数据流中将所有内容放在一起来获得一小部分收益,但除非您做额外的工作来标记不需要序列化的瞬态字段,否则您几乎肯定会因序列化数据结构的增加而损失。)
相反,我建议解决这个问题的关键是只支付一次加载系统的成本,然后在处理许多句子时将其保存在内存中。

1

如果唯一的原因是它没有标记为Serializable,那么您可以尝试一些非默认序列化策略。例如,您可以尝试JacksonXStream

话虽如此,如果它本来就不应该是Serializable,那么这些策略很可能会以有趣的方式失败。请进行充分的测试!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接