第四章:关系抽取与知识融合

好,咱们进入第四章。这一章讲的是知识图谱构建中最“烧脑”的两个环节——关系抽取和知识融合。说白了,前面我们搞定了实体识别,知道“张三”、“李四”、“阿里巴巴”是谁。但光知道谁是谁还不够,你得知道他们之间是什么关系。张三和李四是同事?还是朋友?阿里巴巴投资了谁?这些关系,才是知识图谱的灵魂。

我个人习惯把这一章分成两大块:先讲怎么把关系抽出来,再讲怎么把不同来源的知识“捏”到一起。嗯,咱们一步步来。

关系抽取与知识融合 关系抽取 基于规则的方法 基于深度学习的方法 知识融合 实体对齐与消歧 实体链接与属性融合 输出:高质量结构化知识

4.1 实体关系分类:先搞清楚有哪些关系

关系抽取的第一步,不是直接写代码,而是先定义好“关系体系”。你想想看,金融领域的关系和医疗领域的关系能一样吗?肯定不一样。

我在做金融风控项目时,遇到过最头疼的事就是关系定义太细。比如“投资”关系,有人非要拆成“天使投资”、“A轮投资”、“战略投资”……结果模型根本学不过来。后来我学乖了,先做粗粒度分类。

常见的金融关系分类,我一般这么分:

关系大类 具体关系示例 典型三元组
组织-人员 任职、持股、创始人 (张三, 任职于, 阿里巴巴)
组织-组织 投资、收购、合作、竞争 (阿里巴巴, 投资, 蚂蚁集团)
人员-人员 亲属、同事、担保 (李四, 担保, 王五)
组织-事件 涉及诉讼、获得融资 (某公司, 涉及, 股权冻结事件)
我的小建议: 关系分类别超过20种。超过这个数,标注成本会指数级上升,模型效果反而下降。先做精,再做广。

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模型省事多了。

注意: 规则方法最大的坑是“过拟合”。我曾经写了一套规则,在测试集上准确率99%,结果换了一批数据直接掉到60%。规则要留有余地,别写太死。

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”,它们其实是一个东西。这就是实体对齐要解决的问题。

我常用的方法分三步:

  1. 属性相似度计算: 比较两个实体的名称、别名、注册号等属性。用编辑距离或者Jaccard相似度。
  2. 关系相似度计算: 如果两个实体有相似的邻居关系,那它们很可能是同一个。比如A的邻居是“马云”、“淘宝”,B的邻居也是“马云”、“淘宝”,那A和B大概率是同一个。
  3. 阈值判定: 综合得分超过阈值,就合并。
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