知识图谱---简单实践(学习笔记)

接上篇文章,这篇文章也是基于知乎专栏 https://zhuanlan.zhihu.com/knowledgegraph 的学习笔记。本文主要是梳理一遍专栏中实战的内容,以及就自己遇到的问题备注一下解决方案。感谢原up主与下面热心提供解决问题方案的知乎网友们。

文章目录

  • (一)数据准备和本体建模
    • 1. 数据准备(将sql文件导入MySQL)
    • 2. 本体建模
  • (二)把MySQL中的数据转为RDF
  • (三)SPARQL endpoint 开启与两种交互方式
    • 1. 浏览器中查询
    • 2. 用Python脚本进行交互
  • (四)Apache jena SPARQL endpoint 及 owl 推理
    • 1. Fuseki与OWL推理
    • 2. 推理规则实战

(一)数据准备和本体建模

原文:https://zhuanlan.zhihu.com/p/32389370

1. 数据准备(将sql文件导入MySQL)

从博主的github上下载原始数据,在data文件夹中。把数据文件导入mysql。具体方法:
preprocess: 用编辑器打开sql文件,把所有的CHARSET=utf8mb4改为CHARSET=utf8。(避免后面不必要的麻烦)

  1. 打开Navicat,在自己创建的数据库上右键选择“打开链接”后选择“运行SQL文件”:
    知识图谱---简单实践(学习笔记)_第1张图片

  2. 选择data文件夹里的sql文件,选择编码方式,开始导入(编码设为utf8,避免之后一些不必要的麻烦):

知识图谱---简单实践(学习笔记)_第2张图片
3. 完成后产生一张名为kg_demo_movie的数据库,打开内有五张表,如图:

知识图谱---简单实践(学习笔记)_第3张图片
以上。数据准备完成。

2. 本体建模

即上篇文章说到的owl的部分,搭建大类之间的关系,使用工具Protégé(点击进入官网下载)。

  1. 点击“Download now”—“Download for Desktop”得到压缩包,解压即可。解压后打开直接运行Protege.exe进入如下界面,把红框中内容改为如图,这是我们新建本体资源的IRI(Internationalized Resource Identifiers)

知识图谱---简单实践(学习笔记)_第4张图片

  1. 点击“Entities”标签,选择“Classes”,在owl Thing下面创建子类。“Genre”“People”“Movie”,中间三个小红框分别是"创建子类"“创建平行类”“删除当前选中的类”(从左至右)。右边的“Description Genre”下面可以按需设置类的特性。

知识图谱---简单实践(学习笔记)_第5张图片

  1. 在“Object properties”中可以设置类之间的关系(即连接两个实体的那条线),右边设置线发起(Domains)和指向(Range)的实体。即这段关系的主题与取值范围。也可以设置关系与关系间的相反,相等等性质。以在日后的推理中发挥作用。

知识图谱---简单实践(学习笔记)_第6张图片

  1. 最后设置数据属性。选择“Data properties”。设置方法与上面类似,不同的是数据相当于树的叶子节点,不指向谁,所以他们的“ranges”是数值类型。

知识图谱---简单实践(学习笔记)_第7张图片
6. 选择“Window”选项选择“Tabs”,打开“OntoGraf”,再选择“OntoGraf”,拖拽标签可以让实体关系可视化。

知识图谱---简单实践(学习笔记)_第8张图片

  1. 把实体文件保存为ontology.owl,以便随后使用。

(二)把MySQL中的数据转为RDF

原文:https://zhuanlan.zhihu.com/p/32552993

通过D2RQ(点击打开网址)来实现转化,下载压缩包(我下的是d2rq-0.8.1.tar.gz),解压,进入目录。

运行如下命令生成默认mapping文件:

generate-mapping -u root -o kg_demo_movie_mapping.ttl -p 123456 jdbc:mysql:///kg_demo_movie

“-u”后面是mysql的用户名,“-o”后面是保存的文件名,“-p”后面是mysql的密码(如果没有就不用输入“-p”及后面的内容),jdbc:mysql:///kg_demo_movie指定我们要映射的数据库。于是生成了默认的mapping文件:

@prefix map: <#> .
@prefix db: <> .
@prefix vocab:  .
@prefix rdf:  .
@prefix rdfs:  .
@prefix xsd:  .
@prefix d2rq:  .
@prefix jdbc:  .

