关系抽取配置怎么配?从schema定义到批量入库的实操流程
关系抽取配置通常分四步走:先定义实体和关系类型(schema),再准备少量标注样例,然后选择规则或模型方式配置抽取器,最后批量运行并抽样检查结果。
下面以 Python 环境下的开源工具为例,说明每一步的具体操作和容易出错的点。
先定 schema,再选工具
关系抽取不是打开一个开关就能用,配置前必须明确你要抽什么。
schema 就是实体类型和关系类型的清单,例如:
- 实体类型:人物、公司、职位
- 关系类型:任职于、创始人、总部位于
schema 越具体,后续配置越容易。
建议先用表格列出「头实体类型-关系-尾实体类型」,例如 人物-任职于-公司。
工具选择上,如果文本格式固定、关系类型少,优先用规则或词典匹配,成本低且可控;
如果表达多样,再考虑预训练模型。
本文演示用 spaCy 的规则匹配和 pipeline 组件做基础配置,不依赖 GPU。
安装依赖:
pip install spacy
python -m spacy download zh_core_web_sm
zh_core_web_sm 是中文小模型,适合做分词和基础实体识别。
如果下载慢,可以换用镜像源或手动下载模型包。
准备标注样例和词典
规则配置需要词典,模型配置需要标注样例。
两种方式都建议先准备 20~50 条覆盖主要关系的句子。
以「人物-任职于-公司」为例,准备一个词典文件 patterns.jsonl,每行一个模式:
{"label": "EMPLOYED_BY", "pattern": [{"LOWER": "在"}, {"ENT_TYPE": "ORG"}, {"LOWER": "工作"}]}
这个模式表示「在 + 组织机构 + 工作」的短语结构。
实际配置时,ENT_TYPE 需要和 spaCy 识别出的实体类型对齐,中文模型的组织机构类型通常是 ORG。
如果使用模型方式,需要把句子转成标注格式,例如:
{"text": "张三在阿里巴巴工作", "entities": [[0, 2, "PERSON"], [3, 7, "ORG"]], "relations": [[0, 2, 3, 7, "EMPLOYED_BY"]]}
标注时注意实体边界要精确到字符索引,关系头尾实体必须出现在 entities 列表中。
配置抽取器并跑通单条文本
规则方式在 spaCy 中通过 EntityRuler 和自定义组件实现。
下面是一个最小可运行脚本 relation_extract.py:
import spacy
from spacy.matcher import Matcher
nlp = spacy.load("zh_core_web_sm")
matcher = Matcher(nlp.vocab)
# 匹配「在 + ORG + 工作」结构
pattern = [{"LOWER": "在"}, {"ENT_TYPE": "ORG"}, {"LOWER": "工作"}]
matcher.add("EMPLOYED_BY", [pattern])
def extract_relations(doc):
matches = matcher(doc)
results = []
for match_id, start, end in matches:
span = doc[start:end]
org = [ent for ent in span.ents if ent.label_ == "ORG"]
if org:
results.append({"relation": "EMPLOYED_BY", "org": org[0].text})
return results
text = "张三在阿里巴巴工作"
doc = nlp(text)
print(extract_relations(doc))
运行 python relation_extract.py,预期输出类似 [{'relation': 'EMPLOYED_BY', 'org': '阿里巴巴'}]。
如果输出为空,先用 print([(ent.text, ent.label_) for ent in doc.ents]) 检查实体识别是否正常。
模型方式则使用 spacy train 命令加载配置文件和标注数据,配置文件中需要设置 [components.relation_extractor] 的 model 和 labels。
训练命令示例:
python -m spacy train config.cfg --output ./output --paths.train ./train.spacy --paths.dev ./dev.spacy
训练前需要把标注 JSON 转成 spaCy 的二进制格式,具体转换命令参考官方文档,不要直接复用不兼容的旧版命令。
批量处理与结果验证
单条跑通后,把输入文本整理成每行一条的 input.txt,用循环批量处理:
with open("input.txt", encoding="utf-8") as f:
for line in f:
doc = nlp(line.strip())
print(extract_relations(doc))
验证阶段重点看三件事:
- 召回率:抽样 30 条结果,统计漏抽的比例。漏抽多说明模式覆盖不够,需要补充词典或增加标注样例。
- 准确率:统计抽错的比例。错抽多通常是实体边界识别不准,检查分词和实体类型。
- 关系方向:头实体和尾实体是否颠倒,规则模式中顺序要固定。
如果批量处理时出现内存增长,把 nlp 对象放在循环外复用,不要每条文本重新加载模型。
容易踩的坑
第一,实体类型不匹配。
中文小模型对机构名识别不稳定,配置前先用测试句确认 ORG 能识别出目标公司名,否则规则永远匹配不上。
第二,标注索引偏移。
手动写字符索引容易多算空格,建议用标注工具导出,不要手写。
第三,关系类型膨胀。
一开始就定义十几种关系,标注和验证都做不完。
先跑通 2~3 个核心关系,再逐步扩展。
第四,忽略负样本。
只准备正例会导致模型把无关句子也抽出关系,标注时保留一部分不包含目标关系的句子。
常见疑问
规则和模型能混用吗?
可以。
常见做法是先用规则覆盖高频固定表达,再用模型处理长尾句子,最后合并结果去重。
需要多少标注数据?
规则方式 20 条左右即可起步;
模型方式通常需要几百条以上,具体取决于关系类型数量和句子多样性,建议先用小样本训练看验证集表现再决定是否扩充。
中文关系抽取必须用大模型吗?
不一定。
文本结构固定、关系类型少时,词典加规则就能满足需求,成本更低且结果可解释。
配置完成后如何持续维护?
把每次抽错的句子加入测试集,定期重跑验证,规则和模型都按版本管理,不要直接改生产配置。