借助语义技术构建 Wikipedia 查询表单 -3 构建应用程序
- UID
- 1066743
|
借助语义技术构建 Wikipedia 查询表单 -3 构建应用程序
构建应用程序第一个应用程序的目的是为了体现 linkedmdb.org 数据库和 SPARQL 查询语言的益处,而将实际的查询和 URI 对应用程序的用户隐藏起来。就上述系统的基础架构而言,
- 应用程序用户利用 图 1 所示的表单输入两个导演的名字。
图 1. commonActors 应用程序的输入表单 - 表单将这两个导演的名字传递给 commonActors.cgi CGI 脚本。
- CGI 脚本将这两个导演的名字插入 SPARQL 查询并将此查询发送至位于 http://data.linkedmdb.org/sparql 的 linkedmdb.org SPARQL 端点。
- SPARQL 端点返回 JSON 版本的结果,CGI 脚本围绕所返回的数据构建一个 HTML 页面并将页面发送至用户的浏览器。
所示的这个 SPARQL 查询将被发送并硬编码,以索询有关 Sofia 和 Francis Ford Coppola 的信息:
清单 3. SPARQL 查询用来列出 Sofia 和 Francis Ford Coppola 电影中共用的演员1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| PREFIX m: <http://data.linkedmdb.org/resource/movie/>
SELECT DISTINCT ?actorName WHERE {
?dir1 m:director_name "Sofia Coppola".
?dir2 m:director_name "Francis Ford Coppola".
?dir1film m:director ?dir1;
m:actor ?actor.
?dir2film m:director ?dir2;
m:actor ?actor.
?actor m:actor_name ?actorName.
}
|
如果将这个查询粘贴至 linkedmdb.org 的 SNORQL 接口,您将发现只有 Kathleen Turner 曾出现在由这两位导演各自执导的电影中。
存储于 commonActors.html 文件内的 Web 输入表单(您可以在 自己进行尝试)将所输入的导演姓名分别分配给变量 dir1 和 dir2,而这二者又被传递给 commonActors.cgi 脚本。
清单 4. commonActors 应用程序的 Web 输入表单1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Find common actors between two directors</title>
<link href="simple.css" type="text/css" rel="stylesheet" />
</head>
<body>
<h1>Find common actors between two directors</h1>
<form action="commonActors.cgi" method="get">
<p>Enter the "official" name of each director (check
<a href="http://www.imdb.com">IMDB</a> if you're not sure)
and click "Search" to list actors who have appeared in movies by
both directors.</p>
<p>
<input type="text" name="dir1"/>
<input type="text" name="dir2"/>
<input type="submit" value="search"/>
</p>
</form>
</body>
</html>
|
SPARQL 端点的一个妙处是:通过一个基于 REST 的 HTTP 接口,您可以与所有端点通信,但 Web 搜索应该提供一个针对您采用的编程语言的更为简单的接口。我用 Python 编写 commonActors.cgi CGI 脚本并使用 SPARQLWrapper 库来简化查询的发送和对结果的解包。
清单 5. commonActors 应用程序的 Python 脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| #!/usr/local/bin/python
import sys
sys.path.append('/usr/home/bobd/lib/python/') # needed for hosted version
from SPARQLWrapper import SPARQLWrapper, JSON
import string
import urllib
import cgi
def main():
form = cgi.FieldStorage()
dir1name = form.getvalue('dir1')
dir2name = form.getvalue('dir2')
sparql = SPARQLWrapper("http://data.linkedmdb.org/sparql")
queryString = """
PREFIX m: <http://data.linkedmdb.org/resource/movie/>
SELECT DISTINCT ?actorName WHERE {
?dir1 m:director_name "DIR1-NAME".
?dir2 m:director_name "DIR2-NAME".
?dir1film m:director ?dir1;
m:actor ?actor.
?dir2film m:director ?dir2;
m:actor ?actor.
?actor m:actor_name ?actorName.
}
"""
queryString = queryString.replace("DIR1-NAME",dir1name)
queryString = queryString.replace("DIR2-NAME",dir2name)
sparql.setQuery(queryString)
sparql.setReturnFormat(JSON)
try:
ret = sparql.query()
results = ret.convert()
requestGood = True
except Exception, e:
results = str(e)
requestGood = False
print """Content-type: text/html
<html>
<head>
<title>results</title>
<link href="simple.css" type="text/css" rel="stylesheet" />
</head>
<body>
"""
if requestGood == False:
print "<h1>Problem communicating with the server</h1>"
print "<p>" + results + "</p>"
elif (len(results["results"]["bindings"]) == 0):
print "<p>No results found.</p>"
else:
for result in results["results"]["bindings"]:
print "<p>" + result["actorName"]["value"] + "</p>"
print "</body></html>"
main()
|
其中的 sys.path.append 行是必需的,因为当我在一个托管服务上运行上述脚本时,我要用它来告诉托管 Python 编译器我将 SPARQLWrapper 与 JSON 库安装在了什么位置,因为标准的 Python 发行版并不包含 SPARQLWrapper 与 JSON 库。
在导入了这些必需的库并保存了来自 HTML 表单并以 dir1name 与 dir2name 变量传递而来的导演名字值后,此脚本会设置 SPARQL 查询并将其发送给 SPARQL 端点。在创建 SPARQLWrapper 对象(存储于脚本的 sparql 对象中)时,此端点会被一个作为实参传递来的 URL 标识。
保存在 queryString 变量中的查询类似于前面用来索询同时出现在两个导演执导影片中的演员的那个查询,只有一点除外,即在 queryString 变量创建后,DIR1-NAME 和 DIR2-NAME 字符串被 dir1name 和 dir2name 值替代。
在设置了查询字符串和确定了将数据作为 JSON 返回的格式后,try/except 块就会将查询发送给服务器并设置一个 requestGood 变量以指示请求是否成功。在输出了 HTML 页面头后,此脚本的输出有如下三种情况:
- 如果请求不成功,输出一个简单的错误消息。
- 如果查询没有错误,但却未找到结果,就会输出一个 “No results found” 消息。
- 每个演员的名字,作为单一一个 HTML 段落。
脚本的末尾输出 HTML 页面的 body 和 html 元素。 |
|
|
|
|
|