这四个词汇与推理密切相关,查看JENA的RDFSRuleReasonerFactory可以看到里面有这么一段代码:
- Resource base = capabilities.createResource(getURI());
- base.addProperty(ReasonerVocabulary.nameP, "RDFS FB-TGC Rule Reasoner")
- .addProperty(ReasonerVocabulary.descriptionP, "Complete RDFS implementation supporting metalevel statements.\nCan separate tbox and abox data if desired to reuse tbox caching or mix them.")
- .addProperty(ReasonerVocabulary.supportsP, RDFS.subClassOf)
- .addProperty(ReasonerVocabulary.supportsP, RDFS.subPropertyOf)
- .addProperty(ReasonerVocabulary.supportsP, RDFS.member)
- .addProperty(ReasonerVocabulary.supportsP, RDFS.range)
- .addProperty(ReasonerVocabulary.supportsP, RDFS.domain)
- .addProperty(ReasonerVocabulary.versionP, "0.1");
说明jena对其提供了支持。
subPropertyOf
如果张三养了一只狗,那么一定可以推理出张三养了一只宠物,因此养狗和有宠物是subPropertyOf关系。
- String ns = "htpp://www.crabone.com#";
-
- Model model = ModelFactory.createDefaultModel();
-
- // 养狗subPropertyOf有宠物
- Property hasPet = model.createProperty(ns, "有宠物");
- Property hasDog = model.createProperty(ns, "养狗");
- model.add(hasDog, RDFS.subPropertyOf, hasPet);
-
- // 张三养了一只狗叫汪汪
- model.createResource(ns+"张三").addProperty(hasDog, "汪汪");
-
- // 得到JENA内置的RDFS推理机
- Reasoner reasoner = ReasonerRegistry.getRDFSReasoner();
-
- // 用原来的图和推理机构造出新的推理图
- InfModel infModel = ModelFactory.createInfModel(reasoner, model);
-
- System.out.println(infModel.getResource(ns+"张三").getProperty(hasPet));
输出:[htpp://www.crabone.com#张三, htpp://www.crabone.com#有宠物, "汪汪"]
从代码来看,jena的推理是基于图的相关算法来实现的。subClassOf和其道理一样,这里就不啰嗦了。
domain、range
个人感觉这是推理性非常强的一种机制!在protege入门里面就有相关的解释。domain和range是用来描述一个property的,比如:拿养狗这个property来说,一般,只有人才会养狗,水瓶是不会养狗的,电插座也是不会养狗的,所以养狗这个property的domain是人(一种class),同样养狗这个property的range是狗(一种class)。当推理机知道这些道理后,告诉它,张三养了一只汪汪,那么,这个推理机能推理出,张三是人,汪汪是狗。
- String ns = "htpp://www.crabone.com#";
-
- Model model = ModelFactory.createDefaultModel();
-
- // 构造人这个类
- Resource personClass = model.createResource(ns+"人");
- model.add(personClass, RDF.type, RDFS.Class);
-
- // 构造狗这个类
- Resource dogClass = model.createResource(ns+"狗");
- model.add(dogClass, RDF.type, RDFS.Class);
-
- // 构造养狗这个属性,并设置domain是人,range是狗
- Property hasDog = model.createProperty(ns, "养狗");
- model.add(hasDog, RDFS.domain, personClass);
- model.add(hasDog, RDFS.range, dogClass);
-
- // 添加张三养了一条狗汪汪这个事实
- Resource zhangsan = model.createResource(ns+"张三");
- Resource wangwang = model.createResource(ns+"汪汪");
- zhangsan.addProperty(hasDog, wangwang);
-
- // 构造RDFS推理机
- Reasoner reasoner = ReasonerRegistry.getRDFSReasoner();
-
- // 生成推理图
- InfModel infModel = ModelFactory.createInfModel(reasoner, model);
-
- System.out.println(infModel.getResource(ns+"张三").getProperty(RDF.type));
- System.out.println(infModel.getResource(ns+"汪汪").getProperty(RDF.type));
输出:
[htpp://www.crabone.com#张三, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, htpp://www.crabone.com#人]
[htpp://www.crabone.com#汪汪, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, htpp://www.crabone.com#狗]
总结:domain和rang其实也是一种property;domain这个property用来连接property和class,range这个property用来连接property和class,这是w3的标准,其实在JENA里面比较宽松,domain这个property用来连接property和节点即可,range也是如此。
JENA, 语义网基础
JENA
JENA中有一个最底层的接口:RDFNode,它代表RDF这张巨大图中的节点,这个节点可以是一个资源,可以是一个字符窜或者数字。因此它对应与2个子接口:
interface Literal extends RDFNode
interface Resource extends RDFNode
Literal接口代表了一些原始类型节点,比如:32位整型、布尔型等等。
Resource接口还可以继续衍生出2个重要的接口:
interface Container extends Resource
interface Property extends Resource
Container接口就对应了RDF的容器表达能力,里面有bag,seq,alt
Property接口就是所谓的资源属性了
在RDF的世界中,其实描述资源只有一种方式,那就是三元组,包括:主体(subject),谓词(predicate),客体(object)。主体和客体就是图中的2个节点,谓词就是一条边。这三元组在JENA中用Statement接口来描述,该接口中有下面3个方法:
public Resource getSubject();
public Property getPredicate();
public RDFNode getObject();
我们可以发现,主体一定是一种资源,不可能是一个Literal原始类型,因此主体必定属于Resource接口实现,但是客体可以是原始类型,比如:人有2条腿。人为主体;有为谓词;2为客体。
用一个例子来巩固下:
- <?xml version="1.0"?>
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:s="http://example.org/students/vocab#">
-
- <rdf:Description rdf:about="http://example.org/courses/6.001">
- <s:students>
- <rdf:Bag>
- <rdf:li rdf:resource="http://example.org/students/Amy"/>
- <rdf:li rdf:resource="http://example.org/students/Mohamed"/>
- <rdf:li rdf:resource="http://example.org/students/Johann"/>
- <rdf:li rdf:resource="http://example.org/students/Maria"/>
- <rdf:li rdf:resource="http://example.org/students/Phuong"/>
- </rdf:Bag>
- </s:students>
- </rdf:Description>
- </rdf:RDF>
如果要一下子看出这个RDF中有几个三元组,一定不是很方便吧?如果用图来表示:

是不是非常清晰呢?图中有一个主体http://example.org/courses/6.001,它有一条边http://example.org/students/vocab#students,对应的客体就是那个空节点。同理还有这个空节点所对应的那些三元组。用JENA来解析这个例子:
- Model model = ModelFactory.createDefaultModel();
-
- model.read(new FileInputStream("student.rdf"), null);
-
- StmtIterator it = model.listStatements();
-
- while(it.hasNext())
- {
- System.out.println(it.next());
- }
打印的结果如下:
[http://example.org/courses/6.001, http://example.org/students/vocab#students, -23ba78ea:125e9da42c8:-8000]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#_5, http://example.org/students/Phuong]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#_4, http://example.org/students/Maria]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#_3, http://example.org/students/Johann]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#_2, http://example.org/students/Mohamed]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#_1, http://example.org/students/Amy]
[-23ba78ea:125e9da42c8:-8000, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag]
JENA, 语义网基础
JENA, 三元组
在RDF入门的例子中,有这样一幅图:

最中间的那个节点起一个过渡作用,这时,虽然它也是一个资源,但这个资源没有必要标上资源描述符,因为它可能只在应用程序局部使用,作为推理机的一个桥梁等等作用,换句说,这个资源别人没有必要去引用。这样的节点,我们称之为空节点:
- Model model = ModelFactory.createDefaultModel();
-
- Resource blankNode = model.createResource(new AnonId("tempNode"));
- Property city = model.createProperty("http://www.crabobe.com/city");
- Property street = model.createProperty("http://www.crabobe.com/street");
- blankNode.addProperty(city, "深圳");
- blankNode.addProperty(street, "龙岗");
-
- Resource crab = model.createResource("http://www.crabobe.com/crab");
- Property address = model.createProperty("http://www.crabobe.com/address");
- crab.addProperty(address, blankNode);
-
- model.write(System.out);
注意,包含中文的源码文件必须是UTF-8的,运行结果如下:
- <rdf:RDF
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:j.0="http://www.crabobe.com/" >
- <rdf:Description rdf:about="http://www.crabobe.com/crab">
- <j.0:address rdf:nodeID="A0"/>
- </rdf:Description>
- <rdf:Description rdf:nodeID="A0">
- <j.0:street>龙岗</j.0:street>
- <j.0:city>深圳</j.0:city>
- </rdf:Description>
- </rdf:RDF>
JENA, 语义网基础
AnonId, JENA, RDF, 空节点