知识图谱小demo

实验环境

系统:
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

准备

数据

与电影相关的.基本统计数据如下:

  1. 演员数量:505人
  2. 电影数量:4518部
  3. 电影类型:19类
  4. 人物与电影的关系:14451
  5. 电影与类型的关系: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" ;
  • 重启运行 ./fuseki-server
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)]
  • 修改juseki-server配置文件:
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