map:database a d2rq:Database;
	d2rq:jdbcDriver "com.mysql.jdbc.Driver";
	d2rq:jdbcDSN "jdbc:mysql:///kg_demo_movie";
	d2rq:username "root";
	d2rq:password "123456";
	jdbc:autoReconnect "true";
	jdbc:zeroDateTimeBehavior "convertToNull";
	.

# Table genre
map:genre a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "genre/@@genre.genre_id@@";
	d2rq:class vocab:genre;
	d2rq:classDefinitionLabel "genre";
	.
map:genre__label a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:genre;
	d2rq:property rdfs:label;
	d2rq:pattern "genre #@@genre.genre_id@@";
	.
map:genre_genre_id a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:genre;
	d2rq:property vocab:genre_genre_id;
	d2rq:propertyDefinitionLabel "genre genre_id";
	d2rq:column "genre.genre_id";
	d2rq:datatype xsd:integer;
	.
map:genre_genre_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:genre;
	d2rq:property vocab:genre_genre_name;
	d2rq:propertyDefinitionLabel "genre genre_name";
	d2rq:column "genre.genre_name";
	.

# Table movie
map:movie a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "movie/@@movie.movie_id@@";
	d2rq:class vocab:movie;
	d2rq:classDefinitionLabel "movie";
	.
map:movie__label a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property rdfs:label;
	d2rq:pattern "movie #@@movie.movie_id@@";
	.
map:movie_movie_id a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_movie_id;
	d2rq:propertyDefinitionLabel "movie movie_id";
	d2rq:column "movie.movie_id";
	d2rq:datatype xsd:integer;
	.
map:movie_movie_title a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_movie_title;
	d2rq:propertyDefinitionLabel "movie movie_title";
	d2rq:column "movie.movie_title";
	.
map:movie_movie_introduction a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_movie_introduction;
	d2rq:propertyDefinitionLabel "movie movie_introduction";
	d2rq:column "movie.movie_introduction";
	.
map:movie_movie_rating a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_movie_rating;
	d2rq:propertyDefinitionLabel "movie movie_rating";
	d2rq:column "movie.movie_rating";
	d2rq:datatype xsd:double;
	.
map:movie_movie_release_date a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_movie_release_date;
	d2rq:propertyDefinitionLabel "movie movie_release_date";
	d2rq:column "movie.movie_release_date";
	.

# Table movie_to_genre (n:m)
map:movie_to_genre__link a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:movie_to_genre;
	d2rq:refersToClassMap map:genre;
	d2rq:join "movie_to_genre.movie_id => movie.movie_id";
	d2rq:join "movie_to_genre.genre_id => genre.genre_id";
	.

# Table person
map:person a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "person/@@person.person_id@@";
	d2rq:class vocab:person;
	d2rq:classDefinitionLabel "person";
	.
map:person__label a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property rdfs:label;
	d2rq:pattern "person #@@person.person_id@@";
	.
map:person_person_id a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_id;
	d2rq:propertyDefinitionLabel "person person_id";
	d2rq:column "person.person_id";
	d2rq:datatype xsd:integer;
	.
map:person_person_birth_day a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_birth_day;
	d2rq:propertyDefinitionLabel "person person_birth_day";
	d2rq:column "person.person_birth_day";
	.
map:person_person_death_day a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_death_day;
	d2rq:propertyDefinitionLabel "person person_death_day";
	d2rq:column "person.person_death_day";
	.
map:person_person_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_name;
	d2rq:propertyDefinitionLabel "person person_name";
	d2rq:column "person.person_name";
	.
map:person_person_english_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_english_name;
	d2rq:propertyDefinitionLabel "person person_english_name";
	d2rq:column "person.person_english_name";
	.
map:person_person_biography a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_biography;
	d2rq:propertyDefinitionLabel "person person_biography";
	d2rq:column "person.person_biography";
	.
map:person_person_birth_place a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property vocab:person_person_birth_place;
	d2rq:propertyDefinitionLabel "person person_birth_place";
	d2rq:column "person.person_birth_place";
	.

# Table person_to_movie (n:m)
map:person_to_movie__link a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property vocab:person_to_movie;
	d2rq:refersToClassMap map:person;
	d2rq:join "person_to_movie.movie_id => movie.movie_id";
	d2rq:join "person_to_movie.person_id => person.person_id";
	.

修改为:

@prefix map: <#> .
@prefix db: <> .
@prefix vocab:  .
@prefix rdf:  .
@prefix rdfs:  .
@prefix xsd:  .
@prefix d2rq:  .
@prefix jdbc:  .
@prefix :  .

