第八讲 · 知识存储与检索

(updated 2026年8月23日)

对应 PPT:第8讲 重点:RDF 图 vs 属性图、SPARQL vs Cypher、4 种基于关系型数据库的存储方案。


1. 概述

1.1 2 个核心问题

  • 如何保存知识图谱?
  • 如何查询 / 增加 / 修改 / 删除图谱中的知识?

1.2 存储载体

规模存储方式例子
小规模文件CSV、TXT
大规模数据库关系型数据库 / 图数据库

2. 两种知识图谱数据模型

2.1 图的数学定义

G=(V,E)G = (V, E)
  • VV = 节点集合(Vertices)
  • EE = 边集合(Edges)

2.2 RDF 图(来自语义网)

RDF 图 = 三元组 (S,P,O)(S, P, O) 的有限集。

  • 每个三元组 = 1 个陈述(Statement)
  • 多个陈述 = 1 个描述(Description)
  • 三元组含义:
    • SS 与 OO 之间有 PP 关系
    • 或 SS 具有 PP 属性,属性值为 OO

关键:RDF 没有属性图那种直接挂在节点或边上的键值属性;补充信息仍通过三元组表达,描述某条陈述本身时还需要 RDF reification(具体化)等额外机制。

2.3 属性图(来自数据库)

节点性质(4 条):

  • 每个节点有唯一 id
  • 每个节点有若干出边
  • 每个节点有若干入边
  • 每个节点有若干属性(键值对)

边性质(5 条):

  • 每条边有唯一 id
  • 每条边有一个头节点
  • 每条边有一个尾节点
  • 每条边有标签(关系类型)
  • 每条边有若干属性(键值对)

上面的定义可以按节点 4 条、边 5 条分别检查。

2.4 RDF 图 vs 属性图

维度RDF 图属性图
起源语义网数据库
属性表达用额外三元组表达节点、边原生携带键值属性
类型标注类(Class)+ 属性(Property)标签(Label)+ 键值对
查询语言SPARQL(W3C 标准)Cypher(Neo4j)

Neo4j 实际支持节点 Label,但它不是这页 PPT 所列的四条节点性质之一。


3. 知识图谱查询语言

3.1 SPARQL(RDF 标准查询)

SPARQL = SPARQL Protocol and RDF Query Language W3C 制定的 RDF 图数据标准查询语言;声明式查询语言。

返回形式:XML、JSON、CSV、TSV。

SPARQL 的 7 个核心语法元素

元素作用例子
URI资源唯一标识<http://example.com/ontology#>
PREFIX定义前缀PREFIX abc: <http://...>
变量? 或 $ 开头?capital、$country
SELECT指定返回变量SELECT ?capital ?country
WHERE指定查询条件(三元组模式)WHERE { ?x abc:cityname ?capital }
FILTER过滤条件FILTER (?year < 2000)
OPTIONAL可选匹配OPTIONAL { ?x abc:phone ?phone }

常用前缀(W3C 定义)

前缀命名空间用途
rdf:RDF 核心type, Property, Statement
rdfs:RDF SchemaClass, subClassOf, label
owl:Web OntologyClass, ObjectProperty
xsd:XML Schema Datatypestring, int, date
foaf:Friend of a Friendname, knows
skos:Simple Knowledge OrganizationConcept, prefLabel

SPARQL 三元组模式(4 种用法)

主语谓语宾语作用
abc:city_cairoabc:cityname"Cairo"存储内容
abc:city_cairoabc:cityname?name查城市名称
?cityabc:cityname"Cairo"按名字查城市
?xabc:cityname?capital查所有城市及其名称

三元组模式中,哪个位置换成 ?x,就是在查询哪个位置的值。

SPARQL 例子:非洲国家的首都

PREFIX abc: <http://example.com/exampleOntology#>
SELECT ?capital ?country
WHERE {
  ?country abc:locatedIn "Africa" .
  ?country abc:hasCapital ?capital .
}

3.2 Cypher(Neo4j 属性图查询)

Cypher 最初由 Neo4j 实现,声明式属性图查询语言。 实现系统:SAP HANA Graph、Redis Graph、AgensGraph、Memgraph。

Cypher 基本语法

节点:

