知识图谱推理与实践 (2) -- 基于jena实现规则推理
本章,介绍 基于jena的规则引擎实现推理,并通过两个例子介绍如何coding实现。
规则引擎概述
jena包含了一个通用的规则推理机,可以在RDFS和OWL推理机使用,也可以单独使用。
推理机支持在RDF图上推理,提供前向链、后向链和二者混合执行模式。包含RETE engine 和 one tabled datalog engine。可以通过GenericRuleReasoner来进行配置参数,使用各种推理引擎。要使用 GenericRuleReasoner,需要一个规则集来定义其行为.
Rule的语法与结构
规则通过 Rule对象来进行定义,包含 body terms列表 (premises),head terms列表 (conclusions) 和可选的 name 和可选的direction。
An informal description of the simplified text rule syntax is:
_Rule_ := _bare-rule_ .
or [ _bare-rule_ ]
or [ ruleName : _bare-rule_ ]
_bare-rule_ := _term_, ... _term_ -> _hterm_, ... _hterm_ // forward rule
or _bhterm_ <- _term_, ... _term _ // backward rule
_hterm := term
_ or [ _bare-rule_ ]
_term_ := (_node_, _node_, _node_) // triple pattern
or (_node_, _node_, _functor_) // extended triple pattern
or builtin(_node_, ... _node_) // invoke procedural primitive
_bhterm_ := (_node_, _node_, _node_) // triple pattern
_functor_ := functorName(_node_, ... _node_) // structured literal
_node_ := _uri-ref_ // e.g. http://foo.com/eg
or prefix:localname // e.g. rdf:type
or <_uri-ref_> // e.g. <myscheme:myuri>
or ?_varname_ // variable
or 'a literal' // a plain string literal
or 'lex'^^typeURI // a typed literal, xsd:* type names supported
or number // e.g. 42 or 25.5
逗号 "," 分隔符是可选的.
前向和后向规则语法之间的区别仅与混合执行策略相关,请参见下文。
_functor_ 是一个扩展的三元组,用于创建和访问文本值。functorName可以是任何简单的标识符。
为保障rules的可读性URI引用支持qname语法。可以使用在 PrintUtil对象中注册的前缀。
下面是一些规则示例:
[allID: (?C rdf:type owl:Restriction), (?C owl:onProperty ?P),
(?C owl:allValuesFrom ?D) -> (?C owl:equivalentClass all(?P, ?D)) ]
[all2: (?C rdfs:subClassOf all(?P, ?D)) -> print('Rule for ', ?C)
[all1b: (?Y rdf:type ?D) <- (?X ?P ?Y), (?X rdf:type ?C) ] ]
[max1: (?A rdf:type max(?P, 1)), (?A ?P ?B), (?A ?P ?C)
-> (?B owl:sameAs ?C) ]
- Rule
allID说明了functor用于将OWL限制的组件收集到单个数据结构中,然后可以触发进一步的规则 - Rule
all2表示一个前向规则,它创建了一个新的后向规则,并且还调用了print. - Rule
max1说明了如何使用数字
可以使用以下方法加载和解析规则文件:
List rules = Rule.rulesFromURL("file:myfile.rules");
或者
BufferedReader br = / _open reader_ / ;
List rules = Rule.parseRules( Rule.rulesParserFromReader(br) );
或者
String ruleSrc = / _list of rules in line_ /
List rules = Rule.parseRules( rulesSrc );
在前两种情况下(从URL或BufferedReader读取),规则文件由一个简单的处理器预处理,该处理器剥离注释并支持一些额外的宏命令:
# ...- 注释.
// ...- 注释
@prefix pre: <http://domain/url#>.- 定义了一个前缀
pre,可以用在规则文件中. @include <urlToRuleFile>.- 包含指定规则,允许规则文件包含RDFS和OWL的预定义规则
完整实例:
@prefix pre: <http://jena.hpl.hp.com/prefix#>.
@include <RDFS>.
[rule1: (?f pre:father ?a) (?u pre:brother ?f) -> (?u pre:uncle ?a)]
规则推理demo1--喜剧演员
例如,在一个电影知识图谱里,如果一个演员参演的电影的类型是喜剧片,我们可以认为这个演员是喜剧电影
推理规则:
[ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)]
我们用代码来实现:
String prefix = "http://www.test.com/kg/#";
Graph data = Factory.createGraphMem();
// 定义节点
Node movie = NodeFactory.createURI(prefix + "movie");
Node hasActedIn = NodeFactory.createURI(prefix + "hasActedIn");
Node hasGenre = NodeFactory.createURI(prefix + "hasGenre");
Node genreName = NodeFactory.createURI(prefix + "genreName");
Node genre = NodeFactory.createURI(prefix + "genre");
Node person = NodeFactory.createURI(prefix + "person");
Node Comedian = NodeFactory.createURI(prefix + "Comedian");
// 添加三元组
data.add(new Triple(genre, genreName, NodeFactory.createLiteral("喜剧")));
data.add(new Triple(movie, hasGenre, genre));
data.add(new Triple(person, hasActedIn, movie));
// 创建推理机
GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory.theInstance().create(null);
PrintUtil.registerPrefix("", prefix);
// 设置规则
reasoner.setRules(Rule.parseRules(
"[ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)] \n"
+ "-> tableAll()."));
reasoner.setMode(GenericRuleReasoner.HYBRID); // HYBRID混合推理
InfGraph infgraph = reasoner.bind(data);
infgraph.setDerivationLogging(true);
// 执行推理
Iterator<Triple> tripleIterator = infgraph.find(person, null, null);
while (tripleIterator.hasNext()) {
System.out.println(PrintUtil.print(tripleIterator.next()));
}
输出结果:
(:person rdf:type :Comedian)
(:person :hasActedIn :movie)
可以看到,已经给person加上了Comedian。
规则推理demo2 -- 关联交易
我们再来看上一篇文章中提到的那个金融图谱:

陈华钧老师PPT里,有一个推理任务:
- 执掌一家公司就一定是这家公司的股东;
- 某人同时是两家公司的股东,那么这两家公司一定有关联交易;
PPT里是使用Drools来实现的,具体可以参见PPT。我们这里使用jena来实现,可以达到同样的效果。
首先,构造好图谱,为了方便理解,我们用中文变量:
Model myMod = ModelFactory.createDefaultModel();
String finance = "http://www.example.org/kse/finance#";
Resource 孙宏斌 = myMod.createResource(finance + "孙宏斌");
Resource 融创中国 = myMod.createResource(finance + "融创中国");
Resource 乐视网 = myMod.createResource(finance + "乐视网");
Property 执掌 = myMod.createProperty(finance + "执掌");
Resource 贾跃亭 = myMod.createResource(finance + "贾跃亭");
Resource 地产公司 = myMod.createResource(finance + "地产公司");
Resource 公司 = myMod.createResource(finance + "公司");
Resource 法人实体 = myMod.createResource(finance + "法人实体");
Resource 人 = myMod.createResource(finance + "人");
Property 主要收入 = myMod.createProperty(finance + "主要收入");
Resource 地产事业 = myMod.createResource(finance + "地产事业");
Resource 王健林 = myMod.createResource(finance + "王健林");
Resource 万达集团 = myMod.createResource(finance + "万达集团");
Property 主要资产 = myMod.createProperty(finance + "主要资产");
Property 股东 = myMod.createProperty(finance + "股东");
Property 关联交易 = myMod.createProperty(finance + "关联交易");
Property 收购 = myMod.createProperty(finance + "收购");
// 加入三元组
myMod.add(孙宏斌, 执掌, 融创中国);
myMod.add(贾跃亭, 执掌, 乐视网);
myMod.add(王健林, 执掌, 万达集团);
myMod.add(乐视网, RDF.type, 公司);
myMod.add(万达集团, RDF.type, 公司);
myMod.add(融创中国, RDF.type, 地产公司);
myMod.add(地产公司, RDFS.subClassOf, 公司);
myMod.add(公司, RDFS.subClassOf, 法人实体);
myMod.add(孙宏斌, RDF.type, 人);
myMod.add(贾跃亭, RDF.type, 人);
myMod.add(王健林, RDF.type, 人);
myMod.add(万达集团,主要资产,地产事业);
myMod.add(融创中国,主要收入,地产事业);
myMod.add(孙宏斌, 股东, 乐视网);
myMod.add(孙宏斌, 收购, 万达集团);
PrintUtil.registerPrefix("", finance);
// 输出当前模型
StmtIterator i = myMod.listStatements(null,null,(RDFNode)null);
while (i.hasNext()) {
System.out.println(" - " + PrintUtil.print(i.nextStatement()));
}
上图所示的图谱,包含如下的三元组:
- (:公司 rdfs:subClassOf :法人实体)
- (:万达集团 :主要资产 :地产事业)
- (:万达集团 rdf:type :公司)
- (:地产公司 rdfs:subClassOf :公司)
- (:融创中国 :主要收入 :地产事业)
- (:融创中国 rdf:type :地产公司)
- (:孙宏斌 :股东 :乐视网)
- (:孙宏斌 rdf:type :人)
- (:孙宏斌 :执掌 :融创中国)
- (:乐视网 rdf:type :公司)
- (:贾跃亭 rdf:type :人)
- (:贾跃亭 :执掌 :乐视网)
- (:王健林 rdf:type :人)
- (:王健林 :执掌 :万达集团)
我们来定义推理规则:
- 执掌一家公司就一定是这家公司的股东;
- 收购一家公司,就是这家公司的股东
- 某人同时是两家公司的股东,那么这两家公司一定有关联交易;
用jena规则来表示:
[ruleHoldShare: (?p :执掌 ?c) -> (?p :股东 ?c)]
[[ruleHoldShare2: (?p :收购 ?c) -> (?p :股东 ?c)]
[ruleConnTrans: (?p :股东 ?c) (?p :股东 ?c2) -> (?c :关联交易 ?c2)]
执行推理:
GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory.theInstance().create(null);
reasoner.setRules(Rule.parseRules(
"[ruleHoldShare: (?p :执掌 ?c) -> (?p :股东 ?c)] \n"
+ "[ruleConnTrans: (?p :收购 ?c) -> (?p :股东 ?c)] \n"
+ "[ruleConnTrans: (?p :股东 ?c) (?p :股东 ?c2) -> (?c :关联交易 ?c2)] \n"
+ "-> tableAll()."));
reasoner.setMode(GenericRuleReasoner.HYBRID);
InfGraph infgraph = reasoner.bind(myMod.getGraph());
infgraph.setDerivationLogging(true);
System.out.println("推理后...\n");
Iterator<Triple> tripleIterator = infgraph.find(null, null, null);
while (tripleIterator.hasNext()) {
System.out.println(" - " + PrintUtil.print(tripleIterator.next()));
}
输出结果:
推理后...
- (:万达集团 :关联交易 :乐视网)
- (:万达集团 :关联交易 :融创中国)
- (:万达集团 :关联交易 :万达集团)
- (:孙宏斌 :股东 :万达集团)
- (:孙宏斌 :股东 :融创中国)
- (:融创中国 :关联交易 :万达集团)
- (:融创中国 :关联交易 :乐视网)
- (:融创中国 :关联交易 :融创中国)
- (:乐视网 :关联交易 :万达集团)
- (:乐视网 :关联交易 :融创中国)
- (:乐视网 :关联交易 :乐视网)
- (:贾跃亭 :股东 :乐视网)
- (:王健林 :股东 :万达集团)
- (:公司 rdfs:subClassOf :法人实体)
- (:万达集团 :主要资产 :地产事业)
- (:万达集团 rdf:type :公司)
- (:地产公司 rdfs:subClassOf :公司)
- (:融创中国 :主要收入 :地产事业)
- (:融创中国 rdf:type :地产公司)
- (:孙宏斌 :收购 :万达集团)
- (:孙宏斌 :股东 :乐视网)
- (:孙宏斌 rdf:type :人)
- (:孙宏斌 :执掌 :融创中国)
- (:乐视网 rdf:type :公司)
- (:贾跃亭 rdf:type :人)
- (:贾跃亭 :执掌 :乐视网)
- (:王健林 rdf:type :人)
- (:王健林 :执掌 :万达集团)
我们看到,推理后孙宏斌是三家公司的股东,三家公司都有关联交易。
作者:Jadepeng
出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
知识图谱推理与实践 (2) -- 基于jena实现规则推理的更多相关文章
- 知识图谱推理与实践(3) -- jena自定义builtin
在第2篇里,介绍了jena的The general purpose rule engine(通用规则引擎)及其使用,本篇继续探究,如何自定义builtin. builtin介绍 先回顾builtin为 ...
- 知识图谱实体对齐1:基于平移(translation)的方法
1 导引 在知识图谱领域,最重要的任务之一就是实体对齐 [1](entity alignment, EA).实体对齐旨在从不同的知识图谱中识别出表示同一个现实对象的实体.如下图所示,知识图谱\(\ma ...
- 知识图谱实体对齐2:基于GNN嵌入的方法
知识图谱实体对齐2:基于GNN嵌入的方法 1 导引 我们在上一篇博客<知识图谱实体对齐1:基于平移(translation)嵌入的方法>中介绍了如何对基于平移嵌入+对齐损失来完成知识图谱中 ...
- 知识图谱学习与实践(4)——通过例句介绍Sparql的使用
通过例句介绍Sparql的使用 1 简介 SPARQL的定义,是一个递归的定义,为SPARQL Protocal and RDF Query Language,是W3C制定的RDF知识图谱标准查询语言 ...
- 知识图谱学习与实践(4)——Protégé使用入门
1 Protégé简介 Protégé是一个本体建模工具软件,由斯坦福大学基于java语言开发的,属于开放源代码软件.软件主要用于语义网中本体的构建和基于本体的知识应用,是本体构建的核心开发工具,最新 ...
- 知识图谱学习与实践(6)——从结构化数据进行知识抽取(D2RQ介绍)
1 概述 D2RQ,含义是把关系型数据库当作虚拟的RDF图数据库进行访问.D2RQ平台是一个将关系型数据库当作虚拟的.只读的RDF图数据库进行访问的系统.提供了基于RDF访问关系数据库的内容,而无需复 ...
- 知识图谱之图数据库Neo4j
知识图谱中的知识是通过RDF结构来进行表示的,其基本单元是事实.每个事实是一个三元组(S, P, O),在实际系统中,按照存储方式的不同,知识图谱的存储可以分为基于表结构的存储和基于图结构的存储. 基 ...
- 知识图谱顶会论文(IJCAI-2022) TEMP:多跳推理的类型感知嵌入
IJCAI-TEMP:知识图谱上多跳推理的类型感知嵌入 论文地址: Type-aware Embeddings for Multi-Hop Reasoning over Knowledge Graph ...
- 知识图谱顶会论文(ACL-2022) ACL-SimKGC:基于PLM的简单对比KGC
12.(2022.5.4)ACL-SimKGC:基于PLM的简单对比KGC 12.(2022.5.4)ACL-SimKGC:基于PLM的简单对比KGC 摘要 1.引言 2.相关工作 2.1 知识图补全 ...
随机推荐
- 【Android Studio】类名字右下角红色的 J 【待解决】
问题如下图所示: 正在寻找结解决方法--
- 以太坊solidity智能合约-生成随机数
Solidity随机数生成 在以太坊的只能合约中,没有提供像其他面向对象编程一样的生成随机数的工具类或方法.其实,所谓的随机数也是伪随机的,没有哪一种语言能够真正的生成随机数. 对于solidity来 ...
- Java动态,安全追踪工具
Java动态,安全追踪工具 在我们日常的开发中,总是难以避免的要解决线上的问题.如果线上的问题我们在本地调试的时候无论调试多少次发现明明本地调用了这个方法呀,怎么线上就是没调呢?还有就是出了问题的时候 ...
- RabbitMQ与spring集成,配置完整的生产者和消费者
RabbitMQ与AMQP协议详解可以看看这个 http://www.cnblogs.com/frankyou/p/5283539.html 下面是rabbitMQ和spring集成的配置,我配置了二 ...
- Node.js 环境搭建及简单应用
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型.如果你想创建自己的服务,那么Node.js是一个非 ...
- win10和浏览器快捷键
1. Win10快捷键[Win+↑/↓/←/→] 将当前窗口按比例固定到屏幕的四个边角,如左上.右上.左下.右下.[Win+1/2/3…] 按顺序打开任务栏上的已固定程序(不包括第一个“任务视图”按钮 ...
- IDEA+maven搭建scala开发环境(spark)(半转载)
以下内容部分来自于https://zhuanlan.zhihu.com/p/23141509,我尝试了一遍,然后添加了一些图片.. 其实我觉得在IDEA中使用scala插件然后创建project的时候 ...
- Java——异常处理
1.java提供的异常不可能预见所有的问题,所以需要自己定义异常类,必须从已有的异常类继承,最好选择意思相近的异常类继承. class MyException extends Exception{} ...
- (二)对象以及变量的并发访问--synchronized的使用细节,用法
具体的记录synchronized关键的各种使用方式,注意事项.感觉一步一步跟我来都可以看懂滴 大致是按照以下思路进行书写的.黑体字可以理解为结论, 1.synchronized锁的是什么? 2.sy ...
- Windows Server 2008创建域环境
介绍一下域环境搭建,域主要用于中大型企业,小型企业计算机数量不多,而中大型企业计算机比较多,使用域可以方便管理,安全性也比在工作组中安全 1.安装完操作系统默认都属于WORKGROUP工作组. 2.安 ...