map:database a d2rq:Database;
	d2rq:jdbcDriver "com.mysql.jdbc.Driver";
	d2rq:jdbcDSN "jdbc:mysql:///kg_demo_movie?useUnicode=true&characterEncoding=utf8";
	d2rq:username "root";
	d2rq:password "123456";
	jdbc:autoReconnect "true";
	jdbc:zeroDateTimeBehavior "convertToNull";
	.

# Table genre
map:genre a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "genre/@@genre.genre_id@@";
	d2rq:class :Genre;
	d2rq:classDefinitionLabel "genre";
	.
map:genre_genre_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:genre;
	d2rq:property :genreName;
	d2rq:propertyDefinitionLabel "genre genre_name";
	d2rq:column "genre.genre_name";
	.

# Table movie
map:movie a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "movie/@@movie.movie_id@@";
	d2rq:class :Movie;
	d2rq:classDefinitionLabel "movie";
	.
map:movie_movie_title a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property :movieTitle;
	d2rq:propertyDefinitionLabel "movie movie_title";
	d2rq:column "movie.movie_title";
	.
map:movie_movie_introduction a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property :movieIntroduction;
	d2rq:propertyDefinitionLabel "movie movie_introduction";
	d2rq:column "movie.movie_introduction";
	.
map:movie_movie_rating a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property :movieRating;
	d2rq:propertyDefinitionLabel "movie movie_rating";
	d2rq:column "movie.movie_rating";
	d2rq:datatype xsd:double;
	.
map:movie_movie_release_date a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property :movieReleaseDate;
	d2rq:propertyDefinitionLabel "movie movie_release_date";
	d2rq:column "movie.movie_release_date";
	.

# Table movie_to_genre (n:m)
map:movie_to_genre__link a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:movie;
	d2rq:property :hasGenre;
	d2rq:refersToClassMap map:genre;
	d2rq:join "movie_to_genre.movie_id => movie.movie_id";
	d2rq:join "movie_to_genre.genre_id => genre.genre_id";
	.

# Table person
map:person a d2rq:ClassMap;
	d2rq:dataStorage map:database;
	d2rq:uriPattern "person/@@person.person_id@@";
	d2rq:class :Person;
	d2rq:classDefinitionLabel "person";
	.
map:person_person_birth_day a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personBirthDay;
	d2rq:propertyDefinitionLabel "person person_birth_day";
	d2rq:column "person.person_birth_day";
	.
map:person_person_death_day a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personDeathDay;
	d2rq:propertyDefinitionLabel "person person_death_day";
	d2rq:column "person.person_death_day";
	.
map:person_person_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personName;
	d2rq:propertyDefinitionLabel "person person_name";
	d2rq:column "person.person_name";
	.
map:person_person_english_name a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personEnglishName;
	d2rq:propertyDefinitionLabel "person person_english_name";
	d2rq:column "person.person_english_name";
	.
map:person_person_biography a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personBiography;
	d2rq:propertyDefinitionLabel "person person_biography";
	d2rq:column "person.person_biography";
	.
map:person_person_birth_place a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :personBirthPlace;
	d2rq:propertyDefinitionLabel "person person_birth_place";
	d2rq:column "person.person_birth_place";
	.

# Table person_to_movie (n:m)
map:person_to_movie__link a d2rq:PropertyBridge;
	d2rq:belongsToClassMap map:person;
	d2rq:property :hasActedIn;
	d2rq:refersToClassMap map:movie;
	d2rq:join "person_to_movie.movie_id => movie.movie_id";
	d2rq:join "person_to_movie.person_id => person.person_id";
	.

主要改变有:

  1. @perfix后面加了一行
@prefix :  .

这样的话可以用 “:”来指代这一串IRI,即

http://www.kgdemo.com#Person

可以表达为

:Person
d2rq:jdbcDSN "jdbc:mysql:///kg_demo_movie";

改为

d2rq:jdbcDSN "jdbc:mysql:///kg_demo_movie?useUnicode=true&characterEncoding=utf8";

与mysql里的数据统一字符编码。

  1. 删除了每一类的“label”和“id”定义,因为对我们的后续应用没什么用。
  2. “belongsToClassMap”是domain,refersToClassMap是range,检查一下是否正确,中间的property是映射词汇,修改这些词汇为RDF中的映射词汇即可,如:“vocab:person_person_birth_day”修改为“:personBirthDay”。
    (注意后面的分号及每个段落后的句点不要删掉了。)

输入如下命令把数据转化为RDF:

.\dump-rdf.bat -o kg_demo_movie.nt .\kg_demo_movie_mapping.ttl

