Jena 研究 之 Inference API 之 通用推理机

2020-03-13   98 次阅读


Jena官方推理API教程
Jena推理旨在将一系列推理引擎或是推理机整合到Jena中,该类引擎用于从一些基本RDF中得出附加的RDF断言(assert),以及任何可选的本体信息以及其与推理程序关联的公理与规则

推理总体结构
reasoneroverview.png

  • 应用程序通常通过使用将ModelFactory数据集与某个推理相关联来创建新模型来访问推理机
  • 对创建的模型的查询将不仅返回原始数据中存在的那些语句,还会返回由推理机实现的规则或者其他推理机制从数据派生的其他语句
  • 推理API通过使用bindSchema调用将推理程序绑定到一组schema或者本体数据来支持特定推理程序的概念
  • ReasonerRegistry,是一个静态类,通过它可以检查当前可以用的推理程序,可注册新的推理机并动态搜索给定类型的推理机

通用(Generic)推理机

  • 对于每种类型的推理机都有一个工厂类(符合ReasonerRegistry)
  • 一旦有了推理机实例,就可以通过将该实例绑定到不同的数据集来重复使用,而不存在互相干扰
  • 一旦有了推理机实例,就可以将其附加到RDF数据上创建推理模型,可以将其所有数据放入一个模型中或者分为两个部分(模式与实例数据)来完成

创建推理模型

InfModel inf = ModelFactory.createRDFSModel(rdfsExample);
其中rdfsExample是一个模型Model

或是

Reasoner reasoner = ReasonerRegistry.getRDFSReasoner();
InfModel inf = ModelFactory.createInfModel(reasoner, rdfsExample);

或者可以创建一个可以配置参数的推理模型

Reasoner reasoner = RDFSRuleReasonerFactory.theInstance().create(null);
InfModel inf = ModelFactory.createInfModel(reasoner, rdfsExample);

配置参数方法如下

Resource config = ModelFactory.createDefaultModel()
                              .createResource()
                              .addProperty(ReasonerVocabulary.PROPsetRDFSLevel, "simple");
Reasoner reasoner = RDFSRuleReasonerFactory.theInstance().create(config);
InfModel inf = ModelFactory.createInfModel(reasoner, rdfsExample);

倘若在schema中定义了复杂的模式信息,并且希望将这些模式应用于多组数据,则可以使用SPI级别方法来完成(虽然本人还没用过)

Reasoner boundReasoner = reasoner.bindSchema(schema);
InfModel inf = ModelFactory.createInfModel(boundReasoner, data)

推理模型的验证

验证接口简称数据集是否违背了某些定义的约束
example:RDFS中的数据类型范围,倘若RDF语句断言属性的对象值位于给定值空间之外,便存在着不一致

验证模板代码

ValidityReport validity = infmodel.validate();
if (validity.isValid()) {
    System.out.println("OK");
} else {
    System.out.println("Conflicts");
    for (Iterator i = validity.getReports(); i.hasNext(); ) {
        System.out.println(" - " + i.next());
    }
}

也就是说如果数据集中没有违反约束的数据就输出OK,否则将有违反约束的数据进行输出

直接关系与间接关系

不是很理解。。暂时跳过,施工暂停
directrelations.png

派生

接下来终于到了最激动人心的时刻,定义规则开始推理

  • 定义规则后将规则(rule)打入推理机(reasoner)中
  • 然后将推理机和模型一起创建一个新的推理模型(InfModel)
    大致如下
String rules = "[rule1: (?a eg:p ?b) (?b eg:p ?c) -> (?a eg:p ?c)]";
Reasoner reasoner = new GenericRuleReasoner(Rule.parseRules(rules));
reasoner.setDerivationLogging(true);
InfModel inf = ModelFactory.createInfModel(reasoner, rawData);

需要注意的是rules的撰写方法要符合rule的语法规则

在开头有提到Jena的推理机可以推理出数据中隐含的关系,但是究竟是通过哪些规则推导出哪些新关系的,这里提供了一个方法用于记录派生过程
getDerivation()

PrintWriter out = new PrintWriter(System.out);
for (StmtIterator i = inf.listStatements(A, p, D); i.hasNext(); ) {
    Statement s = i.nextStatement();
    System.out.println("Statement is " + s);
    for (Iterator id = inf.getDerivation(s); id.hasNext(); ) {
        Derivation deriv = (Derivation) id.next();
        deriv.printTrace(out, true);
    }
}

上述代码查询A是否通过p与D相关联,并列出派生路线
本人将A和D替换成了null,也就是遍历推理模型中所有谓语为p的语句,从而找出派生的语句并输出其派生过程
定制规则

String rules = "[rule1: (?a http://www.w3.org/1999/02/22-rdf-syntax-ns#type ?b) (?b http://www.w3.org/1999/02/22-rdf-syntax-ns#type ?c) -> (?a http://www.w3.org/1999/02/22-rdf-syntax-ns#type ?c)]";		

简而言之就是赋予type属性传递性,一个对象的类型是另一个对象,另一个对象的类型是第三对象,那么这个对象的类型也是第三对象(好像没毛病)
3.jpg!
结果如下
5.jpg

很明显,通过第一个fact(各个国家属于country)与第二个fact(country属于类class)推出了各个国家属于类class
同时遍历推理模型,与原模型进行对比,可发现推理模型中多出了上述推理出来的语句

注意

  • 假设一个推理模型InfModel已经绑定了一个Model,那么修改原Model的话绑定的推理模型InfModel也会受影响,通常包含方法addremove,模型的任何此类更改将会导致当前所有的推论与临时规则被丢弃,并且推断从下一次查询时重头开始,可通过InfModel.prepare()来实现
  • 可通过InfModel.reset()强制InfModel放弃所有缓存状态如果有任何未完成的查询,查询都将被终止
  • 可通过InfModel.rebind()来强制推理模型重新协商原始数据

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议