我已将DKPro Core设置为Web服务,以获取输入并提供令牌化输出。服务本身设置为泽西岛资源:
@Path("/")
public class MyResource
{
public MyResource()
{
// Nothing here
}
@GET
public String generate(@QueryParam("q") final String input)
{
try
{
final JCasIterable en = iteratePipeline(
createReaderDescription(StringReader.class, StringReader.PARAM_DOCUMENT_TEXT, input, StringReader.PARAM_LANGUAGE, "en")
,createEngineDescription(StanfordSegmenter.class)
,createEngineDescription(StanfordPosTagger.class)
,createEngineDescription(StanfordParser.class)
,createEngineDescription(StanfordNamedEntityRecognizer.class)
);
final StringBuilder sb = new StringBuilder();
for (final JCas jCas : en)
{
for (final Token token : select(jCas, Token.class))
{
sb.append('[');
sb.append(token.getCoveredText());
sb.append(' ');
sb.append(token.getPos().getPosValue());
sb.append(']');
}
}
return sb.toString();
}
catch (final Exception e)
{
throw new RuntimeException("Problem", e);
}
}
}
一切正常但速度很慢,每次输入需要7-10秒。我认为这是因为正在为每个请求重新创建管道。
如何重新设计此代码以将管道创建移至构造函数并减少单个请求的负载?请注意,可能存在多个同时发出的请求,因此任何不是线程安全的都需要在请求中。
答案 0 :(得分:3)
创建一个CAS:
JCas jcas = JCasFactory.createJCas();
填写CAS
jcas.setDocumentText("This is a test");
jcas.setDocumentLanguage("en");
使用
创建一次管道(并保留引擎以进一步请求)AnalysisEngine engine = createEngine(
createEngineDescription(...),
createEngineDescription(...),
...);
如果你一直隐式创建引擎,它必须一遍又一遍地加载模型等。
将管道应用于CAS
SimplePipeline.runPipeline(jcas, engine);
如果您想进一步加快处理速度,那么请创建一个CAS池并在多个请求中重复使用它们 - 从头开始创建CAS需要一点时间。
某些组件可能是线程安全的,其他组件可能不是。这在很大程度上取决于底层第三方库的实现。但DKPro Core中的包装器也没有明确构建为线程安全的。例如,在默认配置中,根据文档语言加载和使用模型。如果您从多个线程使用相同的分析引擎实例,则会导致问题。
同样,您应该考虑创建一个预先实例化的管道池。你需要相当多的内存,因为每个实例都将加载自己的模型。有一些实验性功能可以在同一组件的实例之间共享模型,但它没有经过太多测试。请注意,第三方工具也可能以非线程安全的方式实现其模型。有关DKPro Core中的模型共享,请参阅this discussion on the mailing list。
披露:我是DKPro Core开发人员之一。