2015/05/28更新 代码在 https://github.com/zhoujiagen/semanticWebTutorialUsingJena
前言
该手册参考和扩展“Hebeler J, Fisher M, et al.Web 3.0与Semantic Web编程[M]. 清华大学出版社, 北京.2010.”中的HelloWorld。
在描述中,不将Web本体与描述逻辑的术语做区分,尽量采用Web本体的英文表述,下面列出Web本体与描述逻辑的术语对应关系:
Web本体 | 描述逻辑 |
Class | Concept |
Property Object Property Data Property | Role |
Individual | Instance |
计划记录类容:
1 Jena RDF API使用
2 用SPARQL做RDF navigate
3 手动本体对准(ontology alignment)
4 Jena OWL推理(Inference)
5 Jena Rule推理
内容
0 数据!数据!数据!
数据准备思路:将TBox与ABox分开,两个本体(TBox1, ABox1, TBox2, ABox2),其中ABox1与TBox1的命名空间不同,ABox2与TBox2的命名空间相同。
TBox1:FOAF的规范(http://xmlns.com/foaf/spec/)
ABox1:生成自FOAF数据的链接(http://www.ldodds.com/foaf/foaf-a-matic)
TBox2, ABox2: 如何用Protege建立本体(http://protegewiki.stanford.edu/wiki/Ontology101, http://130.88.198.11/tutorials/protegeowltutorial/),话外Protege官网现在变得好炫.
1 Jena RDF API使用
这里只涉及如何用RDF文件填充Model,code sketch如下:
Model model = ModelFactory.createDefaultModel(); InputStream is = FileManager.get().open("E:/码农的世界/码农的自我修养/semantic web/workspace/foafData.rdf"); model.read(is, "http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl"); is.close();
2 用SPARQL做RDF navigate
SPARQL的全称是SPARQL Protocol and RDF Query Language,既是一个定义如何执行RDF查询、更新操作的协议,也是一个RDF查询语言。
Jena中的Graph抽象比较好,这是个类似于关系型数据库中视图的概念,只是Graph中基础的数据结构是形如<Subject, Predicate, Object>的Triple,SPARQL作为查询语言,就是在Graph中Triple中定位和导航数据。
Jena ARQ API的code sketch如下:
//组装查询字符串StringBuilder sb = new StringBuilder(); sb.append("PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>").append(NEWLINE).append("PREFIX owl: <http://www.w3.org/2002/07/owl#>") .append(NEWLINE).append("PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>").append(NEWLINE) .append("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>").append(NEWLINE).append("PREFIX foaf: <http://xmlns.com/foaf/0.1/>") .append(NEWLINE).append("PREFIX myfoaf: <http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#>").append(NEWLINE) .append("PREFIX people: <http://www.people.com#>").append(NEWLINE); sb.append("SELECT DISTINCT ?name").append(NEWLINE).append("WHERE { myfoaf:me foaf:name ?name}").append(NEWLINE); //执行查询 sparql(model, sb.toString(), "?name"); private static void sparql(Model model, String query, String field) { Query q = QueryFactory.create(query); QueryExecution qexec = QueryExecutionFactory.create(q, model); System.out.println("Plan to run SPARQL query: "); System.out.println(BOUNDARY); System.out.println(query); System.out.println(BOUNDARY); ResultSet rs = qexec.execSelect(); while (rs.hasNext()) { QuerySolution qs = rs.nextSolution(); RDFNode name = qs.get(field);// 暂用RDFNode if (name != null) { System.out.println("Hello to " + name); } else { System.out.println("No friends found!"); } } qexec.close(); }
3 手动本体对准(ontology alignment)
这个例子涉及4个对准:
两个命名空间中的Class等价、两个命名空间中Property等价、两个命名空间中Property蕴涵和两个命名空间中Individual等价(异名同义)。
下图中红色箭头表示本体对准关系,没有展示Property之间的对准关系(该图用Graphviz手工生成,自动生成在下一步的计划中):
本体对准code sketch如下,其中Model shema仅加载两个本体的TBox:
// [1]people:Individual = foaf:Person Resource resource = schema.createResource(PEOPLE_NS + "#Individual"); Property property = schema.createProperty(OWL_URL + "equivalentClass"); Resource object = schema.createResource(FOAF_URL + "Person"); schema.add(resource, property, object); // [2]people:hasName = foaf:name resource = schema.createResource(PEOPLE_NS + "#hasName"); property = schema.createProperty(OWL_URL + "equivalentProperty"); object = schema.createResource(FOAF_URL + "name"); schema.add(resource, property, object); // [3]people:hasFriend < foaf:knows resource = schema.createResource(PEOPLE_NS + "#hasFriend"); property = schema.createProperty(RDFS_URL + "subPropertyOf"); object = schema.createResource(FOAF_URL + "knows"); schema.add(resource, property, object); // [4]myfoaf:me = people:individual_5 resource = schema.createResource(MYFOAF_NS + "#me"); property = schema.createProperty(OWL_URL + "sameAs"); object = schema.createResource(PEOPLE_NS + "#individual_5"); schema.add(resource, property, object);
4 Jena OWL推理(Inference)
下表是OWL支持的推理形式的概要:
OWL构造/描述逻辑支持的推理
语义构造 | 推理规则 |
概念包含 | C ⊑ D ∧ C(a) ⇒ D(a) |
概念互斥 | C ⊓ D ⊑ ⊥ ∧ C(a) ∧ D(b) ⇒ a≉ b |
关系包含 | R ⊑ S ∧ R(a, b) ⇒ S(a, b) |
关系定义域 | domain(R, C) ∧ R(a, b) ⇒ C(a) |
关系值域 | range(R, C) ∧ R(a, b) ⇒ C(b) |
自反关系 | R ⊑ id(C) ⇒ R(a, a) |
传递关系 | R(a, b) ∧ R(b, c) ⇒ R(a, c) |
对称关系 | R ≡ R⁻∧ R(a, b) ⇒ R(b, a) |
关系组合 | R ∘ S ⊑ R ′∧ R(a, b) ∧ S(b, c) ⇒ R′(a, c) |
互逆关系 | R(a, b) ⇒ R⁻(a, b) R⁻(a, b) ⇒ R(a, b) |
函数关系 | R(a, b) ∧ R(a, c) ⇒ b≈ c |
键 | HasKey(C, R)∧ C(a) ∧ C(b) ∧ R(a, c) ∧ R(b, c) ⇒ b≈ c |
Jena API关于OWL推理的基本策略是用Reasoner绑定TBox,在代表ABox的Model对象基础上创建出推理后模型IntModel对象。
code sketch如下:
InfModel inferredModel = null; Reasoner reasoner = ReasonerRegistry.getOWLReasoner(); reasoner = reasoner.bindSchema(schema);// tbox inferredModel = ModelFactory.createInfModel(reasoner, friendsModel);// abox
5 Jena Rule推理
尽管语义Web事实上的规则语言标准是SWRL,但Jena提供了自己的规则语言,一些值得关注的特性是Jena规则支持前向推理和后向推理、可以动态生成匿名节点。
使用Jena Rule执行推理的code sketch如下:
String rule = "[gmailFriend: (?person <http://xmlns.com/foaf/0.1/mbox_sha1sum> ?email), strConcat(?email, ?lit), regex(?lit, '(.*gmail.com)')" + "-> (?person " + RDF_TYPE + " <http://www.people.com#GmailPerson>)]"; Reasoner ruleReasoner = new GenericRuleReasoner(Rule.parseRules(rule)); ruleReasoner = ruleReasoner.bindSchema(schema); inferredModel = ModelFactory.createInfModel(ruleReasoner, friendsModel);
6 总结
本手册记录了Jena如何加载RDF文件填充Model、如何用SPARQL导航Model、如何执行OWL和Jena Rule推理,也简单介绍了本体对准。
数据
foafSchema.rdf (NS=http://xmlns.com/foaf/0.1/)
下载链接为http://xmlns.com/foaf/spec/index.rdf,将其重名为foafSchema.rdf。
foafData.rdf (NS=http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl)
<?xml version="1.0"?> <!DOCTYPE rdf:RDF [ <!ENTITY foaf "http://xmlns.com/foaf/0.1/" > <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" > <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" > <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" > ]> <rdf:RDF xmlns="http://www.w3.org/2002/07/owl#" xml:base="http://www.w3.org/2002/07/owl" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <Ontology rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl"> <imports rdf:resource="http://xmlns.com/foaf/0.1/"/> </Ontology> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Annotation properties // /////////////////////////////////////////////////////////////////////////////////////// --> <AnnotationProperty rdf:about="&foaf;givenname"/> <AnnotationProperty rdf:about="&foaf;mbox_sha1sum"/> <AnnotationProperty rdf:about="&foaf;nick"/> <AnnotationProperty rdf:about="&foaf;homepage"/> <AnnotationProperty rdf:about="&foaf;depiction"/> <AnnotationProperty rdf:about="&foaf;title"/> <AnnotationProperty rdf:about="&foaf;workInfoHomepage"/> <AnnotationProperty rdf:about="&foaf;workplaceHomepage"/> <AnnotationProperty rdf:about="&foaf;family_name"/> <AnnotationProperty rdf:about="&foaf;knows"/> <AnnotationProperty rdf:about="&foaf;schoolHomepage"/> <AnnotationProperty rdf:about="&foaf;phone"/> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Datatypes // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Individuals // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Ontology --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Ontology"> <rdf:type rdf:resource="http://schema.org/Person"/> <foaf:name rdf:datatype="&xsd;string">I. M. Ontology</foaf:name> <rdfs:seeAlso rdf:datatype="&xsd;string">http://ont.com</rdfs:seeAlso> <foaf:mbox_sha1sum rdf:datatype="&xsd;string">mailto:[email protected]</foaf:mbox_sha1sum> </NamedIndividual> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Reasoner --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Reasoner"> <rdf:type rdf:resource="http://schema.org/Person"/> <foaf:name rdf:datatype="&xsd;string">Ican Reason</foaf:name> <rdfs:seeAlso rdf:datatype="&xsd;string">http://reasoner.com</rdfs:seeAlso> <foaf:mbox_sha1sum rdf:datatype="&xsd;string">maillto:[email protected]</foaf:mbox_sha1sum> </NamedIndividual> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Statement --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Statement"> <rdf:type rdf:resource="http://schema.org/Person"/> <foaf:name rdf:datatype="&xsd;string">Makea Statement</foaf:name> <rdfs:seeAlso rdf:datatype="&xsd;string">http://statement.com</rdfs:seeAlso> <foaf:mbox_sha1sum rdf:datatype="&xsd;string">mailto:[email protected]</foaf:mbox_sha1sum> </NamedIndividual> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://blog.sina.com.cn/zhoujiagenontology --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://blog.sina.com.cn/zhoujiagenontology"/> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://s8.sinaimg.cn/mw690/002RJaAlty6FSYutTO777&690 --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://s8.sinaimg.cn/mw690/002RJaAlty6FSYutTO777&690"> <rdf:type rdf:resource="&foaf;Image"/> </NamedIndividual> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.cqu.edu.cn/ --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.cqu.edu.cn/"/> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.founderinternational.com/ --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.founderinternational.com/"/> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#me --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#me"> <rdf:type rdf:resource="http://schema.org/Person"/> <foaf:givenname rdf:datatype="&xsd;string">Semantic</foaf:givenname> <foaf:name rdf:datatype="&xsd;string">Semantic Web</foaf:name> <foaf:family_name rdf:datatype="&xsd;string">Web</foaf:family_name> <foaf:nick rdf:datatype="&xsd;string">Webby</foaf:nick> <foaf:title rdf:datatype="&xsd;string">master</foaf:title> <foaf:mbox_sha1sum rdf:datatype="&xsd;string">[email protected]</foaf:mbox_sha1sum> <foaf:knows rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Ontology"/> <foaf:knows rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Reasoner"/> <foaf:knows rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#Statement"/> <foaf:homepage rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://blog.sina.com.cn/zhoujiagenontology"/> <foaf:depiction rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://s8.sinaimg.cn/mw690/002RJaAlty6FSYutTO777&690"/> <foaf:schoolHomepage rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.cqu.edu.cn/"/> <foaf:workplaceHomepage rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.founderinternational.com/"/> <foaf:workInfoHomepage rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#http://www.founderinternational.com/"/> <foaf:phone rdf:resource="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#tel:13552854032"/> </NamedIndividual> <!-- http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#tel:13552854032 --> <NamedIndividual rdf:about="http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#tel:13552854032"/> </rdf:RDF> <!-- Generated by the OWL API (version 3.2.5.1912) http://owlapi.sourceforge.net -->
peopleSchema.rdf (NS=http://www.people.com)
<?xml version="1.0"?> <!DOCTYPE rdf:RDF [ <!ENTITY owl "http://www.w3.org/2002/07/owl#" > <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" > <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" > <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" > ]> <rdf:RDF xmlns="http://www.people.com#" xml:base="http://www.people.com" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <owl:Ontology rdf:about="http://www.people.com"/> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Datatypes // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Object Properties // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#hasFriend --> <owl:ObjectProperty rdf:about="http://www.people.com#hasFriend"> <rdfs:range rdf:resource="http://www.people.com#Individual"/> <rdfs:domain rdf:resource="http://www.people.com#Individual"/> </owl:ObjectProperty> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Data properties // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#hasName --> <owl:DatatypeProperty rdf:about="http://www.people.com#hasName"> <rdfs:domain rdf:resource="http://www.people.com#Individual"/> <rdfs:range rdf:resource="&xsd;string"/> </owl:DatatypeProperty> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Classes // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#GmailPerson --> <owl:Class rdf:about="http://www.people.com#GmailPerson"> <rdfs:subClassOf rdf:resource="http://www.people.com#Individual"/> </owl:Class> <!-- http://www.people.com#Individual --> <owl:Class rdf:about="http://www.people.com#Individual"/> </rdf:RDF> <!-- Generated by the OWL API (version 3.2.5.1912) http://owlapi.sourceforge.net -->
peopleData.rdf (NS=http://www.people.com)
<?xml version="1.0"?> <!DOCTYPE rdf:RDF [ <!ENTITY www "http://www.people.com#" > <!ENTITY owl "http://www.w3.org/2002/07/owl#" > <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" > <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" > <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" > ]> <rdf:RDF xmlns="http://www.people.com#" xml:base="http://www.people.com" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:www="http://www.people.com#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <owl:Ontology rdf:about="http://www.people.com"/> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Datatypes // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Object Properties // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#hasFriend --> <owl:ObjectProperty rdf:about="&www;hasFriend"> <rdfs:range rdf:resource="&www;Individual"/> <rdfs:domain rdf:resource="&www;Individual"/> </owl:ObjectProperty> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Data properties // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#hasName --> <owl:DatatypeProperty rdf:about="&www;hasName"> <rdfs:domain rdf:resource="&www;Individual"/> <rdfs:range rdf:resource="&xsd;string"/> </owl:DatatypeProperty> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Classes // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#GmailPerson --> <owl:Class rdf:about="&www;GmailPerson"> <rdfs:subClassOf rdf:resource="&www;Individual"/> </owl:Class> <!-- http://www.people.com#Individual --> <owl:Class rdf:about="&www;Individual"/> <!-- /////////////////////////////////////////////////////////////////////////////////////// // // Individuals // /////////////////////////////////////////////////////////////////////////////////////// --> <!-- http://www.people.com#individual_5 --> <owl:NamedIndividual rdf:about="&www;individual_5"> <rdf:type rdf:resource="&www;Individual"/> <hasName rdf:datatype="&xsd;string">Sem Web</hasName> <hasFriend rdf:resource="&www;individual_6"/> <hasFriend rdf:resource="&www;individual_7"/> </owl:NamedIndividual> <!-- http://www.people.com#individual_6 --> <owl:NamedIndividual rdf:about="&www;individual_6"> <rdf:type rdf:resource="&www;Individual"/> <hasName rdf:datatype="&xsd;string">Web O Data</hasName> </owl:NamedIndividual> <!-- http://www.people.com#individual_7 --> <owl:NamedIndividual rdf:about="&www;individual_7"> <rdf:type rdf:resource="&www;Individual"/> <hasName rdf:datatype="&xsd;string">Mr. OWL</hasName> </owl:NamedIndividual> </rdf:RDF> <!-- Generated by the OWL API (version 3.2.5.1912) http://owlapi.sourceforge.net -->
代码
代码1 常量类
package util; /** * <ul> * <li>Author: zhoujg | Date: 2014-3-23 下午1:25:14</li> * <li>Description: 常量类</li> * </ul> */ public class Constants { public static final String NEWLINE = System.getProperty("line.separator"); public static final String TAB = System.getProperty("\t"); public static final String BOUNDARY = "-----------------------------------------------------------------------"; public static final String RDF_URL = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; public static final String RDFS_URL = "http://www.w3.org/2000/01/rdf-schema#"; public static final String OWL_URL = "http://www.w3.org/2002/07/owl#"; public static final String XSD_URL = "http://www.w3.org/2001/XMLSchema#"; public static final String FOAF_URL = "http://xmlns.com/foaf/0.1/"; public static final String RDF_TYPE = "<" + RDF_URL + "type>"; }
代码2 HelloSemanticWeb
package helloworld; import java.io.IOException; import java.io.InputStream; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.InfModel; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.reasoner.Reasoner; import com.hp.hpl.jena.reasoner.ReasonerRegistry; import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner; import com.hp.hpl.jena.reasoner.rulesys.Rule; import com.hp.hpl.jena.util.FileManager; import static util.Constants.*; /** * <ul> * <li>Author: zhoujg | Date: 2014-3-23 下午12:56:51</li> * <li>Description: Jena语义Web编程之HelloWorld</li> * </ul> */ class HelloSemanticWeb { // FOAF命名空间 private static final String FOAF_NS = "http://xmlns.com/foaf/0.1/"; // FOAF文件绝对路径 private static final String FOAF_SCHEMA_FN = "E:/码农的世界/码农的自我修养/semantic web/workspace/foafSchema.rdf"; // myfoaf命名空间 private static final String MYFOAF_NS = "http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl"; // myfoaf文件绝对路径 private static final String MYFOAF_DATA_FN = "E:/码农的世界/码农的自我修养/semantic web/workspace/foafData.rdf"; // poeple命名空间 private static final String PEOPLE_NS = "http://www.people.com"; // people文件的绝对路径 private static final String PEOPLE_SCHEMA_FN = "E:/码农的世界/码农的自我修养/semantic web/workspace/peopleSchema.rdf"; private static final String PEOPLE_DATA_FN = "E:/码农的世界/码农的自我修养/semantic web/workspace/peopleData.rdf"; // Jena的RDF模型 private static Model friendsModel = null; // 所有本体的Schema模型 private static Model schema = null; // 推理后模型 private static InfModel inferredModel = null; public static void main(String[] args) throws IOException { version2(); } /** version 1: rdf navigate using sparql query */ public static void version1() throws IOException { System.out.println("Load my FOAF friends"); friendsModel = populateMyFOAFFriends(MYFOAF_DATA_FN); System.out.println("Say Hello to myself"); sayHelloToMyself(friendsModel); System.out.println("Say Hello to my friends"); sayHelloToMyFriends(friendsModel); } /** version 2: ontology integration using alignment */ public static void version2() throws IOException { System.out.println("Load the data"); loadABox(); System.out.println("Generate the schema to contain all ontology's tbox"); loadTBox(); // 本体对准 alignmentInTBox(); // 绑定到推理机 bindReasoner(); // 执行查询 sayHelloToMyself(inferredModel); sayHelloToMyFriends(inferredModel); } /** version 3: using jena rules */ public static void version3() throws IOException { System.out.println("Load the data"); loadABox(); System.out.println("Generate the schema to contain all ontology's tbox"); loadTBox(); // 本体对准 alignmentInTBox(); // 绑定到规则推理机 bindJenaReasoner(); // 执行查询 sayHelloToGmailFriends(inferredModel); } private static void bindJenaReasoner() { final String rule = "[gmailFriend: (?person <http://xmlns.com/foaf/0.1/mbox_sha1sum> ?email), strConcat(?email, ?lit), regex(?lit, '(.*gmail.com)')" + "-> (?person " + RDF_TYPE + " <http://www.people.com#GmailPerson>)]"; Reasoner ruleReasoner = new GenericRuleReasoner(Rule.parseRules(rule)); ruleReasoner = ruleReasoner.bindSchema(schema); inferredModel = ModelFactory.createInfModel(ruleReasoner, friendsModel); } /** 加载所有本体的ABox */ private static void loadABox() { friendsModel = ModelFactory.createDefaultModel(); InputStream is = FileManager.get().open(MYFOAF_DATA_FN);// MyFOAF的data friendsModel.read(is, MYFOAF_NS); is = FileManager.get().open(PEOPLE_DATA_FN);// people的data friendsModel.read(is, PEOPLE_NS); } /** 加载所有本体的TBox */ private static void loadTBox() { schema = ModelFactory.createDefaultModel(); InputStream is = FileManager.get().open(FOAF_SCHEMA_FN);// FOAF的Schema schema.read(is, FOAF_NS); is = FileManager.get().open(PEOPLE_SCHEMA_FN);// people的Schema schema.read(is, PEOPLE_NS); } /** 本体对准ontology alignment */ private static void alignmentInTBox() { // [1]people:Individual = foaf:Person Resource resource = schema.createResource(PEOPLE_NS + "#Individual"); Property property = schema.createProperty(OWL_URL + "equivalentClass"); Resource object = schema.createResource(FOAF_URL + "Person"); schema.add(resource, property, object); // [2]people:hasName = foaf:name resource = schema.createResource(PEOPLE_NS + "#hasName"); property = schema.createProperty(OWL_URL + "equivalentProperty"); object = schema.createResource(FOAF_URL + "name"); schema.add(resource, property, object); // [3]people:hasFriend < foaf:knows resource = schema.createResource(PEOPLE_NS + "#hasFriend"); property = schema.createProperty(RDFS_URL + "subPropertyOf"); object = schema.createResource(FOAF_URL + "knows"); schema.add(resource, property, object); // [4]myfoaf:me = people:individual_5 resource = schema.createResource(MYFOAF_NS + "#me"); property = schema.createProperty(OWL_URL + "sameAs"); object = schema.createResource(PEOPLE_NS + "#individual_5"); schema.add(resource, property, object); } private static void bindReasoner() { Reasoner reasoner = ReasonerRegistry.getOWLReasoner(); reasoner = reasoner.bindSchema(schema);// tbox inferredModel = ModelFactory.createInfModel(reasoner, friendsModel);// abox } /** 填充模型 */ private static Model fillModel(String base, String filePath) throws IOException { Model model = ModelFactory.createDefaultModel(); InputStream is = FileManager.get().open(filePath); model.read(is, base); is.close(); return model; } /** MyFOAF填充模型 */ private static Model populateMyFOAFFriends(String filePath) throws IOException { return fillModel(MYFOAF_NS, filePath); } /** RDF模型导航:SPARQL查询 - 查询自己name */ private static void sayHelloToMyself(Model model) { String query = generateMyselfSPARQLQuery(); sparql(model, query, "?name"); } private static void sayHelloToGmailFriends(Model model) { String query = generateGmailFriendsSPARQLQuery(); sparql(model, query, "?name"); } /** RDF模型导航:SPARQL查询 - 查询朋友name */ private static void sayHelloToMyFriends(Model model) { String query = generateFriendsSPARQLQuery(); sparql(model, query, "?name"); } /** 在RDF模型中执行SPARQL查询 */ private static void sparql(Model model, String query, String field) { Query q = QueryFactory.create(query); QueryExecution qexec = QueryExecutionFactory.create(q, model); System.out.println("Plan to run SPARQL query: "); System.out.println(BOUNDARY); System.out.println(query); System.out.println(BOUNDARY); ResultSet rs = qexec.execSelect(); while (rs.hasNext()) { QuerySolution qs = rs.nextSolution(); RDFNode name = qs.get(field);// 暂用RDFNode if (name != null) { System.out.println("Hello to " + name); } else { System.out.println("No friends found!"); } } qexec.close(); } private static String generateMyselfSPARQLQuery() { StringBuilder sb = generateSPARQLPREFIX(); // 添加查询语句 sb.append("SELECT DISTINCT ?name").append(NEWLINE).append("WHERE { myfoaf:me foaf:name ?name}").append(NEWLINE); return sb.toString(); } private static String generateGmailFriendsSPARQLQuery() { StringBuilder sb = generateSPARQLPREFIX(); sb.append("SELECT DISTINCT ?name WHERE {?name rdf:type people:GmailPerson}"); return sb.toString(); } private static String generateFriendsSPARQLQuery() { StringBuilder sb = generateSPARQLPREFIX(); sb.append("SELECT DISTINCT ?name").append(NEWLINE).append("WHERE { myfoaf:me foaf:knows ?friend. ").append("?friend foaf:name ?name}") .append(NEWLINE); return sb.toString(); } /** 添加SPARQL查询前缀PREFIX */ private static StringBuilder generateSPARQLPREFIX() { StringBuilder sb = new StringBuilder(); sb.append("PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>").append(NEWLINE).append("PREFIX owl: <http://www.w3.org/2002/07/owl#>") .append(NEWLINE).append("PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>").append(NEWLINE) .append("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>").append(NEWLINE).append("PREFIX foaf: <http://xmlns.com/foaf/0.1/>") .append(NEWLINE).append("PREFIX myfoaf: <http://blog.sina.com.cn/zhoujiagenontology/helloworld.owl#>").append(NEWLINE) .append("PREFIX people: <http://www.people.com#>").append(NEWLINE); return sb; } }