实验环境 系统: ubuntu16.04
软件目录:
项目目录/home/gao/software/kgdemo/
数据库/home/gao/software/mysql
应用框架/home/gao/software/apache-jena-3.6.0(这里使用了它的TDB组件
SPARQL服务器/home/gao/software/apache-jena-fuseki-3.6.0
数据转化工具/home/gao/software/d2rq-0.8.1
本体构建工具/home/gao/software/Protege-5.2.0
准备 数据 与电影相关的.基本统计数据如下:
演员数量:505人
电影数量:4518部
电影类型:19类
人物与电影的关系:14451
电影与类型的关系:7898
演员的基本信息包括:姓名、英文名、出生日期、死亡日期、出生地、个人简介. 电影的基本信息包括:电影名称、电影简介、电影评分、电影发行日期、电影类型.
本体建模
打开protege,在Ontology IRI中填写新建本体资源的IRI为”http://www.kgmovie.demo.com “
1 2 # 进入protege目录,执行下面的命令 ./run.sh
点击“Entities”tab标签,选择“Classes”标签.在这个界面,我们创建电影知识图谱的类/概念.
在owl:Thing下创建三个子类,Person,Movie,Genre.三个类的默认关系是互斥的.
切换到”Object Properties”页面创建类之间的关系,即,对象属性 。
创建了三个对象属性,”hasActedIn”表示某人参演了某电影,该属性的”domain”是人,”range”是电影。(“domain”表示该属性是属于哪个类的,”range”表示该属性的取值范围 ),设置该属性的逆属性(Inverse of)是”hasActor”,可用于推理.另外一个属性”hasGenre”表示电影属于什么类型.
切换到”Data properties”页面创建类的属性,即,数据属性 .
其实区分数据属性和对象属性还有一个很直观的方法,我们观察其”range”取值范围即可.
对象属性的取值范围是类,而数据属性的取值范围则是字面量.
保存文件,命名为”kgdemo.owl”
注意到,mysql中有五个表,本体中只有三个类
数据转换 mysql -> RDF
下载D2RQ,进入其目录,运行下面的命令生成默认的 mapping文件:
1 ./generate-mapping -u <username> -p <password> -o ../kgdemo/kg_demo_movie_mapping.ttl jdbc:mysql:///kg_demo_movie
根据我们定义的本体修改mapping文件
ttl文件中添加前缀: @prefix : http://www.kgmovie.demo.com# .(包括最后的这个句号)
去除没用的genre__label和genre_genre_id信息
vocab:xxxx 换成了本体构建时候的类
d2rq:property属性修改为本体中定义的属性(对象属性或者数据属性)
数据转为RDF
1 ./dump-rdf -o ../kgdemo/kg_demo_movie.nt ../kgdemo/kg_demo_movie_mapping.ttl
查询示例
1 2 3 4 5 6 7 SELECT ?titles WHERE { ?p rdf:type :Person. ?p :personEnglishName 'Stephen Chow' . ?p :hasActedIn ?movies. ?movies :movieTitle ?titles } limit 10
返回结果为:
titles
“功夫”
“琉璃樽”
“英雄本色”
“少林足球”
“西游记第壹佰零壹回之月光宝盒”
“长江七号”
“西游记大结局之仙履奇缘”
“建国大业”
“审死官”
“龙在天涯”
Bug To Fix 使用中文姓名查询不到person
jena SPARQL endpoint及推理 jena示例
下载apache-jena和apache-jena-fuseki
在apache-jena目录下,使用“tdbloader”将之前我们的RDF数据以TDB的方式存储。命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ./tdbloader --loc="../../kgdemo/tdb" "../../kgdemo/kg_demo_movie.nt" 16:15:50 INFO loader :: -- Start triples data phase 16:15:50 INFO loader :: ** Load empty triples table 16:15:50 INFO loader :: -- Start quads data phase 16:15:50 INFO loader :: ** Load empty quads table 16:15:50 INFO loader :: Load: ../../kgdemo/kg_demo_movie.nt -- 2018/03/19 16:15:50 CST 16:15:52 INFO loader :: -- Finish triples data phase 16:15:52 INFO loader :: ** Data: 47,144 triples loaded in 1.26 seconds [Rate: 37,327.00 per second] 16:15:52 INFO loader :: -- Finish quads data phase 16:15:52 INFO loader :: -- Start triples index phase 16:15:52 INFO loader :: ** Index SPO->POS: 47,144 slots indexed in 0.14 seconds [Rate: 334,354.63 per second] 16:15:52 INFO loader :: ** Index SPO->OSP: 47,144 slots indexed in 0.13 seconds [Rate: 374,158.72 per second] 16:15:52 INFO loader :: -- Finish triples index phase 16:15:52 INFO loader :: ** 47,144 triples indexed in 0.27 seconds [Rate: 172,688.64 per second] 16:15:52 INFO loader :: -- Finish triples load 16:15:52 INFO loader :: ** Completed: 47,144 triples loaded in 1.55 seconds [Rate: 30,356.73 per second] 16:15:52 INFO loader :: -- Finish quads load
在fuseki-server目录下,运行 ./fuseki-server 服务,会在当前目录生成run文件夹,将本体文件重命名为”kgdemo.ttl”放入run/database,然后在run/configuration里创建config.ttl文件,内容为:
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 @prefix : <http://base/#> . @prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix fuseki: <http://jena.apache.org/fuseki#> . :service1 a fuseki:Service ; fuseki:dataset <#dataset> ; fuseki:name "kg_demo_movie" ; fuseki:serviceQuery "query" , "sparql" ; fuseki:serviceReadGraphStore "get" ; fuseki:serviceReadWriteGraphStore "data" ; fuseki:serviceUpdate "update" ; fuseki:serviceUpload "upload" . <#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph <#model_inf> ; . <#model_inf> a ja:InfModel ; ja:baseModel <#tdbGraph> ; #本体文件的路径 ja:content [ja:externalContent <file:////home/gao/software/apache-jena-fuseki-3.6.0/run/databases/kgdemo.ttl> ] ; #启用OWL推理机 ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] . <#tdbGraph> rdf:type tdb:GraphTDB ; tdb:dataset <#tdbDataset> ; . <#tdbDataset> rdf:type tdb:DatasetTDB ; tdb:location "/home/gao/software/kgdemo/tdb" ;
1 2 3 4 5 6 7 8 [2018-03-19 16:39:13] Server INFO Apache Jena Fuseki 3.6.0 [2018-03-19 16:39:13] Config INFO FUSEKI_HOME=/home/gao/software/apache-jena-fuseki-3.6.0 [2018-03-19 16:39:13] Config INFO FUSEKI_BASE=/home/gao/software/apache-jena-fuseki-3.6.0/run [2018-03-19 16:39:13] Config INFO Shiro file: file:///home/gao/software/apache-jena-fuseki-3.6.0/run/shiro.ini [2018-03-19 16:39:13] Config INFO Configuration file: /home/gao/software/apache-jena-fuseki-3.6.0/run/config.ttl [2018-03-19 16:39:13] Config INFO Load configuration: file:///home/gao/software/apache-jena-fuseki-3.6.0/run/configuration/conf.ttl [2018-03-19 16:39:13] Config INFO Register: /kg_demo_movie [2018-03-19 16:39:13] Server INFO Started 2018/03/19 16:39:13 CST on port 3030
打开页面localhost:3030,查询,这里使用中文ok
1 2 3 4 5 6 7 8 9 10 11 12 PREFIX rdf: < http:/ / www.w3.org/ 1999 / 02 / 22 - rdf- syntax- ns#> prefix rdfs: < http:/ / www.w3.org/ 2000 / 01 / rdf- schema#> prefix owl: < http:/ / www.w3.org/ 2002 / 07 / owl#> prefix : < http:/ / www.kgmovie.demo.com#> SELECT ?titles WHERE { ?p rdf:type :Person. ?p :personName '周星驰' . ?p :hasActedIn ?movies. ?movies :movieTitle ?titles } limit 10
titles
1
“琉璃樽”
2
“西游记第壹佰零壹回之月光宝盒”
3
“大内密探零零发”
4
“功夫”
5
“长江七号”
6
“回魂夜”
7
“百变星君”
8
“英雄本色”
9
“建国大业”
10
“唐伯虎点秋香”
自定义推理规则
在“databases”文件夹下新建一个文本文件“rules.ttl”,填入如下内容:
1 2 3 4 5 6 7 8 @prefix : <http://www.kgmovie.demo.com#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix xsd: <XML Schema> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . [ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)] [ruleInverse: (?p :hasActedIn ?m) -> (?m :hasActor ?p)]
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 @prefix : <http://base/#> . @prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix fuseki: <http://jena.apache.org/fuseki#> . :service1 a fuseki:Service ; fuseki:dataset <#dataset> ; fuseki:name "kg_demo_movie" ; fuseki:serviceQuery "query" , "sparql" ; fuseki:serviceReadGraphStore "get" ; fuseki:serviceReadWriteGraphStore "data" ; fuseki:serviceUpdate "update" ; fuseki:serviceUpload "upload" . <#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph <#model_inf> ; . <#model_inf> a ja:InfModel ; ja:baseModel <#tdbGraph> ; #本体文件的路径 ja:content [ja:externalContent <file:////home/gao/software/apache-jena-fuseki-3.6.0/run/databases/kgdemo.ttl> ] ; #关闭OWL推理机 #ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] . #开启规则推理机,并指定规则文件路径 ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; ja:rulesFrom <file:////home/gao/software/apache-jena-fuseki-3.6.0/run/databases/rules.ttl> ; ] . <#tdbGraph> rdf:type tdb:GraphTDB ; tdb:dataset <#tdbDataset> ; . <#tdbDataset> rdf:type tdb:DatasetTDB ; tdb:location "/home/gao/software/kgdemo/tdb" ; .
1 2 3 4 5 SELECT n WHERE {?x rdf:type :Comedian. ?x :personName ?n. } limit 10
结果如下:
n
1
“邓浩光”
2
“梁朝伟”
3
“杨恭如”
4
“梁韵蕊”
5
“吴宇森”
6
“徐锦江”
7
“黄家驹”
8
“叶进”
9
“午马”
10
“梁咏琪”
TODO 不用sparql,用natural language查询结果 query-answer