(variable:Label {propertyKey: 'propertyValue'})
// ()
// :Label
// { propertykey: 'value' }

关系:

(node1:LabelA)-[rel1:RELATIONSHIP_TYPE]->(node2:LabelB)
// -[]-> 有向
// <-[]- 反向
// -[]- 无向

Cypher 常用查询模式

模式例子
Match all nodesMATCH (n) RETURN n
按 label 查MATCH (a:Person) RETURN a
按 label + 属性查MATCH (a:Person {name: "Théo Gauchoux"}) RETURN a
按关系查MATCH (a)-[:KNOWS]-(b) RETURN a, b
带 WHEREMATCH (p:Person {name:"Alice"})-[s:LIVES_IN]->(city:City) WHERE s.since = 2015 RETURN p, city

Cypher 经典例题

汤姆汉克斯 2000 年之前演过的电影

MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)
WHERE actor.name = "Tom Hanks" AND movie.released < 2000
RETURN movie, actor

这类查询通常按 MATCH、WHERE、RETURN 三部分来写。


4. 常见知识图谱存储方法(4 大类)

4.1 三元组表(最简单)

  • 每条记录 = 1 个三元组 (Subject, Predicate, Object)
  • 最简单、最直接
  • 缺点:复杂查询需要大量自连接(self-join),性能低下

复杂度:

  • 5 跳路径 → 5 个 JOIN
  • 图模式匹配 → 指数级组合
  • 一般:O(Nk)O(N^k)(NN = 表大小,kk = JOIN 次数)

例子:“找某人朋友所在公司的位置”

SELECT t3.o
FROM Triple t1
JOIN Triple t2 ON t1.o = t2.s
JOIN Triple t3 ON t2.o = t3.s
WHERE t1.s = 'A' AND t1.p = 'friendOf'
  AND t2.p = 'worksAt' AND t3.p = 'locatedIn';

4.2 水平表

  • 每一行 = 1 个主语 + 全部谓语和宾语
  • 缺点:不同主语谓语数量不同 → 列数 = 全部谓语数量总和 → 表结构改造成本高

4.3 属性表

  • 水平表的细化:同类主语分到一张表
  • 缺点:表类型过多性能低;不能彻底解决列数问题

4.4 垂直划分

  • 以谓语为划分维度
  • 为每种谓语建立 1 张表
  • 缺点:表类型过多,复杂查询开销大

4.5 4 种方法对比

方法优点缺点适用
三元组表最简单、灵活自连接性能差小规模 / 简单查询
水平表查询快列数固定、改造难谓语稳定的场景
属性表比水平表更细表多、复杂查询差同类主语多
垂直划分谓语查询快复杂查询慢简单分析场景

实际工业界更多用专门的 RDF 三元组库或图数据库(见下),而不是关系型数据库。


5. 面向 RDF 的三元组数据库

5.1 Eclipse RDF4J(开源标准)

  • 开源 RDF 三元组数据库
  • 支持 SPARQL 1.1
  • 模块化设计,GraphDB 上层标准框架以 RDF4J 为标准

5.2 AllegroGraph(商业强大)

  • 支持 SPARQL 1.1
  • 推理机很全:
    • RDFS++ 推理机
    • OWL2 RL 推理机
    • Prolog 规则推理系统
    • 时空推理机制
    • 社会网络分析库
    • 可视化 RDF 图浏览器

6. 基于 Neo4j 的知识图谱存储与检索

6.1 Neo4j 概述

维度内容
模型属性图
社区版单机(免费)
企业版集群 / 高可用(付费)
查询语言Cypher
安装Java + Neo4j 安装包
在线Neo4j Aura(云服务,免费版)

6.2 安装步骤

