3. SPARQL 查询入门:SELECT 语句与基本模式匹配

好,我们终于开始写真正的查询了。前面两章把 RDF 和 SPARQL 的背景铺了一遍,可能你觉得有点虚。这一章我们直接上手,用 SELECT 语句从药物图谱里把数据“拽”出来。

SELECT 是 SPARQL 里最常用的查询形式。说白了,它有点像 SQL 里的 SELECT,但又不完全一样。核心区别在于——SPARQL 查的是图,不是表。你想想看,图数据没有固定的列,你得用“三元组模式”去描述你要找的东西长什么样。

3.1 SELECT 语句的基本骨架

一个最简单的 SELECT 查询长这样:

SELECT ?药物 ?靶点
WHERE {
  ?药物 rdf:type <http://example.org/drug> .
  ?药物 <http://example.org/target> ?靶点 .
}

嗯,来拆解一下。

  • SELECT 子句:列出你关心的变量。变量用问号开头,比如 ?药物、?靶点。
  • WHERE 子句:里面放一组三元组模式。这些模式就是你要在图里匹配的“路标”。
  • 三元组模式:主语、谓语、宾语。每个位置可以是具体 URI、字面量,也可以是变量。
我个人的习惯:变量名尽量用中文或英文有意义的名词,别用 ?a、?b。虽然 SPARQL 不限制,但几个月后回头看,你大概率会忘记 ?x 到底代表什么东西。

3.2 基本模式匹配的工作原理

SPARQL 引擎是怎么工作的?它会把 WHERE 里的每个三元组模式,拿到 RDF 图里去做子图匹配。

举个例子。假设药物图谱里有这么几条数据:

<http://example.org/drug/阿司匹林> rdf:type <http://example.org/drug> .
<http://example.org/drug/阿司匹林> <http://example.org/target> <http://example.org/protein/COX-1> .
<http://example.org/drug/阿司匹林> <http://example.org/target> <http://example.org/protein/COX-2> .

当你运行上面的 SELECT 查询时,引擎会做三件事:

  1. 找到所有类型是 drug 的节点——这里匹配到“阿司匹林”。
  2. 对每个 drug 节点,找到它的 target 属性值——这里找到 COX-1 和 COX-2。
  3. 把匹配到的变量值组合成结果行。

结果就是两行:

?药物              ?靶点
阿司匹林          COX-1
阿司匹林          COX-2
关键点:SPARQL 的模式匹配默认是 AND 逻辑。所有三元组模式必须同时成立,结果才会被返回。

3.3 避坑:前缀声明的重要性

你肯定不想每次写 URI 都写全长。太痛苦了。SPARQL 提供了 PREFIX 关键字。我记得刚开始写查询时,总是忘记加前缀声明,结果查了半天什么也没返回……

PREFIX d: <http://example.org/drug/>
PREFIX p: <http://example.org/protein/>
PREFIX vocab: <http://example.org/>

SELECT ?药物 ?靶点
WHERE {
  ?药物 rdf:type vocab:drug .
  ?药物 vocab:target ?靶点 .
}

这里我定义了三个前缀:d: 用于药物,p: 用于蛋白,vocab: 用于命名空间。注意,rdf:type 是 SPARQL 内置前缀 rdf:,不用自己声明。

我曾经踩过的坑:前缀声明里冒号后面不要漏掉空格。写 PREFIX d:<http://...> 是错的,必须写成 PREFIX d: <http://...>。这个空格很容易被忽略,但丢了 SPARQL 解析器会报错。

另外,前缀只是别名,不会改变查询语义。引擎在内部会把前缀展开成完整 URI。

3.4 使用 FILTER 缩小结果范围

大部分时候你不需要所有数据。你想查“靶点是 COX-1 的药物有哪些?”这时就要用 FILTER。

PREFIX vocab: <http://example.org/>

SELECT ?药物
WHERE {
  ?药物 rdf:type vocab:drug .
  ?药物 vocab:target ?靶点 .
  FILTER(?靶点 = <http://example.org/protein/COX-1>)
}

FILTER 里可以写各种条件:

  • 字符串比较:FILTER(CONTAINS(?药物名称, "阿司匹林"))
  • 数值比较:FILTER(?分子量 > 300)
  • 逻辑组合:FILTER(?a > 10 && ?b < 20)

你想想看,没有 FILTER 的话,你只能返回所有数据,然后在应用层过滤——效率太低了。数据量一上来,网络传输就是瓶颈。

3.5 本章知识结构

下面的 SVG 把 SELECT 查询的核心流程画出来了。从“发现目标”到“写出三元组模式”,再到“添加过滤条件”,最后“获取结果”。

SELECT 查询基本流程 1. 发现查询目标 2. 定义 PREFIX 3. 写 SELECT 变量 4. 写三元组模式 5. 添加 FILTER 6. 获取结果 注意 三元组模式顺序不重要 引擎会自行优化匹配 但要保证变量名一致

3.6 常见新手问题

问题 原因 解决方法
查询返回空结果 URI 写错或前缀未声明 检查前缀声明和 URI 是否与数据一致
变量名拼写不一致 WHERE 里用了 ?protein,SELECT 里写了 ?protien 养成复制变量名的习惯
忘记加 . 号 每个三元组模式必须以 . 结束(最后一个可选) 写模式时统一加 . 号
我建议:刚开始练习时,用 SPARQL 提供的可视化查询编辑器(比如 Apache Jena Fuseki 的 Web UI)。它能实时显示查询结果,直观看到模式匹配的效果。等你熟练了再用编程方式调用。

嗯,这一章的内容先到这里。SELECT 和基本模式匹配是 SPARQL 的基石。后面的 JOIN、OPTIONAL、UNION 都是在这一层基础上叠加的。把这几步练熟,后面的路就好走了。