阶段5 | NLP传统 · 第28课/共30课

📖 第28课:知识图谱构建

🎯 课程目标

知识图谱以结构化方式存储实体和关系,是智能问答、推荐系统的核心基础设施。本课学习从零构建知识图谱并实现基于KG的问答。

📐 核心原理

知识图谱的数据模型

知识图谱的核心是三元组:(Subject, Relation, Object)

例如:(马云, 创建, 阿里巴巴)、(阿里巴巴, 总部位于, 杭州)

三元组可以自然地表示为有向图:实体是节点,关系是边。

💡 多跳推理:单跳查询找直接关系,多跳查询可以回答"马云创建的公司在哪里"这类复合问题。这是KG区别于简单数据库的核心能力。

🔬 知识图谱构建与查询

KG存储与多跳查询

class KnowledgeGraph: def __init__(self): self.entities = set() self.relations = [] self.entity_attrs = {} def add_triple(self, subject, relation, obj): self.entities.add(subject) self.entities.add(obj) self.relations.append((subject, relation, obj)) def add_entity_attr(self, entity, attr, value): if entity not in self.entity_attrs: self.entity_attrs[entity] = {} self.entity_attrs[entity][attr] = value def query_by_entity(self, entity): results = [] for s, r, o in self.relations: if s == entity: results.append((r, o, 'outgoing')) if o == entity: results.append((r, s, 'incoming')) return results def query_by_relation(self, relation): return [(s, o) for s, r, o in self.relations if r == relation] def multi_hop_query(self, start_entity, hops=2): paths = [[start_entity]] for _ in range(hops): new_paths = [] for path in paths: last = path[-1] for s, r, o in self.relations: if s == last and o not in path: new_paths.append(path + [r, o]) paths = new_paths return paths kg = KnowledgeGraph() # 构建知识图谱 triples = [ ("马云", "创建", "阿里巴巴"), ("阿里巴巴", "总部位于", "杭州"), ("阿里巴巴", "行业", "电子商务"), ("张勇", "担任", "CEO"), ("张勇", "就职于", "阿里巴巴"), ("腾讯", "总部位于", "深圳"), ("马化腾", "创建", "腾讯"), ("腾讯", "行业", "社交"), ("腾讯", "投资", "美团"), ("美团", "总部位于", "北京"), ("美团", "行业", "本地生活"), ] for s, r, o in triples: kg.add_triple(s, r, o) print("=== 知识图谱查询 ===") print(f"实体数: {len(kg.entities)}, 关系数: {len(kg.relations)}") print("\n阿里巴巴的关联:") for rel, entity, direction in kg.query_by_entity("阿里巴巴"): arrow = "→" if direction == "outgoing" else "←" print(f" {entity} {arrow} [{rel}]") print("\n总部位于关系:") for s, o in kg.query_by_relation("总部位于"): print(f" {s} → {o}") print("\n马云的2跳查询:") paths = kg.multi_hop_query("马云", hops=2) for path in paths: print(f" {' → '.join(path)}")
=== 知识图谱查询 === 实体数: 13, 关系数: 11 阿里巴巴的关联: 马云 ← [创建] 杭州 → [总部位于] 电子商务 → [行业] 张勇 ← [就职于] 总部位于关系: 阿里巴巴 → 杭州 腾讯 → 深圳 美团 → 北京 马云的2跳查询: 马云 → 创建 → 阿里巴巴 → 总部位于 → 杭州 马云 → 创建 → 阿里巴巴 → 行业 → 电子商务

✅ 验证通过:代码实机运行结果如上

🔧 基于KG的问答

KGQA知识图谱问答

class KGQA: def __init__(self, kg): self.kg = kg def answer(self, question): # 简单的基于模板的KG问答 import re patterns = [ (r'(.+?)的(.+?)是什么', self._query_attr), (r'(.+?)的(.+)', self._query_relation), (r'谁(.+?)了(.+)', self._query_reverse), ] for pattern, handler in patterns: match = re.match(pattern, question) if match: return handler(match) return "无法理解该问题" def _query_attr(self, match): entity = match.group(1) attr = match.group(2) if entity in self.kg.entity_attrs and attr in self.kg.entity_attrs[entity]: return self.kg.entity_attrs[entity][attr] # 尝试关系查询 for rel, obj, direction in self.kg.query_by_entity(entity): if attr in rel: return obj if direction == 'outgoing' else f"{obj} (反向)" return f"未知: {entity}的{attr}" def _query_relation(self, match): entity = match.group(1) relation = match.group(2) for rel, obj, direction in self.kg.query_by_entity(entity): if relation in rel or rel in relation: return obj if direction == 'outgoing' else f"{obj} (反向)" return f"未知: {entity}的{relation}" def _query_reverse(self, match): relation = match.group(1) obj = match.group(2) for s, r, o in self.kg.relations: if o == obj and relation in r: return s return f"未知: 谁{relation}了{obj}" qa = KGQA(kg) questions = [ "阿里巴巴的行业是什么", "阿里巴巴的总部位于", "谁创建了腾讯", "马云的2跳查询", ] print("=== 知识图谱问答 ===") for q in questions: if '2跳' in q: paths = kg.multi_hop_query("马云", hops=2) answer = ' | '.join(['→'.join(p) for p in paths[:3]]) else: answer = qa.answer(q) print(f" 问: {q}") print(f" 答: {answer}")
[STDERR] Traceback (most recent call last): File "<string>", line 48, in <module> NameError: name 'kg' is not defined

⚠️ 部分验证:代码实机运行结果如上

📝 练习

动手练习

  1. 从维基百科文本自动抽取三元组,构建大规模KG
  2. 实现图数据库存储(Neo4j),替代内存存储
  3. 实现基于图嵌入(KGE)的链接预测
🧠

🏆 成就解锁:图谱建造师

掌握了知识图谱的构建与查询,能将非结构化文本转化为结构化知识。

🧪 扩展:知识图谱的存储方案

图数据库 vs 关系数据库

方面Neo4j(图)MySQL(关系)
多跳查询高效需要多次JOIN
模式灵活无模式固定模式
可视化内置需第三方工具
事务支持ACIDACID

知识图谱嵌入(KGE)

将实体和关系映射到向量空间,用于链接预测:

📚 参考文献

推荐阅读

在线资源

知识图谱 - 关键概念速查

概念定义应用
Pipeline处理流水线,各步骤串行执行文本处理系统
Tokenization将文本切分为词/子词单元分词、子词分割
Embedding将离散符号映射到连续向量空间词向量、句向量
Feature Engineering从原始数据提取有效数值特征传统ML模型输入
Fine-tuning在预训练模型基础上微调BERT等模型适配

本课要点回顾

  1. 知识图谱是NLP技术栈的重要组件
  2. 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
  3. 代码验证是学习的好方法——动手跑一遍胜过读十遍
  4. 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
  5. 实践出真知——用自己的数据跑一遍,发现课本上没写的问题

❓ 常见问题FAQ

Q: 这个方法的数据需求量是多少?
A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
Q: 如何处理中文的特殊情况?
A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
Q: 传统方法和深度学习如何选择?
A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
Q: 如何评估和调优?
A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
Q: 生产环境部署要注意什么?
A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。

🛠️ 实用工具箱

工具用途安装
jieba中文分词pip install jieba
gensim词向量训练pip install gensim
scikit-learn传统MLpip install scikit-learn
nltk英文NLP工具pip install nltk
spaCy工业NLP管线pip install spacy
hanlp中文NLP工具包pip install hanlp
fasttextFacebook文本分类pip install fasttext
textblob简单NLP接口pip install textblob