(三)SPARQL endpoint 开启与两种交互方式

原文:https://zhuanlan.zhihu.com/p/32880610

D2RQ的mapping文件使得我们可以以RDF形式访问关系数据库中的数据,即它把SPARQL翻译成了SQL语句进行查询。
进入D2RQ目录打开命令窗口,通过如下命令启动D2R Server:

d2r-server.bat kg_demo_movie_mapping.ttl

1. 浏览器中查询

在浏览器输入“http://localhost:2020/”进入如下界面
知识图谱---简单实践(学习笔记)_第9张图片
红框1是我们定义的类别,点开任意类别可以看到其对应的所有实例(默认显示50个,可在mapping文件中修改服务器配置),点开某个实例可以看到其包含的所有属性。点击红框2进入endpoint。
输入框默认SPARQL查询是获取所有RDF三元组,LIMIT限制返回结果数量,点击“Go!”返回如下结果:

知识图谱---简单实践(学习笔记)_第10张图片

例1: “周星驰演出了哪些电影?”

SELECT ?n WHERE {
?s rdf:type :Person.
?s :personName ‘周星驰’.
?s :hasActedIn ?o.
?o :movieTitle ?n
}
LIMIT 10

返回如图:
知识图谱---简单实践(学习笔记)_第11张图片

SPARQL语法的具体使用请参考 https://www.w3.org/2009/Talks/0615-qbe/

例2: “英雄这部电影有哪些人参演?”

SELECT ?n WHERE {
?s rdf:type :Movie.
?s :movieTitle ‘英雄’.
?a :hasActedIn ?s.
?a :movieTitle ?n
}
LIMIT 10

返回结果如图:
知识图谱---简单实践(学习笔记)_第12张图片

例3 :“巩俐参演的评分大于7的电影有哪些?”

SELECT ?n WHERE{
?s rdf:type :Person.
?s :personName ‘巩俐’.
?s :hasActedIn ?o.
?o :movieTitle ?n.
?o :movieRating ?r.
FILTER(?r >= 7)
}
LIMIT 10

若返回‘no result’,寻找原因,先看不加filter能否正常返回结果,若不能,可能是之前的编码格式没有统一,重复上面操作再试一次,若返回了值如下图:
知识图谱---简单实践(学习笔记)_第13张图片考虑把FILTER的内容改为:

FILTER(?r >= “7.0E0”^^xsd:double)

即在后面定义其类型为xsd:double型。
返回结果如图:
知识图谱---简单实践(学习笔记)_第14张图片

2. 用Python脚本进行交互

首先用下载SPARQLwrapper,这个包让我们可以方便地跟endpoint进行交互。下载完成后执行Python代码如下:

from SPARQLWrapper import SPARQLWrapper, JSON

sparql = SPARQLWrapper("http://localhost:2020/sparql")
sparql.setQuery("""
    PREFIX : 
    PREFIX rdf: 

  SELECT ?n WHERE{
       ?s rdf:type :Person.
      ?s :personName '巩俐'.
      ?s :hasActedIn ?o.
      ?o :movieTitle ?n.
      ?o :movieRating ?r
      FILTER(?r >= 7)
    }
LIMIT 10
""")
sparql.setReturnFormat(JSON)
results = sparql.query().convert()

for result in results["results"]['bindings']:
    print(result['n']['value'])

返回巩俐参演的评分大于7分的电影。
http://localhost:2020/sparql 为D2RQ的默认链接,用于初始化Wrapper。

(四)Apache jena SPARQL endpoint 及 owl 推理

原文: https://zhuanlan.zhihu.com/p/33224431

上一节利用D2RQ来开启endpoint服务有两个缺点:

  1. 不支持直接将RDF通过endpoint发布到网络上。
  2. 不支持推理。
    Apache Jena(后简称Jena)可以解决以上两个问题。
    Jena是一个源的Java语义网框架(open source Semantic Web Framework for Java),用于构建语义网和链接数据应用。
    这里我们会用到Jena的三个组件: TDB、rule reasoner 和 Fuseki。
    其中TDB是用于存储RDF的组件,Jena可以通过自身的rule reasoner 实现RDFS和OWL推理,Fuseki是一个SPARQL服务器,也就是一个SPARQL endpoint。

1. Fuseki与OWL推理