① 安装 Java 虚拟机
② 下载 Neo4j(https://neo4j.com/download/)
③ 设置环境变量:Path 加 Neo4j bin 路径
④ 管理员身份 CMD 运行:neo4j.bat console

7. 查询语义与 Neo4j 操作

7.1 同一个问题如何落到两种查询语言

SPARQL 用三元组模式查询 RDF 图

SPARQL 的查询条件本身仍是一张“带变量的 RDF 图”。例如查询北航隶属机构的名字,要让三个三元组模式通过变量相接:

SELECT ?name
WHERE {
  ?university <http://example.org/名称> "北航" .
  ?university <http://example.org/隶属于> ?organization .
  ?organization <http://example.org/名称> ?name .
}

Cypher 用节点和关系模式查询属性图

Cypher 则直接画出节点—关系模式,并从匹配到的节点读取属性:

MATCH (university:University {name: '北航'})-[:隶属于]->(organization:Organization)
RETURN organization.name

两者的思路相同:先描述要匹配的局部图,再指定返回值。区别是 RDF 把名称也表达成三元组,属性图则把 name 放在节点的键值属性里。

7.2 Neo4j 的增删改查

课件不仅讲查询,还列出了创建节点和关系、增改属性、删除属性、删除节点和关系等操作。可以用下面这一组最小命令串起来理解:

CREATE (university:University {name: '北航'})
RETURN university
MATCH (university:University {name: '北航'})
MERGE (city:City {name: '北京'})
MERGE (university)-[:位于]->(city)
SET university.FOUNDED_IN = 1952
RETURN university, city
MATCH (university:University {name: '北航'})
REMOVE university.FOUNDED_IN
MATCH (:University {name: '北航'})-[relation:位于]->(:City {name: '北京'})
DELETE relation
MATCH (node {name: '北航'})
DETACH DELETE node

DELETE node 只能删除没有关系的节点;DETACH DELETE node 会先删除相连关系。清空当前数据库可写成 MATCH (node) DETACH DELETE node,执行前必须确认数据范围。

批量导入时,把 UTF-8 CSV 放入 Neo4j 的 import 目录:

LOAD CSV WITH HEADERS FROM 'file:///example_node.csv' AS line
MERGE (:Node {id: line.id, name: line.name})
LOAD CSV WITH HEADERS FROM 'file:///example_relation.csv' AS line
MATCH (source:Node {id: line.START_ID}), (target:Node {id: line.END_ID})
MERGE (source)-[:REL {type: line.TYPE}]->(target)

Python 侧的 py2neo 相当于连接器;建立 Graph 后,可用 graph.run("MATCH ...") 发送 Cypher。查询语义仍由 Cypher 决定,py2neo 只负责连接、参数传递和结果封装。

7.3 北航小图谱:任一与同时

课件用“北航—人工智能学院—两门课程”演示了一个容易出错的查询。下面这条语句只要求课程名属于给定集合:

MATCH (department:Department)-[:开设]->(course:Course)
WHERE course.name IN ['人工智能导论', '知识图谱']
RETURN department.name

它的语义是“开设了任一门课程的二级单位”,每匹配一门课就产生一行,同一个单位还可能重复出现。即使加 DISTINCT,也只是去重,并不会把“任一”变成“同时”。

要表达“同时开设两门”,可以用两个图模式约束同一个 department:

MATCH (department:Department)-[:开设]->(:Course {name: '人工智能导论'})
MATCH (department)-[:开设]->(:Course {name: '知识图谱'})
RETURN department.name

也可以聚合后要求两个目标课程都出现:

MATCH (department:Department)-[:开设]->(course:Course)
WHERE course.name IN ['人工智能导论', '知识图谱']
WITH department, count(DISTINCT course.name) AS courseCount
WHERE courseCount = 2
RETURN department.name

同一语义在 RDF/SPARQL 中通过两个独立三元组模式表达:

SELECT ?name
WHERE {
  ?department <http://example.org/开设> ?knowledgeGraph .
  ?department <http://example.org/开设> ?introToAI .
  ?knowledgeGraph <http://example.org/名称> "知识图谱" .
  ?introToAI <http://example.org/名称> "人工智能导论" .
  ?department <http://example.org/名称> ?name .
}

这组对照的核心不是背语法,而是先判断自然语言中的量词:是“至少一项命中”,还是“每项约束都要成立”。


8. 本讲小结

知识存储与检索
├── 数据模型:RDF 图 / 属性图
├── 查询语言:SPARQL / Cypher
├── 关系数据库方案:三元组表 / 水平表 / 属性表 / 垂直划分
├── RDF 数据库:RDF4J / AllegroGraph
└── Neo4j:查询、增删改、CSV 导入与图模式量词

评论