引言
上一代图数据库技术栈中,与属性图(Labeled Property Graph)并列的另一条主线是 RDF(资源描述框架)——语义网的核心标准。RDF 把一切知识表达为「主语-谓语-宾语」三元组,配合 SPARQL 查询与 OWL 本体推理,成为开放数据、科研图谱、跨域知识互操作的事实标准(Wikidata、Schema.org、Linked Open Data 都在其上)。
本文系统讲 RDF 与 SPARQL:先建立三元组与图模型的直觉,再覆盖四种主流序列化;接着讲 RDFS/OWL 本体建模,深入 SPARQL 四大查询形式与推理;最后用 Jena/Virtuoso 落地一个从 Turtle 数据到 SPARQL 查询的完整案例,并给出 RDF vs 属性图的选型对照。
前置:/graphdb-data-model-basics/(RDF 三元组概念)、/graphdb-knowledge-graph/(知识图谱应用)、/graphdb-modeling-patterns/(图建模思维)。
目录
- 1. RDF 核心:三元组即最小知识单元
- 2. RDF 序列化:Turtle、RDF/XML 与 JSON-LD
- 3. 命名空间与 IRI:全球唯一标识
- 4. RDFS 与 OWL:本体建模
- 5. SPARQL 四大查询形式
- 6. SPARQL 进阶:FILTER、聚合与属性路径
- 7. SPARQL 更新与推理
- 8. Jena/Virtuoso 实战:从数据到查询
- 9. RDF vs 属性图:选型对照
- 10. 速查表
- 延伸阅读
1. RDF 核心:三元组即最小知识单元
1.1 三元组(Triple)
RDF 的所有知识都由「主语 - 谓语 - 宾语」三元组组成:
主语(Subject) :被描述的资源(IRI 或空白节点)
谓语(Predicate) :资源与值的关系(IRI,即属性/关系类型)
宾语(Object) :值(IRI、字面量 literal,或空白节点)
示例:
<Alice> <knows> <Bob>
<Alice> <name> "Alice Smith" ← 宾语是字面量
<Bob> <age> "30"^^xsd:integer
1.2 三元组即图
一张 RDF 数据集合就是有向图:主语和宾语是节点、谓语是边:
[Alice] --knows--> [Bob]
| |
name name
v v
"Alice Smith" "Bob Jones"
1.3 与属性图的对应关系
| 属性图概念 | RDF 概念 |
|---|---|
| 节点 | 主语/宾语(IRI 或字面量) |
| 关系 | 谓语(IRI) |
| 属性 | 字面量宾语(如 name) |
| 标签/类型 | rdf:type 谓语的宾语(类) |
| 关系属性 | RDF 无法直接表达,需重定标(blank node) |
一句话总结:RDF 用「主语-谓语-宾语」统一表达一切知识,三要素拼起来就是一张有向图——没有属性图的「节点属性」与「关系属性」,需要用 reification(重定标)表达。
2. RDF 序列化:Turtle、RDF/XML 与 JSON-LD
2.1 Turtle(推荐,人类可读)
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ex: <http://example.org/> .
ex:alice a foaf:Person ; # a = rdf:type 的简写
foaf:name "Alice Smith" ;
foaf:knows ex:bob .
ex:bob a foaf:Person ;
foaf:name "Bob Jones" ;
foaf:age 30 .
2.2 RDF/XML(机器交换)
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:foaf="http://xmlns.com/foaf/0.1/">
<foaf:Person rdf:about="http://example.org/alice">
<foaf:name>Alice Smith</foaf:name>
<foaf:knows rdf:resource="http://example.org/bob"/>
</foaf:Person>
</rdf:RDF>
2.3 JSON-LD(Web 集成友好)
{
"@context": {
"name": "http://xmlns.com/foaf/0.1/name",
"knows": { "@id": "http://xmlns.com/foaf/0.1/knows", "@type": "@id" },
"Person": "http://xmlns.com/foaf/0.1/Person"
},
"@id": "http://example.org/alice",
"@type": "Person",
"name": "Alice Smith",
"knows": { "@id": "http://example.org/bob" }
}
2.4 序列化选型
| 格式 | 可读性 | 生态 | 适用 |
|---|---|---|---|
| Turtle | ★★★★ | 好 | 手写数据、教学 |
| RDF/XML | ★★ | 标准 | 老系统、协议交换 |
| JSON-LD | ★★★ | Web 原生 | Schema.org、前端嵌入 |
| N-Triples | ★★ | 好 | 流式大文件 |
一句话总结:序列化只是同一张图的表达——教学手写用 Turtle、Web 集成用 JSON-LD、协议交换用 RDF/XML,底层三元组完全等价。
3. 命名空间与 IRI:全球唯一标识
3.1 为什么需要 IRI
RDF 的宾语主语用 IRI(国际资源标识符)保证「同一个资源在任何数据集里都指向同一个东西」:
http://example.org/people/alice
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
IRI = 全局唯一、可反引(URL)、可被语义网互联
3.2 前缀缩写(prefix)
@prefix dbo: <http://dbpedia.org/ontology/> . # DBpedia 本体
@prefix dbr: <http://dbpedia.org/resource/> . # DBpedia 资源
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
dbr:Beijing a dbo:City ;
dbo:country dbr:China ;
dbo:population "21540000"^^xsd:integer .
3.3 常用标准命名空间
| 前缀 | IRI | 用途 |
|---|---|---|
| rdf | …/02/22-rdf-syntax-ns# | type, Property, … |
| rdfs | …/02/22-rdf-schema-ns# | Class, subClassOf, label |
| owl | …/02/owl# | 本体推理 |
| foaf | http://xmlns.com/foaf/0.1/ | 人物社交 |
| schema | https://schema.org/ | 通用 Web 数据 |
| dcterms | http://purl.org/dc/terms/ | 元数据 |
| xsd | http://www.w3.org/2001/XMLSchema# | 数据类型 |
一句话总结:IRI 让 RDF 真正「互联」——同一个 IRI 在不同数据集中就是同一个实体,前缀缩写只是书写便利,语义上完全等价。
4. RDFS 与 OWL:本体建模
4.1 RDFS:轻量类型与层级
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ex:Person rdfs:subClassOf ex:Agent . # 类别层级
ex:knows rdfs:domain ex:Person ;
rdfs:range ex:Person . # 谓词约束
ex:name rdfs:subPropertyOf ex:label . # 属性层级
4.2 OWL:更强约束与推理
@prefix owl: <http://www.w3.org/2002/07/owl#> .
# 类的等价与不相交
ex:Employee owl:equivalentClass ex:Staff .
ex:Cat owl:disjointWith ex:Dog .
# 属性特性
ex:marriedTo a owl:ObjectProperty ;
owl:inverseOf ex:marriedTo ; # 对称
owl:SymmetricProperty . # 若 a 认识 b 则 b 认识 a
ex:isParentOf a owl:TransitiveProperty . # 传递:爷爷→爸爸→儿子
4.3 本体推理能干什么
输入:ex:alice ex:isParentOf ex:bob .
ex:bob ex:isParentOf ex:carol .
OWL 推理:ex:alice ex:isParentOf ex:carol . ← TransitiveProperty 推导
ex:alice a ex:Person . ← 由 rdfs:domain 推导
ex:carol a ex:Person . ← 由 rdfs:range 推导
一句话总结:RDFS 定义「类和层级」,OWL 定义「约束和推理规则」——本体的价值在于让机器从显式数据推导出隐式知识。
5. SPARQL 四大查询形式
5.1 SELECT:返回变量表
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name WHERE {
?person foaf:name ?name .
?person foaf:knows ?friend .
}
LIMIT 10
5.2 CONSTRUCT:返回一张新图
# 从已知图「构造」社交图谱子图
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT { ?person foaf:knows ?friend }
WHERE { ?person foaf:knows ?friend }
5.3 ASK:返回布尔
# 问:是否存在 Alice 认识 Bob 的三元组?
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
ASK { ex:alice foaf:knows ex:bob }
# → true / false
5.4 DESCRIBE:返回资源描述图
PREFIX ex: <http://example.org/>
DESCRIBE ex:alice
# → 返回 alice 的所有三元组(由实现决定范围)
5.5 四大形式对比
| 形式 | 返回 | 用途 |
|---|---|---|
| SELECT | 值绑定表 | 数据分析、取数 |
| CONSTRUCT | RDF 图 | 图转换、API 输出 |
| ASK | true/false | 存在性判断 |
| DESCRIBE | RDF 图 | 资源全貌展示 |
一句话总结:SELECT 取数、CONSTRUCT 造图、ASK 判存在、DESCRIBE 看全貌——SPARQL 四大形式覆盖查询的四种目标。
6. SPARQL 进阶:FILTER、聚合与属性路径
6.1 FILTER 与值约束
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?city WHERE {
?city a dbo:City ;
dbo:country dbr:China ;
dbo:population ?pop .
FILTER (?pop > 10000000)
}
ORDER BY DESC(?pop)
6.2 聚合 GROUP BY
# 每个国家有多少城市、平均人口
SELECT ?country (COUNT(?city) AS ?count) (AVG(?pop) AS ?avgPop)
WHERE {
?city a dbo:City ;
dbo:country ?country ;
dbo:population ?pop .
}
GROUP BY ?country
HAVING (COUNT(?city) > 5)
ORDER BY DESC(?count)
6.3 属性路径(类似 Cypher 变长路径)
# 朋友的朋友(路径长度 2)
SELECT DISTINCT ?friend WHERE {
ex:alice foaf:knows/foaf:knows ?friend .
}
# 传递闭包(任意长度,对应 TransitiveProperty)
SELECT ?descendant WHERE {
ex:grandpa ex:isParentOf+ ?descendant .
}
| 路径语法 | 含义 |
|---|---|
p/q | 复合路径(先 p 再 q) |
p+ | 一个或多个 p |
p* | 零个或多个 p |
p^ | 反向路径 |
| `(p | q)` |
6.4 UNION 与 OPTIONAL
SELECT ?person ?name ?email WHERE {
{ ?person a foaf:Person . ?person foaf:name ?name . }
UNION
{ ?person a foaf:Person . ?person foaf:mbox ?email . }
# OPTIONAL:可缺失的绑定(左连接)
OPTIONAL { ?person foaf:homepage ?homepage . }
}
一句话总结:FILTER 约束值、GROUP BY 聚合、属性路径表达多跳遍历、OPTIONAL 做左连接——SPARQL 进阶四件套覆盖了图查询的大多数真实需求。
7. SPARQL 更新与推理
7.1 INSERT/DELETE 更新
# 插入新三元组
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
INSERT DATA { ex:carol a foaf:Person ; foaf:name "Carol" . }
# 带条件的更新:把 Alice 的年龄加一
DELETE { ex:alice foaf:age ?old . }
INSERT { ex:alice foaf:age ?new . }
WHERE {
ex:alice foaf:age ?old .
BIND(?old + 1 AS ?new)
}
7.2 推理(Reasoning)
推理可让查询「少写条件」:
# 开启推理前:查不到「孙子」——需要显式 2 跳
SELECT ?grandchild WHERE { ex:grandpa ex:isParentOf ?m .
?m ex:isParentOf ?grandchild . }
# 开启推理后(如 Jena OWL reasoner、Virtuoso inference):
# isParentOf 声明为 TransitiveProperty → 直接查 1 跳即可
SELECT ?grandchild WHERE { ex:grandpa ex:isParentOf ?grandchild . }
7.3 推理 vs 物化
推理(inference):查询时动态推导 → 数据不变、查询慢
物化(materialize):提前把推导结果写入图 → 查询快、数据膨胀
N-Triples 大图常用物化;交互式场景用推理
一句话总结:SPARQL 更新直接改三元组,推理让「声明即查询」——TransitiveProperty 等 OWL 约束能在查询层自动补出隐式关系,推理与物化的取舍是性能与灵活性的权衡。
8. Jena/Virtuoso 实战:从数据到查询
8.1 Jena 的 TDB 存储 + ARQ 查询(Java/Java 生态)
// 1. 加载 Turtle 到 TDB
import org.apache.jena.query.*;
import org.apache.jena.rdf.model.*;
import org.apache.jena.tdb2.TDB2Factory;
Dataset ds = TDB2Factory.createDataset("data/tdb");
ds.begin(ReadWrite.WRITE);
Model model = ds.getDefaultModel();
model.read("data/people.ttl", "TTL"); // 读入 Turtle
ds.commit();
// 2. SPARQL 查询
String queryStr =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/> " +
"SELECT ?name WHERE { ?p foaf:name ?name } " +
"ORDER BY ?name";
try (QueryExecution qexec = QueryExecutionFactory.create(queryStr, model)) {
ResultSet results = qexec.execSelect();
results.forEachRemaining(row ->
System.out.println(row.get("name").asLiteral().getString()));
}
8.2 Virtuoso(SPARQL 端点)
# 加载 Turtle
isql-vt
SQL> DB.DBA.TTLP_LOAD_FILE('/data/people.ttl', 'http://example.org/', 0);
# SPARQL 端点即服务 HTTP 查询
curl -X POST "http://localhost:8890/sparql" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'query=PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ?name WHERE { ?p foaf:name ?name }'
8.3 基于 Wikidata SPARQL 的实例查询
# Wikidata 端点实战:人口超过 1000 万的中国城市
SELECT ?city ?cityLabel ?pop WHERE {
?city wdt:P31 wd:Q515 . # 实例=城市
?city wdt:P17 wd:Q148 . # 国家=中国
?city wdt:P1082 ?pop . # 人口
FILTER(?pop > 10000000)
SERVICE wikibase:label { bd:serviceParam wikibase:language "zh". }
}
ORDER BY DESC(?pop)
8.4 技术栈速览
| 组件 | 角色 |
|---|---|
| Jena TDB | Java 图存储 |
| ARQ | SPARQL 查询引擎 |
| Fuseki | Jena 的 SPARQL 服务器 |
| Virtuoso | 高性能 RDF 数据库 + 端点 |
| rdf4j | Java RDF 框架 |
| rdflib | Python RDF 库 |
| Blazegraph | 图存储(Wikidata 曾用) |
一句话总结:落地 RDF 的路径很统一——用 Turtle/JSON-LD 建数据,加载进 Jena/Virtuoso 存储,再用 SPARQL 查询;端点上可直接对接 Wikidata 等开放数据。
9. RDF vs 属性图:选型对照
| 维度 | RDF | 属性图(Neo4j) |
|---|---|---|
| 建模单元 | 三元组 | 节点/关系/属性 |
| 关系属性 | 需重定标 | 原生支持 |
| 推理 | OWL/RDFS 原生 | 需自己实现 |
| 开放互操作 | Linked Open Data 天然 | 弱 |
| 查询语言 | SPARQL | Cypher / GQL |
| 标准性 | W3C 全套标准 | 厂商标准(GQL 新标准) |
| 擅长 | 科研、开放数据、跨域集成 | 应用内关系分析、性能 |
| 学习曲线 | 较陡 | 相对平缓 |
选型建议:
需要跨组织数据互通、语义推理、开放链接 → RDF + SPARQL
应用内业务关系分析、性能敏感、关系属性多 → 属性图
数据要先建本体、长期开放共享 → RDF
一句话总结:RDF 胜在「开放与推理」,属性图胜在「性能与关系属性」——研究性、开放域选 RDF,业务型、关系分析选属性图,两者可互补。
10. 速查表
| 需求 | 做法 |
|---|---|
| 建模最小单元 | 主语-谓语-宾语三元组 |
| 序列化 | Turtle / RDF-XML / JSON-LD |
| 全局唯一 | IRI + 前缀缩写 |
| 类别层级 | RDFS subClassOf |
| 推理规则 | OWL(Transitive/Symmetric) |
| 取数查询 | SELECT |
| 构造图 | CONSTRUCT |
| 判存在 | ASK |
| 看全貌 | DESCRIBE |
| 多跳遍历 | 属性路径 p+ |
| 推理 | Jena reasoner / Virtuoso inference |
| 存储 | Jena TDB / Virtuoso / rdflib |
一句话记忆:RDF 用三元组统一表达知识、IRI 保证全局唯一、RDFS/OWL 提供类别与推理;SPARQL 四形式 SELECT/CONSTRUCT/ASK/DESCRIBE 各司其职,FILTER/聚合/属性路径管进阶;落地用 Jena/Virtuoso,开放数据直连 Wikidata——RDF 面向「开放与推理」、属性图面向「性能与关系属性」,按场景选型。
延伸阅读
- /graphdb-data-model-basics/ — 属性图 vs RDF 三元组
- /graphdb-knowledge-graph/ — 知识图谱与本体应用
- /graphdb-knowledge-graph-practice/ — 图谱构建流水线
- /graphdb-modeling-patterns/ — 图建模思维
- /graphdb-neo4j-cypher-guide/ — 属性图查询对比
- [[ai-ml]] — 语义网与知识推理
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。