——读懂 GRASP 复现文所需的最小概念集
一句话结论:RDF 把每个地图对象拆成一堆带编号的短句,SPARQL 拿带空格的短句去匹配它们,而模型写错查询几乎都栽在谓词拼写上。本文展开回答三个问题:RDF 怎么把地图数据存成短句?SPARQL 怎么按这些短句查东西?为什么模型常常写不对查询?全部例子的谓词和标签值取自 OpenStreetMap(OSM)经 osm2rdf 转换后的真实数据;节点、路径、关系的编号为教学构造。
用词约定(三篇通用)
| 本文叫法 | 英文与别名 | 说明 |
|---|---|---|
| 三元组 | triple(主语—谓语—宾语短句) | RDF 里数据的基本单位 |
| 对象 | resource / entity | 有编号的东西,可站主语位,也可站宾语位 |
| 谓词 | predicate(字段名、属性名) | 谓语位置的东西 |
| 字面量 | literal(字符串、数字等纯值) | 只能站宾语位 |
| 成员记录 | member blank node | osm2rdf 用来保存顺序的中转节点 |
| 前缀 | prefix | 一长串网址的缩写,冒号前那段 |
一、RDF:把一条记录拆成若干短句
1.1 三元组
RDF(Resource Description Framework,资源描述框架,W3C 标准 [1])只有一条规矩:所有信息写成"主语—谓语—宾语"的短句,一句就是一个三元组。全球 OSM 数据转成 RDF 后是几百亿句这样的短句。
主语和谓词必有编号(网址)。宾语分两种:可以是编号对象,也可以是字面量——字面量没有编号。平时写前缀缩写,例如osmnode:61785451表示https://www.openstreetmap.org/node/61785451。
1.2 节点、路径、关系长什么样
点的例子(OSM 节点,如一个城市的标注点):
osmnode:61785451 osmkey:name "New York City" . osmnode:61785451 osmkey:place "city" . osmnode:61785451 geo:hasGeometry [ geo:asWKT "POINT(-73.98 40.76)"^^geo:wktLiteral ] .线的例子(OSM 路径,如一条叫南京路的街道):
osmway:1000 osmkey:highway "residential" . osmway:1000 osmkey:name "Nanjing Road" . osmway:1000 osmway:member _:m0 . _:m0 osmway:member_id osmnode:500 . _:m0 osmway:member_pos "0"^^xsd:integer .说明:
osmkey:highway是道路分类标签,"residential"表示居民区道路。- 节点不直接挂在路径上。路径先用
osmway:member指向一条成员记录(如_:m0),成员记录再用osmway:member_id指向具体节点、用osmway:member_pos标出顺序。只有这样,节点在线中的先后位置才存得下来。
- 节点不直接挂在路径上。路径先用
- 在 OSM 原始数据里,路径的组成单位叫节点(node);osm2rdf 在 RDF 层统一用
member这套谓词表达"某个元素属于另一个元素"。所以路径里没有 OSM 意义上的"成员",别被谓词名误导。
面的例子(OSM 关系,如芝加哥市界):
- 在 OSM 原始数据里,路径的组成单位叫节点(node);osm2rdf 在 RDF 层统一用
osmrel:122604 osmkey:name "Chicago" . osmrel:122604 osmkey:admin_level "8" . osmrel:122604 osm2rdf:area "588.2"^^xsd:double .面的几何位置有两种存法:简单面可表示为一条首尾闭合的路径;复杂面(如带洞的城市边界)则用关系把多条边拼起来。
1.3 对象与字面量
从上面例子能抽出两条规矩:
- 主语位站对象,谓语位站谓词;宾语可以是对象,也可以是字面量。对象有编号,能在图中继续被指向;谓词是字段名,不能再被展开;字面量到站即止。
- 编号强制,名称可选。每个节点、路径、关系必有编号;名称只是一个可贴可不贴的标签。
1.4 谓词一身二任(属性 vs 关系)
同一个谓词位置,根据宾语不同起两种作用:
- 宾语是字面量时,谓词是属性(property)。例如
osmkey:name "Nanjing Road"、osmkey:highway "residential"。这里的"属性"与关系型数据库里"列"的意思一致:对象的一项特征。 - 宾语是对象时,谓词是关系(relationship)。例如
osmway:member _:m0把路径连到成员记录,osmrel:member_id osmnode:500把成员记录连到节点,ogc:sfContains表达空间包含。这里的"关系"与关系型数据库里"外键/表间关联"的意思一致,也与本体(ontology)里"对象属性(object property)"的意思一致。
属性和关系不是两类谓词,而是同一谓词位置的两种用法。谓词本身不是一条数据,它是字段名;一条三元组才是一条记录。把宾语从字面量换成对象,属性就自然变成了关系。
- 宾语是对象时,谓词是关系(relationship)。例如
二、OSM 标签如何变成谓词
2.1 前缀规则
OSM 原始数据是键值对,例如highway=residential、name=Chicago。osm2rdf 的转换规则很直接:
- 标签键前面拼
osmkey:,变成谓词;值做宾语。例如highway=residential→osmkey:highway "residential"。 - OSM 元素本身用
osmnode:、osmway:、osmrel:做前缀,放在主语位。元素类型靠 URI 前缀区分,而不是rdf:type。
- OSM 元素本身用
- 预计算值用
osm2rdf:前缀,例如osm2rdf:length、osm2rdf:area。
- 预计算值用
- 几何用
geo:hasGeometry指向几何对象,再用geo:asWKT读出 WKT 坐标文本;空间关系用ogc:sf*系列谓词。
注意:这里的主语不是键或标签,而是具体的点、线、面元素。键值对只负责生成"属性"型三元组。
- 几何用
osm2rdf 通常与 QLever(德国弗赖堡大学的 RDF 图数据库)配套使用:osm2rdf 把 OSM 数据转成 RDF,QLever 提供 SPARQL 查询服务。
2.2 路径与关系的成员
路径和关系都引用别的元素,但引用方式略有不同:
| 来源元素 | 引用谓词 | 被指元素 | 顺序/角色 |
|---|---|---|---|
| 路径(way) | osmway:member/osmway:member_id | 节点 | osmway:member_pos |
| 关系(relation) | osmrel:member/osmrel:member_id | 节点/路径/关系 | osmrel:member_pos/osmrel:member_role(如outer、inner) |
沿这些短句一跳一跳地走,就是图结构遍历。例如"路径 1000 的第 2 个节点"要这样跳:
osmway:1000 → osmway:member → _:m2 → osmway:member_pos "2" ↓ osmway:member_id → osmnode:502 ``` ### 2.3 空间关系也是谓词 空间关系写在主语和宾语之间,常见的有: - `ogc:sfIntersects`:相交(对称,A 交 B 与 B 交 A 真值相同)。 - - `ogc:sfContains`:包含(有方向,"芝加哥包含街道"为真,"街道包含芝加哥"为假)。 - - `ogc:sfWithin`:被包含。 - - `ogc:sfTouches`、`ogc:sfOverlaps`、`ogc:sfCrosses`:相触、重叠、穿越。 在 QLever 与 osm2rdf 这套组合里,这些关系的真值在导入阶段就按几何计算好、预存成三元组(QLever 与 PostGIS 的对比详见同目录《地理空间智能前沿-背景知识-关系型数据库与RDF》2.4 节)。不同工具在计算精度和预计算范围上可能有差异,所以"对"或"错"有时取决于用的是哪个端点、哪个版本的数据。 ## 三、SPARQL 查询怎么工作 ### 3.1 变量就是"待填的空格" SPARQL(SPARQL Protocol and RDF Query Language,W3C 标准 [2])是 RDF 的查询语言。写查询时,把想求的值换成以 `?` 开头的变量(variable),数据库会把所有能填进去的结果列成一张表。下面的片段省略了 `PREFIX` 声明和 `SELECT` 子句;实际执行必须先声明前缀,否则直接报错。 **例 1:芝加哥叫什么?** ```sparql osmrel:122604 osmkey:name ?name .模板意思是"找所有『关系 122604 ——名称—— 什么』的短句"。返回一列一行:"Chicago"。
例 2:有名字的报社有哪些?
?x osmkey:office "newspaper" . ?x osmkey:name ?name .两行以同一个?x开头,表示"同一个对象既要满足第一行,也要满足第二行"。返回两列表:对象编号、名字。同一主语的多个条件可缩写为:
?x osmkey:office "newspaper" ; osmkey:name ?name .3.2 多条件与可选项
报社不一定都有名字。直接要求名称会把没名字的丢掉。OPTIONAL { ?x osmkey:name ?name }表示"有就填上,没有留空,行保留"。
3.3 多跳查询
例 3:路径 1000 的第 2 个节点是谁?
osmway:1000 osmway:member ?m . ?m osmway:member_id ?node . ?m osmway:member_pos "2"^^xsd:integer .第一行找到路径 1000 的所有成员记录,第二行从成员记录取出节点编号,第三行限定成员记录的位置序号为 2。三行共享变量?m,合起来表达"路径 1000 中位置序号为 2 的节点"。
也可以用斜杠把前两步合成一行:
osmway:1000 osmway:member / osmway:member_id ?node .但位置序号仍需单独限定,因为它挂在成员记录?m上,而不是节点?node上。
例 4:芝加哥市里有哪些路径?
?street osmkey:highway ?type . osmrel:122604 ogc:sfContains ?street .第一行选出所有带highway标签的要素(绝大多数是路径),第二行限定这些要素被芝加哥市界包含。
3.4 常用算子
FILTER(...):加过滤条件,例如FILTER(?population > 1000000)。GROUP BY+HAVING:分组统计后筛选。
ORDER BY+LIMIT:排序取前 N 行。
ASK {...}:是非题,返回 true/false 而不是表。
geof:distance:计算几何距离;QLever 还有<max-distance-in-meters:30>这类便利写法。
查询结果几乎永远是表(ASK 除外),复杂答案要靠多跳、分组、算式拼出来。
四、写查询为什么这么容易错
4.1 精确匹配:没有"大致对"
SPARQL 是精确查询,谓词必须和数据库里的字段名完全一致。osmway:member能查到东西,osmway:node就查不到;osmkey:highway对,osmkey:road错。差一个字母就全错,没有"大致对",只有"匹配"或"不匹配"。
这和 RAG(检索增强生成,Retrieval-Augmented Generation)检索文字段落不同:RAG 允许语义相近;SPARQL 不允许谓词拼写差一个字母。
4.2 搜索 + 验证是唯一可行的路
模型怎么知道该用哪个谓词?三条路:
- 查数据字典:最可靠,但 OSM 转 RDF 的自定义谓词没有完整手册。
- 搜索工具召回候选,再逐个执行验证:实际主力。输入关键词,返回候选谓词;用小微查询试,能查出东西的才用。
- 按命名习惯猜:最不可靠。GRASP 复现里 GPT-4.1 连猜 8 个不存在的谓词,全军覆没。
全库枚举所有谓词挑一个行不行?不行。在几百亿条三元组上实测超过 180 秒跑不完。所以原则只有一条:搜索给候选,执行做验证,没验证过的不用。
- 按命名习惯猜:最不可靠。GRASP 复现里 GPT-4.1 连猜 8 个不存在的谓词,全军覆没。
4.3 空表陷阱
谓词写错不报错,只返回空表。数据库分不清"这个谓词不存在"和"这个谓词存在但当前没有匹配数据"。拿到空表不能直接下"不存在"的结论——可能是谓词错了,可能是数据里真没有,也可能是搜索工具漏了候选。这是写 SPARQL 最容易踩的坑。
五、RDF 与关系型数据库的对照
关系型数据库里,一个对象通常就是一行记录:一张表包含多行,一行是一个对象,一行有若干列。RDF 里不一样:
- 对象本身不是记录,记录是三元组。描述同一个对象的信息会分散在若干条三元组里,但对象是主语或宾语位置上的那个资源(如
osmway:1000这条路),不是三元组的集合。 - 同一个对象可以出现在很多三元组里。它可以在许多三元组中作主语(挂着名称、标签),也可以在其他三元组中作宾语(如
osmrel:1 ogc:sfContains osmway:1000)。
- 同一个对象可以出现在很多三元组里。它可以在许多三元组中作主语(挂着名称、标签),也可以在其他三元组中作宾语(如
- 谓词相当于字段名,但它不是一条记录。改谓词不动对象本身,只影响查询能不能匹配到它。
记住这个区别:关系型数据库按行把对象的所有信息封装在一起;RDF 把对象的信息拆成许多短句,再通过共享的资源(对象)连成网络。
- 谓词相当于字段名,但它不是一条记录。改谓词不动对象本身,只影响查询能不能匹配到它。
六、索引、形状文档与工具函数
预建索引。事先把对象名和谓词名整理成可快速查找的目录。文本索引按字符串匹配,要求说法准确;向量索引按语义相近召回,搜 “node membership” 也能找到 “member”。GRASP 官方两种都建了 [3][4]。
形状文档。对一类对象的自动统计:这类对象通常带哪些谓词、各取什么值。例如"路径"的形状里会列出osmkey:highway、osmway:member、geo:hasGeometry等。它是从数据里统计出来的数据字典,正好补上"文档不全"的缺口。GRASP 官方代码里有search_shape/get_shape两个工具(本组复现未启用)[4]。
工具函数。查询里可直接调算子:geof:distance算距离(GeoSPARQL / QLever 支持)[6];osm2rdf:length、osm2rdf:area提供预计算的长度和面积 [5]。配合公式就能在查询里做紧凑度、距离等计算。
七、RDF 与大模型:三元组天生适合 NLP 吗?
RDF 三元组是"主语—谓语—宾语"短句,形式上很像自然语言的基本句法。Semantic Web 早期确实有过"用 NLP 直接生成/理解 RDF"的设想。但直到今天,大模型主要在互联网文本上训练,而不是在 RDF 数据上训练,原因很实际:
- 语料规模不对等。互联网文本是万亿 token 级别;公开 RDF 数据集(如 Wikidata、DBpedia)虽然也很大,但总量和多样性仍远小于网页文本。
- URI 是精确符号。大模型擅长文本上的"模糊正确",但 RDF 里的谓词和对象 URI 差一个字符就查不到,模型会虚构 URI。
- Schema 太分散。不同知识图谱用的谓词集合不同,不像自然语言有相对统一的语法。
因此,当前的前沿不是"让大模型直接生成 RDF",而是让大模型把自然语言问题转成正确的 SPARQL,再用 RDF 知识图谱做精确检索。主要方向包括:
- Schema 太分散。不同知识图谱用的谓词集合不同,不像自然语言有相对统一的语法。
- Text-to-SPARQL。研究如何让 LLM 先探索知识图谱(查候选谓词/实体),再生成查询。GRASP 就是这一路线 [3];2025 年 KnowledgeNLP@ACL 的调研显示,给模型提供正确的实体和关系能显著提升查询正确率 [7]。
- GraphRAG。把 RDF/SPARQL 作为结构化检索层,与向量检索混合:先用向量召回相关实体,再用图遍历给出可解释的多跳答案 [8][9]。
- 知识图谱嵌入。把 RDF 中的实体和关系映射成低维向量(如 TransE、ComplEx),用神经网络学习其语义,再辅助链接预测或查询补全 [10]。
- 神经符号混合。有研究直接把张量/嵌入存成 RDF 字面量,扩展 SPARQL 以在查询里做向量运算,把符号推理和神经网络计算连起来 [11]。
一句话:RDF 的句法像自然语言,但使用它需要精确符号;大模型最自然的角色是"翻译官"和"检索调度员",而不是 RDF 的替代品。未来更可能是"LLM 负责模糊理解与编排,RDF/SPARQL 负责精确事实与推理"的混合架构。
- 神经符号混合。有研究直接把张量/嵌入存成 RDF 字面量,扩展 SPARQL 以在查询里做向量运算,把符号推理和神经网络计算连起来 [11]。
Takeaway
回到开头的三个问题:
- RDF 怎么存地图?所有信息写成"主语—谓语—宾语"的三元组;对象靠编号互相指,字面量到站即止;路径和关系的组成靠成员记录中转,顺序单独存。
- SPARQL 怎么查?把想求的值换成
?变量,拿带空格的短句去匹配数据库;多跳靠共享变量,结果永远是表。
- SPARQL 怎么查?把想求的值换成
- 模型为什么写不对?谓词必须逐字母精确,候选只能靠搜索加执行验证,空表不等于"不存在"。
带着这三条去读 GRASP 复现文,两个模型的失败就只剩一句话:正确的谓词osmway:member没有被递到模型手边——一个没认出来,一个没搜到。
- 模型为什么写不对?谓词必须逐字母精确,候选只能靠搜索加执行验证,空表不等于"不存在"。
附录:常用谓词速查
| 类别 | 谓词示例 | 含义 |
|---|---|---|
| 元素判别 | osmnode:/osmway:/osmrel:URI 前缀 | 节点、路径、关系靠前缀区分 |
| 名称标签 | osmkey:name | 名称 |
| 道路分类 | osmkey:highway | 道路类型,如residential、primary |
| 路径节点 | osmway:member/osmway:member_id/osmway:member_pos | 路径引用节点及顺序 |
| 关系成员 | osmrel:member/osmrel:member_id/osmrel:member_pos/osmrel:member_role | 关系引用成员及顺序/角色 |
| 几何 | geo:hasGeometry/geo:asWKT | WKT 格式的几何坐标 |
| 预计算 | osm2rdf:length、osm2rdf:area | 长度、面积 |
| 空间关系 | ogc:sfIntersects、ogc:sfContains、ogc:sfWithin | 相交、包含、被包含 |
参考文献
[1] RDF 1.1 Concepts and Abstract Syntax, W3C Recommendation. https://www.w3.org/TR/rdf11-concepts/
[2] SPARQL 1.1 Query Language, W3C Recommendation. https://www.w3.org/TR/sparql11-query/
[3] Walter, S., & Bast, H. GRASP: A SPARQL Agent for Knowledge Graphs. arXiv:2507.08107(ISWC 2025)。
[4] GRASP 官方代码仓库。https://github.com/ad-freiburg/grasp(2026-08-08 克隆核查)。
[5] osm2rdf 转换工具。https://github.com/ad-freiburg/osm2rdf
[6] QLever 引擎文档。https://github.com/ad-freiburg/qlever
[7] Investigating Large Language Models for Text-to-SPARQL Generation. KnowledgeNLP@ACL 2025。https://aclanthology.org/2025.knowledgenlp-1.5.pdf
[8] Graphwise. What is GraphRAG. 2026-07。https://graphwise.ai/fundamentals/what-is-graph-rag/
[9] semantic-graph-rag: LLM + RDF/OWL + SPARQL experimental framework. GitHub。https://github.com/michel-heon/semantic-graph-rag
[10] Cao, J., Fang, J., Meng, Z., & Liang, S. Knowledge graph embedding: a survey from the perspective of representation spaces. ACM Computing Surveys, 56(6), 1–42 (2024)。https://eprints.gla.ac.uk/307645/
[11] Representing and querying data tensors in RDF and SPARQL. arXiv:2504.19224 (2025)。https://arxiv.org/html/2504.19224v1
版权声明:本文为CSDN