命名实体识别
在分词流水线中开启
Section titled “在分词流水线中开启”NER 默认不开启,需要显式追加:
import segment.dev.znlp.WordSegmenter;import recipe.segment.dev.znlp.SegmentRecipe;import segment.dev.znlp.Token;
WordSegmenter segmenter = SegmentRecipe.standard().withNer().build();
for (Token t : segmenter.segment("中国科学院位于北京市")) { System.out.println(t.word + "/" + t.getNature());}命中的实体,其 Token.getNature() 会被设为 Nature.ns 或 Nature.nt,由 NerProcessor 在合并 B/M/E 跨度之后写回。
因为 WordSegmenter 线程安全,这个 segmenter 应该作为单例长期持有,而不是每次调用都 build()。
独立使用 NERPerceptron
Section titled “独立使用 NERPerceptron”已有分词和词性结果时,可以跳过流水线直接调用 ner.impl.segment.dev.znlp.NERPerceptron:
import ner.impl.segment.dev.znlp.NERPerceptron;import segment.dev.znlp.WordAndNature;
NERPerceptron ner = Znlp.getService(NERPerceptron.class);
List<String> labels = ner.decode(sentence); // sentence 是 List<WordAndNature>注意 decode 的入参是 List<WordAndNature> 而不是 List<String>——NER 需要词性作为特征。Token 本身就实现了 WordAndNature,所以可以直接把分词结果传进来。
static NERPerceptron loadFromModelDir(File dir)static NERPerceptron loadFromClasspath(String path)static NERPerceptron loadFromResource(NlpResourceLoader loader, String path)默认模型资源是 znlp/ner/ner.model,随 znlp-resources jar 分发。loadFromModelDir 用于加载自己训练出的目录式模型。
人名走的是另一条路径。PersonNamePerceptron 在 standard() 配方中默认启用,可以用 withoutPersonNames() 关闭:
WordSegmenter noNames = SegmentRecipe.standard().withoutPersonNames().build();独立使用:
import personname.impl.segment.dev.znlp.PersonNamePerceptron;
PersonNamePerceptron pn = Znlp.getPersonNamePerceptron(); // 门面提供的快捷方法List<String> names = pn.findPersonName("文本");// 也有 char[] 重载:pn.findPersonName(char[])PersonNamePerceptron 使用 BMEO 标注,常量为 B=0 / M=1 / E=2 / O=3。模型资源是 znlp/personname/nr-name.model。
Znlp.getPersonNamePerceptron() 返回的就是默认分词器所用的那个实例,因此它和 Znlp.segment 的人名结果一致。
组合出完整的实体抽取
Section titled “组合出完整的实体抽取”由于三类能力分散在不同组件,一个覆盖人名 / 地名 / 机构 / 时间 / 数量的抽取流程大致是这样:
// 1. 分词 + POS + 人名 + NER 一次拿到WordSegmenter segmenter = SegmentRecipe.standard().withNer().build();List<Token> tokens = segmenter.segment(text);
for (Token t : tokens) { switch (t.getNature()) { case nr -> handlePerson(t); // 人名(PersonNamePerceptron) case ns -> handleLocation(t); // 地名(NER) case nt -> handleOrganization(t); // 机构(NER) default -> { } }}
// 2. 时间、数字、金额、电话等结构化维度另走 DucklingList<Dimension> dims = Znlp.parse(text);Dimension 的 getStart() / getEnd() 是闭区间偏移,可以和 Token.offset 对齐做归并。
训练自己的 NER 模型
Section titled “训练自己的 NER 模型”NERPerceptron 基于通用感知机框架,训练流程与 POS 一致:实现 PerceptronInstance,交给 PerceptronTrainer.train,产出 PerceptronTrainModel 后用 saveModelToDir(File) 落盘,运行时通过 NERPerceptron.loadFromModelDir(File) 加载。
仓库的 data/work/ 下有 ner-model、ner-model-dynamic、ner-model-new 等历史训练工作目录可作参考。完整的训练机制见感知机框架。
- 中文分词 —— 配方组合与 Token 结构
- 词性标注 —— Nature 标签全集
- Duckling 结构化解析 —— 时间、数字、金额等维度
- 感知机框架 —— 训练自己的模型