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.namefind 的 NameFinderME 类包含执行 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 类用于存储集合的 start 和 end 整数。
您可以将 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() 方法接受 begin 和 end 偏移量并返回相应的字符串。我们可以使用此方法将姓名及其跨度(位置)一起打印,如以下代码块所示。
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