2

UIMA 和 StanfordNLP 在操作管道之后生成输出,就像我们想要进行 POS 标记一样,因此在输入文本中首先完成标记化,然后进行 POS 标记。

我想使用 UIMA 的标记化并在 Stanford CoreNLP 的 POS 标记器中使用该标记。但是Stanford CoreNLP 的词性标注器需要在词性标注器之前运行分词器。

那么,是否可以在同一管道中使用不同的 API?是否可以同时使用 UIMA 标记器和斯坦福 CoreNLP?

4

2 回答 2

5

在 UIMA中组合来自不同工具链(例如OpenNLPStanford CoreNLP等)的分析步骤的典型方法是将它们中的每一个包装为 UIMA 分析引擎。分析引擎充当 UIMA 数据结构(CAS)和用作单独工具(例如 OpenNLP POS 标记器或 CoreNLP 解析器)的数据结构之间的适配器。在 UIMA 级别,这些组件可以组合成管道。

有多种 UIMA 组件集合包装了此类工具链,例如ClearTKDKPro CoreU-Compare

以下示例结合了 OpenNLP 分段器(标记器/句子拆分器)和斯坦福 CoreNLP 解析器(在本示例中也创建了 POS 标签)。该示例被实现为一个Groovy脚本,它使用uimaFIT API来创建和运行使用 DKPro 核心集合的组件的管道。

#!/usr/bin/env groovy
@Grab(group='de.tudarmstadt.ukp.dkpro.core', 
      module='de.tudarmstadt.ukp.dkpro.core.opennlp-asl', 
      version='1.5.0')
@Grab(group='de.tudarmstadt.ukp.dkpro.core', 
      module='de.tudarmstadt.ukp.dkpro.core.stanfordnlp-gpl', 
      version='1.5.0')

import static org.apache.uima.fit.pipeline.SimplePipeline.*;
import static org.apache.uima.fit.util.JCasUtil.*;
import static org.apache.uima.fit.factory.AnalysisEngineFactory.*;
import org.apache.uima.fit.factory.JCasFactory;

import de.tudarmstadt.ukp.dkpro.core.opennlp.*;
import de.tudarmstadt.ukp.dkpro.core.stanfordnlp.*;
import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.*;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.*;

def jcas = JCasFactory.createJCas();
jcas.documentText = "This is a test";
jcas.documentLanguage = "en";

runPipeline(jcas,
  createEngineDescription(OpenNlpSegmenter),
  createEngineDescription(StanfordParser,
    StanfordParser.PARAM_WRITE_PENN_TREE, true));

select(jcas, Token).each { println "${it.coveredText} ${it.pos.posValue}" }

select(jcas, PennTree).each { println it.pennTree }

它的输出(经过大量日志输出后)应如下所示:

This DT
is VBZ
a DT
test NN
(ROOT
  (S
    (NP (DT This))
    (VP (VBZ is)
      (NP (DT a) (NN test)))))

我以 Groovy 脚本为例,因为它开箱即用。Java 程序看起来很相似,但通常会使用 Maven 或 Ivy 来获取所需的库。

如果您想尝试该脚本并需要有关安装 Groovy 和潜在故障排除的更多信息,您可以在此处找到更多信息。

披露:我正在从事 DKPro Core 和 Apache UIMA uimaFIT 项目。

于 2014-06-05T20:54:42.560 回答
4

如果你想使用 CoreNLP 作为管道,至少有两种方法可以处理这个问题。

  1. 强制 CoreNLP 忽略这些要求。

    Properties props = new Properties();
    props.put("enforceRequirements", "false");
    props.put("annotators", "pos");
    

    这将摆脱“缺少要求”的错误。但是,CoreNLP 中的 POSTaggerAnnotator 期望标记是 CoreLabel 对象,并且期望句子是 CoreMap 对象(实例化为 ArrayCoreMap),因此您必须转换它们。

  2. 将自定义注释器添加到管道。

    CoreMaps/CoreLabels 是以类作为键的映射,因此您需要一个类/键来进行自定义注释:

    public class CustomAnnotations {        
    
        //this class will act as a key
        public static class UIMATokensAnnotation 
                implements CoreAnnotation<List<CoreLabel>> {        
    
            //getType() defines/restricts the Type of the value associated with this key
            public Class<List<CoreLabel>> getType() {
                return ErasureUtils.<Class<List<CoreLabel>>> uncheckedCast(List.class);
            }
        }  
    }
    

    您还需要一个注释器类:

    public class UIMATokensAnnotator implements Annotator{
    
        //this constructor signature is expected by StanfordCoreNLP.class
        public UIMATokensAnnotator(String name, Properties props) {
            //initialize whatever you need
        }
    
        @Override
        public void annotate(Annotation annotation) {
            List<CoreLabel> tokens = //run the UIMA tokenization and convert output to CoreLabels   
            annotation.set(CustomAnnotations.UIMATokensAnnotation.class, tokens);
        }
    
        @Override
        public Set<Requirement> requirementsSatisfied() {
            return Collections.singleton(TOKENIZE_REQUIREMENT);
        }
    
        @Override
        public Set<Requirement> requires() {
            return Collections.emptySet();
        }
    
    }
    

    最后:

    props.put("customAnnotatorClass.UIMAtokenize", "UIMATokensAnnotator")
    props.put("annotators", "UIMAtokenize, ssplit, pos")
    

    UIMA/OpenNLP/等。可以以类似的方式将句子注释添加为自定义注释器。查看http://nlp.stanford.edu/software/corenlp-faq.shtml#custom以获取选项 #2 的精简版。

于 2014-07-03T21:15:06.930 回答