OpenNLP - 命名实体识别

从给定文本中查找名称、人物、地点和其他实体的过程称为命名实体识别 (NER)。在本章中,我们将讨论如何使用 OpenNLP 库通过 Java 程序执行 NER。

使用开放 NLP 进行命名实体识别

为了执行各种 NER 任务,OpenNLP 使用不同的预定义模型,即 en-nerdate.bn、en-ner-location.bin、en-ner-organization.bin、en-ner-person.bin 和 en-ner-time.bin。所有这些文件都是预定义模型,经过训练可检测给定原始文本中的相应实体。

opennlp.tools.namefind 包包含用于执行 NER 任务的类和接口。要使用 OpenNLP 库执行 NER 任务,您需要 −

  • 使用 TokenNameFinderModel 类加载相应的模型。

  • 实例化 NameFinder 类。

  • 查找名称并打印它们。

以下是编写从给定原始文本中检测名称实体的程序需要遵循的步骤。

步骤 1:加载模型

句子检测模型由名为 TokenNameFinderModel 的类表示,该类属于包 opennlp.tools.namefind

要加载 NER 模型 −

  • 创建一个模型的 InputStream 对象(实例化 FileInputStream 并将相应 NER 模型的路径以字符串格式传递给其构造函数)。

  • 实例化 TokenNameFinderModel 类,并将模型的 InputStream(对象)作为参数传递给其构造函数,如以下代码块所示。

//加载 NER-person 模型
InputStream inputStreamNameFinder = new FileInputStream(".../en-nerperson.bin");
TokenNameFinderModel model = new TokenNameFinderModel(inputStreamNameFinder);

步骤 2:实例化 NameFinderME 类

opennlp.tools.namefindNameFinderME 类包含执行 NER 任务的方法。此类使用最大熵模型在给定的原始文本中查找命名实体。

实例化此类并传递上一步中创建的模型对象,如下所示 −

//实例化 NameFinderME 类
NameFinderME nameFinder = new NameFinderME(model);

步骤 3:查找句子中的名称

NameFinderME 类的 find() 方法用于检测传递给它的原始文本中的名称。此方法接受 String 变量作为参数。

通过将句子的 String 格式传递给此方法来调用此方法。

//查找句子中的名称
Span nameSpans[] = nameFinder.find(sentence);

步骤 4:打印句子中名称的跨度

NameFinderME 类的 find() 方法返回 Span 类型的对象数组。 opennlp.tools.util 包中的 Span 类用于存储集合的 startend 整数。

您可以将 find() 方法返回的跨度存储在 Span 数组中并打印它们,如以下代码块所示。

