第四章:关系抽取与知识融合
好,咱们进入第四章。这一章讲的是知识图谱构建中最“烧脑”的两个环节——关系抽取和知识融合。说白了,前面我们搞定了实体识别,知道“张三”、“李四”、“阿里巴巴”是谁。但光知道谁是谁还不够,你得知道他们之间是什么关系。张三和李四是同事?还是朋友?阿里巴巴投资了谁?这些关系,才是知识图谱的灵魂。
我个人习惯把这一章分成两大块:先讲怎么把关系抽出来,再讲怎么把不同来源的知识“捏”到一起。嗯,咱们一步步来。
4.1 实体关系分类:先搞清楚有哪些关系
关系抽取的第一步,不是直接写代码,而是先定义好“关系体系”。你想想看,金融领域的关系和医疗领域的关系能一样吗?肯定不一样。
我在做金融风控项目时,遇到过最头疼的事就是关系定义太细。比如“投资”关系,有人非要拆成“天使投资”、“A轮投资”、“战略投资”……结果模型根本学不过来。后来我学乖了,先做粗粒度分类。
常见的金融关系分类,我一般这么分:
| 关系大类 | 具体关系示例 | 典型三元组 |
|---|---|---|
| 组织-人员 | 任职、持股、创始人 | (张三, 任职于, 阿里巴巴) |
| 组织-组织 | 投资、收购、合作、竞争 | (阿里巴巴, 投资, 蚂蚁集团) |
| 人员-人员 | 亲属、同事、担保 | (李四, 担保, 王五) |
| 组织-事件 | 涉及诉讼、获得融资 | (某公司, 涉及, 股权冻结事件) |
4.2 基于规则的关系抽取:老方法依然好用
很多人一上来就想上深度学习,其实没必要。规则方法在金融领域特别管用,因为金融文本的句式相对固定。
举个例子,年报里经常出现“XXX持有XXX公司XX%的股份”。这种句式,用正则表达式就能搞定:
import re
text = "张三持有阿里巴巴集团5.2%的股份"
pattern = r"(.+?)持有(.+?)集团?(\d+\.?\d*)%的股份"
match = re.search(pattern, text)
if match:
subject = match.group(1) # 张三
object = match.group(2) # 阿里巴巴
relation = "持股"
print(f"({subject}, {relation}, {object})")
我在项目中遇到过最经典的场景:从企业公告里抽“担保关系”。担保的句式几乎千篇一律——“XX公司为XX公司提供担保”。写个规则,准确率能到95%以上。你想想看,这比训练一个BERT模型省事多了。
4.3 基于深度学习的关系抽取:当规则不够用时
规则搞不定的场景,比如“张三和李四共同创立了公司,后来李四退出,王五加入”。这种复杂关系,规则就抓瞎了。这时候得上深度学习。
我常用的方案是BERT+关系分类头。说白了,就是把实体位置用特殊标记包起来,然后让BERT去理解上下文:
from transformers import BertTokenizer, BertForSequenceClassification
# 输入格式:[CLS] 张三 [SEP] 阿里巴巴 [SEP] 张三担任阿里巴巴CEO [SEP]
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertForSequenceClassification.from_pretrained("bert-base-chinese", num_labels=20)
inputs = tokenizer(
"[CLS] 张三 [SEP] 阿里巴巴 [SEP] 张三担任阿里巴巴CEO [SEP]",
return_tensors="pt"
)
outputs = model(**inputs)
predicted_class = outputs.logits.argmax().item() # 假设对应"任职"关系
这里有个关键点:实体位置标记。我习惯在实体前后加上特殊标记,比如[E1]和[/E1],这样模型能明确知道哪个词是头实体、哪个是尾实体。不这么做的话,模型很容易搞混主语和宾语。
经验之谈: 金融领域的关系抽取,用RoBERTa-wwm-ext(哈工大版)效果比原版BERT好。因为金融文本里有很多专业术语,全词掩码能更好地学习这些词。
4.4 实体对齐与消歧:同一个实体,不同叫法
好,关系抽完了,你以为就结束了?还早。不同来源的数据里,同一个实体可能有不同叫法。比如“阿里巴巴集团”、“阿里巴巴”、“阿里”、“Alibaba”,它们其实是一个东西。这就是实体对齐要解决的问题。
我常用的方法分三步:
- 属性相似度计算: 比较两个实体的名称、别名、注册号等属性。用编辑距离或者Jaccard相似度。
- 关系相似度计算: 如果两个实体有相似的邻居关系,那它们很可能是同一个。比如A的邻居是“马云”、“淘宝”,B的邻居也是“马云”、“淘宝”,那A和B大概率是同一个。
- 阈值判定: 综合得分超过阈值,就合并。
def entity_alignment(entity1, entity2):
# 名称相似度
name_sim = jaccard_similarity(entity1.name, entity2.name)
# 关系邻居相似度
neighbor_sim = neighbor_similarity(entity1.neighbors, entity2.neighbors)
# 综合得分
total_score = 0.6 * name_sim + 0.4 * neighbor_sim
return total_score > 0.75 # 阈值根据经验调整
4.5 知识融合技术:把碎片拼成完整画像
最后一步,知识融合。说白了,就是把不同来源的碎片信息,拼成一个完整的实体画像。
知识融合包含两个核心任务:
- 实体链接: 把文本中提到的实体,链接到知识图谱中已有的节点上。比如新闻里说“阿里”,你要知道它指的是知识图谱里的“阿里巴巴集团”。
- 属性融合: 同一个实体,不同来源可能有不同属性。比如A来源说“张三的生日是1980年1月1日”,B来源说“张三的生日是1980年1月2日”。你得决定信哪个。
属性融合我一般用“投票法”或“置信度加权法”。如果三个来源都说同一个日期,那就用这个日期。如果两个来源冲突,就看哪个来源的权威性更高。比如工商局的数据,肯定比某个论坛的数据可信。
核心原则: 知识融合不是简单的“合并”,而是“去伪存真”。保留高质量数据,剔除噪声。我见过太多项目因为盲目合并,导致知识图谱里全是矛盾信息,最后根本没法用。
嗯,这一章的内容就到这。关系抽取和知识融合,是知识图谱构建中最需要“手艺活”的部分。规则和深度学习要结合着用,对齐和融合要小心谨慎。下一章咱们聊聊知识图谱的存储和查询,那又是另一番天地了。
公众号:蓝海资料掘金营,微信deep3321