首先进入Jena官网点击“Download”分别下载apach-jena和apache-jana-fuseki,如图:
知识图谱---简单实践(学习笔记)_第15张图片
step1
下载下来后分别解压,创建一个文件夹用于存放tdb数据(这里命名为tdb),进入解压后的“apache-jena-X.X.X”文件夹内的“bat”目录,使用“tdbloader.bat”将之前我们的RDF数据以TDB的方式存储。,命令如下(原作者内容):

.\tdbloader.bat --loc="D:\apache jena\tdb" "D:\d2rq\kg_demo_movie.nt"

“–loc”后面是tdb的存储位置(改为自己的),即我们刚刚创建的文件夹,第二个是我们在第二节中最后得到的文件路径(改为自己的)。

step2
进入“apache-jena-fuseki-X.X.X”文件夹,运行“fuseki-server.bat”,然后退出。程序会为我们在当前目录自动创建“run”文件夹。将在第一节中保存的“ontology.owl”移动到“run”文件夹下的“databases”文件夹中,并将“owl”后缀名改为“ttl”。
在“run”文件夹下的“configuration”中,创建名为“fuseki_conf.ttl”的文本文件(取名没有要求),加入如下内容(原作者内容):

@prefix :       .
@prefix tdb:    .
@prefix rdf:    .
@prefix ja:     .
@prefix rdfs:   .
@prefix 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  ] ;
    
    #启用OWL推理机
    ja:reasoner [ja:reasonerURL ] .

<#tdbGraph> rdf:type tdb:GraphTDB ;
    tdb:dataset <#tdbDataset> ;
    .
    #改为tdb文件夹路径(存储数据用)
<#tdbDataset> rdf:type tdb:DatasetTDB ;
    tdb:location "D:/apache jena/tdb" ;
    .

以上,有两个需要修改路径的地方,路径中的空格用“%20”表示,再次运行“fuseki-server.bat”,出现类似如下界面(没有ERROR出现),则界面运行成功。
知识图谱---简单实践(学习笔记)_第16张图片浏览器访问“http://localhost:3030/ ” ,点击“query”即可进行类似之前D2RQ的查询。查询电影《功夫》的所有属性:

PREFIX : 
PREFIX rdf: 
PREFIX rdfs: 

SELECT * WHERE {
?x :movieTitle '功夫'.
?x ?p ?o.
}

(从这里开始我这边一直显示“no result”, 原因未知。)

返回结果中应有电影的“hasActor”属性,这在原本的RDF中是没有的,是由OWL推理机得到。

2. 推理规则实战

在“databases”文件夹下新建一个文本文件“rules.ttl”,填入如下内容:

@prefix :  .
@prefix owl:  .
@prefix rdf:  .
@prefix xsd:  .
@prefix rdfs:  .

[ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)]
[ruleInverse: (?p :hasActedIn ?m) -> (?m :hasActor ?p)]

定义了一个名为“ruleComedian”的规则,它的意思是:如果有一个演员,出演了一部喜剧电影,那么他就是一位喜剧演员。修改配置文件“fuseki_conf.ttl”(原作者内容):

@prefix :       .
@prefix tdb:    .
@prefix rdf:    .
@prefix ja:     .
@prefix rdfs:   .
@prefix 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  ] ;
    
    #关闭OWL推理机
    #ja:reasoner [ja:reasonerURL ] .

    #开启规则推理机,并指定规则文件路径
    ja:reasoner [
        ja:reasonerURL  ; 
        ja:rulesFrom  ; ]
    .

<#tdbGraph> rdf:type tdb:GraphTDB ;
    tdb:dataset <#tdbDataset> ;
    .
   # 修改为tdb路径
<#tdbDataset> rdf:type tdb:DatasetTDB ;
    tdb:location "D:/apache jena/tdb" ;
    .

以上有三个需要修改路径的地方。
我们只能启用一种推理机。前面也提到,OWL的推理功能也可以在规则推理机里面实现,因此我们定义了“ruleInverse”来表示“hasActedIn”和“hasActor”的相反关系。

执行如下SPARQL查询,喜剧演员有哪些:

PREFIX : 
PREFIX rdf: 
PREFIX rdfs: 

SELECT * WHERE {
?x rdf:type :Comedian.
?x :personName ?n.
}
limit 10

查询结果:

                           x                                 n      
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/111298   郑丹瑞  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/70591   陈欣健  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/116351   沈殿霞  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/116052   鲍汉琳  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1002925   张同祖  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/62423   林正英  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1614091   林琪欣  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/224929   陈法蓉  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1135398   叶世荣  
file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/119426   元秋 

以上。最后一节目前未能找到未成功原因,如有建议,万分感谢。

你可能感兴趣的:(知识图谱)