//打印句子及其跨度
for (Span span : spans)
System.out.println(paragraph.substring(span);

NER 示例

以下是读取给定句子并识别其中人员姓名跨度的程序。将此程序保存在名为 NameFinderME_Example.java 的文件中。

import java.io.FileInputStream; 
import java.io.InputStream;  

import opennlp.tools.namefind.NameFinderME; 
import opennlp.tools.namefind.TokenNameFinderModel; 
import opennlp.tools.util.Span;  

public class NameFinderME_Example { 
   public static void main(String args[]) throws Exception{ 
      /Loading the NER - Person model       InputStream inputStream = new 
         FileInputStream("C:/OpenNLP_models/en-ner-person.bin"); 
      TokenNameFinderModel model = new TokenNameFinderModel(inputStream);
      
        //实例化 NameFinder 类
        NameFinderME nameFinder = new NameFinderME(model);
        
        //以 String 数组的形式获取句子
        String [] sentence = new String[]{
        "Mike",
        "and",
        "Smith",
        "are",
        "good",
        "friends"
        };
        
        //查找句子中的名称
        Span nameSpans[] = nameFinder.find(sentence);
        
        //打印句子中名称的跨度
      	for(Span s: nameSpans) 
         System.out.println(s.toString());    
   }    
}      

使用以下命令从命令提示符编译并执行已保存的 Java 文件 −

javac NameFinderME_Example.java
java NameFinderME_Example

执行时,上述程序读取给定的字符串(原始文本),检测其中的人员姓名,并显示其位置(跨度),如下所示。

[0..1) person
[2..3) person

姓名及其位置

String 类的 substring() 方法接受 beginend 偏移量并返回相应的字符串。我们可以使用此方法将姓名及其跨度(位置)一起打印,如以下代码块所示。

for(Span s: nameSpans)
	System.out.println(s.toString()+" "+tokens[s.getStart()]);

以下是从给定的原始文本中检测姓名并显示姓名及其位置的程序。将此程序保存在名为 NameFinderSentences.java 的文件中。

import java.io.FileInputStream; 
import java.io.InputStream;  

import opennlp.tools.namefind.NameFinderME; 
import opennlp.tools.namefind.TokenNameFinderModel; 
import opennlp.tools.tokenize.TokenizerME; 
import opennlp.tools.tokenize.TokenizerModel; 
import opennlp.tools.util.Span;  

public class NameFinderSentences {  
   public static void main(String args[]) throws Exception{        
      
        //加载 tokenizer 模型
        InputStream inputStreamTokenizer = new
        FileInputStream("C:/OpenNLP_models/entoken.bin");
        TokenizerModel tokenModel = new TokenizerModel(inputStreamTokenizer);
        
        //实例化 TokenizerME 类
        TokenizerME tokenizer = new TokenizerME(tokenModel);
        
        //将句子标记为字符串数组
        String sentence = "Mike 是高级编程经理,Rama 是一名职员,都在 Tutorialspoint 工作";
        String tokens[] = tokenizer.tokenize(sentence);
        
        //加载 NER-person 模型
        InputStream inputStreamNameFinder = new
        FileInputStream("C:/OpenNLP_models/enner-person.bin");
        TokenNameFinderModel model = new TokenNameFinderModel(inputStreamNameFinder);
        
        //实例化 NameFinderME 类
        NameFinderME nameFinder = new NameFinderME(model);
        
        //查找句子中的名称
        Span nameSpans[] = nameFinder.find(tokens);
        
        //打印句子中的名称及其跨度
        for(Span s: nameSpans)    
         System.out.println(s.toString()+"  "+tokens[s.getStart()]);      
   }    
} 

使用以下命令从命令提示符编译并执行已保存的 Java 文件 −

javac NameFinderSentences.java
java NameFinderSentences

执行时,上述程序读取给定的字符串(原始文本),检测其中人员的姓名,并显示其位置(跨度),如下所示。

[0..1) person Mike

查找位置的名称

通过加载各种模型,您可以检测各种命名实体。以下是一个 Java 程序,它加载 en-ner-location.bin 模型并检测给定句子中的位置名称。将此程序保存在名为 LocationFinder.java 的文件中。

import java.io.FileInputStream; 
import java.io.InputStream;  

import opennlp.tools.namefind.NameFinderME; 
import opennlp.tools.namefind.TokenNameFinderModel; 
import opennlp.tools.tokenize.TokenizerME; 
import opennlp.tools.tokenize.TokenizerModel; 
import opennlp.tools.util.Span;  

public class LocationFinder { 
   public static void main(String args[]) throws Exception{
 
      InputStream inputStreamTokenizer = new 
         FileInputStream("C:/OpenNLP_models/entoken.bin"); 
      TokenizerModel tokenModel = new TokenizerModel(inputStreamTokenizer); 
       
        //String passage = "Mike 和 Smith 是同学";
        String passage = "Tutorialspoint 位于海得拉巴";
        
        //实例化 TokenizerME 类
        TokenizerME tokenizer = new TokenizerME(tokenModel);
        String tokens[] = tokenizer.tokenize(paragraph);
        
        //加载 NER 位置 moodel
        InputStream inputStreamNameFinder = new
        FileInputStream("C:/OpenNLP_models/en- ner-location.bin");
        TokenNameFinderModel model = new TokenNameFinderModel(inputStreamNameFinder);
        
        //实例化 NameFinderME 类
        NameFinderME nameFinder = new NameFinderME(model);
        
        //查找位置的名称
        Span nameSpans[] = nameFinder.find(tokens);
        //打印句子中位置的跨度
        for(Span s: nameSpans)   
         System.out.println(s.toString()+"  "+tokens[s.getStart()]); 
   }    
}   

使用以下命令从命令提示符编译并执行保存的 Java 文件 −

javac LocationFinder.java
java LocationFinder

执行时,上述程序读取给定的字符串(原始文本),检测其中的人员姓名,并显示其位置(跨度),如下所示。

[4..5) location  Hyderabad

NameFinder 概率

NameFinderME 类的 probs() 方法用于获取最后解码序列的概率。

double[] probs = nameFinder.probs();

以下是打印概率的程序。将此程序保存在名为 TokenizerMEProbs.java 的文件中。

import java.io.FileInputStream; 
import java.io.InputStream; 
import opennlp.tools.tokenize.TokenizerME; 
import opennlp.tools.tokenize.TokenizerModel; 
import opennlp.tools.util.Span; 
public class TokenizerMEProbs { 
   public static void main(String args[]) throws Exception{     
      String sent = "Hello John how are you welcome to Tutorialspoint"; 
       
        //加载 Tokenizer 模型
        InputStream inputStream = new
        FileInputStream("C:/OpenNLP_models/en-token.bin");
        TokenizerModel tokenModel = new TokenizerModel(inputStream);
        
        //实例化 TokenizerME 类
        TokenizerME tokenizer = new TokenizerME(tokenModel);
        
        //检索 token 的位置
        Span tokens[] = tokenizer.tokenizePos(sent);
        
        //获取最近调用 tokenizePos() 方法的概率
        double[] probs = tokenizer.getTokenProbabilities();
        
        //打印 token 的跨度
      	for( Span token : tokens) 
             System.out.println(token +" 
                "+sent.substring(token.getStart(), token.getEnd()));      
             System.out.println("  "); 
      	for(int i = 0; i<probs.length; i++) 
         	System.out.println(probs[i]);          
   } 
}

使用以下命令从命令提示符编译并执行已保存的 Java 文件 −

javac TokenizerMEProbs.java
java TokenizerMEProbs

执行时,上述程序读取给定的字符串,对句子进行标记并打印。此外,它还返回最后解码序列的概率,如下所示。

[0..5) Hello 
[6..10) John 
[11..14) how 
[15..18) are 
[19..22) you 
[23..30) welcome 
[31..33) to 
[34..48) Tutorialspoint 
   
1.0 
1.0 
1.0 
1.0 
1.0 
1.0 
1.0 
1.0