Java 加快OpenNLP';当使用它处理多个文本时,它会进行后期标记
我目前正在开发一个关键词提取工具,它可以为网站上的文本或文档提供标签建议。当我遵循本文提出的方法时:我使用OpenNLP工具包的POSTagger作为第一步,即候选选择 一般来说,关键短语提取效果相当好。我的问题是,每当我想使用POSTagger时,我都必须从相应的文件中执行这种昂贵的模型加载:Java 加快OpenNLP';当使用它处理多个文本时,它会进行后期标记,java,performance,serialization,nlp,opennlp,Java,Performance,Serialization,Nlp,Opennlp,我目前正在开发一个关键词提取工具,它可以为网站上的文本或文档提供标签建议。当我遵循本文提出的方法时:我使用OpenNLP工具包的POSTagger作为第一步,即候选选择 一般来说,关键短语提取效果相当好。我的问题是,每当我想使用POSTagger时,我都必须从相应的文件中执行这种昂贵的模型加载: posTagger = new POSTaggerME(new POSModel(new FileInputStream(new File(modelDir + "/en-pos-maxent.bin"
posTagger = new POSTaggerME(new POSModel(new FileInputStream(new File(modelDir + "/en-pos-maxent.bin"))));
tokenizer = new TokenizerME(new TokenizerModel(new FileInputStream(new File(modelDir + "/en-token.bin"))));
// ...
String[] tokens = tokenizer.tokenize(text);
String[] tags = posTagger.tag(tokens);
这是因为此代码不在Web服务器本身的范围内,而是在一个“处理程序”内,其生命周期仅包括处理一个特定请求。我的问题是:如何实现只加载一次文件?(我不想花10秒钟等待模型加载,然后再使用200毫秒。)
我的第一个想法是序列化postagerme(TokenizerMEresp.)并在每次需要时使用Java的内置机制对其进行反序列化。不幸的是,这不起作用——它引发了一个异常。(我确实序列化了WEKA工具包中的分类器,该工具包在最后对我的候选对象进行了分类,以便不必每次都构建(或训练)分类器。因此我认为这可能也适用于PostAgMe。不幸的是,情况并非如此。)
在标记器的情况下,我可以引用一个简单的WhitespaceTokenizer,它是一个较差的解决方案,但一点也不差:
tokenizer = WhitespaceTokenizer.INSTANCE;
但我不认为这是一个可靠的邮资选择 只需将标记化/词性标记管道包装在中即可 如果底层OpenNLP代码不是线程安全的,请将调用放在同步块中,例如:
// the singletons tokenization/POS-tagging pipeline
String[] tokens;
synchronized(tokenizer) {
tokens = tokenizer.tokenize(text);
}
String[] tags;
synchronized(posTagger) {
tags = posTagger.tag(tokens);
}
当您说您试图序列化对象时,您是指将其序列化到磁盘吗?在我看来,没有任何理由认为这会比再次(从磁盘)加载模型更快。我认为解决这个问题的办法在于将模型保存在内存中,但我对您正在部署的环境了解不够。是的,我想将它序列化到磁盘。我的动机是,我认为这类似于序列化WEKA分类器。但我现在意识到事实并非如此:对于分类器,实际使用的内存大小相当小(而创建它的过程非常耗时)——对于POSTagger,无法减小模型的大小。因此,也许我可以利用一个单例来将所有内容只加载到内存中一次。但是在这种情况下,如果许多处理程序试图同时访问它,我可能会遇到问题。是的,dmcer的答案中的方法可能就是您想要的。不过,我认为您不必担心同步问题,因为这些模型只会被读取,而不会被写入。谢谢!我将使用此代码。此外,我将研究是否可以使用n-gram提取方法来选择候选人,例如通过Maui Indexer()进行选择。这在使用内存方面应该更经济。