我目前正在开发一个关键短语提取工具,该工具应该为网站上的文本或文档提供标记建议。当我遵循本文提出的方法时:A New Approach to Keyphrase Extraction Using Neural Networks我正在使用OpenNLP工具包的POSTagger进行第一步,即候选人选择。
一般来说,关键短语提取效果很好。我的问题是,每次我想使用POSTagger时,我必须从相应的文件中执行这种昂贵的模型加载:
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秒钟等待模型加载并在之后的200ms内使用它。)
我的第一个想法是序列化 POSTaggerME ( TokenizerME resp。)并在每次需要时使用Java的内置机制对其进行反序列化。不幸的是,这不起作用 - 它引发了一个例外。 (我确实从WEKA工具包中对分类器进行了序列化,最终将我的候选人分类,以便不必每次都建立(或训练)分类器。因此,我认为这也适用于POSTaggeME。不幸的是,这是不是这样的。)
在Tokenizer的情况下,我可以参考一个简单的 WhitespaceTokenizer ,这是一个较差的解决方案,但并没有那么糟糕:
tokenizer = WhitespaceTokenizer.INSTANCE;
但我没有看到这个选项可靠的POSTagger。
答案 0 :(得分:1)
只需将您的标记化/ POS标记管道包装在 singleton 中。
如果底层的OpenNLP代码不是线程安全的,请将调用放在同步块中,例如:
// the singletons tokenization/POS-tagging pipeline
String[] tokens;
synchronized(tokenizer) {
tokens = tokenizer.tokenize(text);
}
String[] tags;
synchronized(posTagger) {
tags = posTagger.tag(tokens);
}