DKPro 核心管道的可重用版本
Reusable version of DKPro Core pipeline
我已将 DKPro Core 设置为 Web 服务以获取输入并提供标记化输出。服务本身设置为 Jersey 资源:
@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 秒。我认为这是因为正在为每个请求重新创建管道。
如何修改此代码以将管道创建移至构造函数并减少单个请求的负载?请注意,可能有多个同时请求,因此任何非线程安全的内容都需要包含在请求中。
创建单个 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 核心开发人员之一。
我已将 DKPro Core 设置为 Web 服务以获取输入并提供标记化输出。服务本身设置为 Jersey 资源:
@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 秒。我认为这是因为正在为每个请求重新创建管道。
如何修改此代码以将管道创建移至构造函数并减少单个请求的负载?请注意,可能有多个同时请求,因此任何非线程安全的内容都需要包含在请求中。
创建单个 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 核心开发人员之一。