本文簡單介紹Jena(Jena 2.4),使用Protégé 3.1(不是最新版本)創建一個簡單的生物(Creature)本體,然后參照Jena文檔中的一個例子對本體進行簡單的處理,輸出本體中的Class、Property等信息。
本文內容安排如下:
Ø 介紹Jena
Ø 運行Jena
Ø Jena Ontology API
Ø 例子
Ø 參考資料
一、介紹Jena
Jena由 HP Labs(http://www.hpl.hp.com)開發的Java開發工具包, 用於Semantic Web(語義網)中的應用程序開發;Jana是開源的,在下載的文檔中有Jena的完整代碼。Jena框架主要包括:
a) 以RDF/XML、三元組形式讀寫RDF
資源描述框架是(RDF)是描述資源的一項標准(在技術上是W3C的推薦標准),Jena文檔中有一部分呢詳細介紹了RDF和Jena RDF API,其內容包括對Jena RDF包的介紹、RDF模型的創建、讀寫、查詢等操作,以及RDF容器等的討論。
b) RDFS,OWL,DAML+OIL等本體的操作
Jena框架包含一個本體子系統(Ontology Subsystem),它提供的API允許處理基於RDF的本體數據,也就是說,它支持OWL,DAML+OIL和RDFS。本體API與推理子系統結合可以從特定本體中提取信息,Jena 2還提供文檔管理器(OntDocumentManager)以支持對導入本體的文檔管理。
c) 利用數據庫保存數據
Jena 2允許將數據存儲到硬盤中,或者是OWL文件,或者是關系數據庫中。本文處理的本體就是OWL文件讀入的。
d) 查詢模型
Jena 2提供了ARQ查詢引擎,它實現SPARQL查詢語言和RDQL,從而支持對模型的查詢。另外,查詢引擎與關系數據庫相關聯,這使得查詢存儲在關系數據庫中的本體時能夠達到更高的效率。
e) 基於規則的推理
Jena 2支持基於規則的簡單推理,其推理機制支持將推理器(inference reasoners)導入Jena,創建模型時將推理器與模型關聯以實現推理。
Protégé是一個開源的本體編輯器(目前的版本是Protégé 3.2),用戶可以在GUI環境下創建本體或者知識庫。有一種說法是:Jena對應用程序就像Protégé對我們——我們使用Protégé操作本體,應用程序則是使用Jena來做同樣的工作。當然這些應用程序還是得由我們來編寫。
二、運行Jena
可以在Jena的主頁(http://jena.sourceforge.net/downloads.html)下載Jena的最新版本,目前是Jena2.4版本。Jena是Java API,所以需要Java運行環境。本文使用的是jdk1.5.0_04和Eclipse3.2。
將下載的Jena-2.4.zip解壓到任意路徑,解壓之后生成Jena2.4文件夾,將Jena2.4 lib下的jar文件全部加入CLASSPATH,這樣就可以在任意的Java編輯器中調用Jena API了。在解壓目錄下有一個test.bat文件,用於配置的測試。在控制台運行此程序,如果你的配置正確,測試將順利完成。
如果使用Eclipse,則可以通過修改工程的Java創建路徑的方法導入Jena jar文件。在Eclipse下創建Java工程,右健單擊工程名字,選擇“屬性/Properties”,在打開的對話框中選擇“Java創建路徑/Java Build Path”,在右邊標簽中選擇“庫/Libraries”,之后選擇“添加外部文件/Add Extenal JARs”,找到Jena2.4 lib目錄下的所有jar文件並將其添加到工程。這樣就可以運行Jean文檔中的例子了。
三、Jena Ontology API
Jena2.4的Ontology API包含在ontology包(com.hp.hpl.jena.ontology)中,可以在目錄 Jena-2.4 src com hp hpl jena ontology下查看所有程序的代碼,Jena本體部分的說明網頁是 Jena-2.4 doc ontology index.html,本部分內容以及程序的編寫主要參考這兩個文檔。
在語義網上有很多表示本體信息的本體語言,其中表達能力最強的是OWL,OWL按復雜程度分為 OWL Full、OWL DL和OWL Lite三個版本。其他的本體語言還有RDFS、DAML+OIL。Jena Ontology API為語義網應用程序開發者提供了一組獨立於具體語言的一致編程接口。
Jena提供的接口本質上都是Java程序,也就是.java文件經過javac之后生成的.class文件。顯然,class文件並不能提示本體創建使用的語言。為了區別於其他的表示方法,每種本體語言都有一個自己的框架(profile),它列出了這種語言使用的類(概念)和屬性的構建方式和URI。因此,在DAML框架里,對象屬性()的URI是daml:ObjectProperty,而在OWL框架里卻是owl:ObjectProperty。RDFS並沒有定義對象屬性,所以在RDFS框架里,對象屬性的URI是null。
在Jena中,這種框架通過參數的設置在創建時與本體模型(Ontology Model)綁定在一起。本體模型繼承自Jena中的Model類。Model允許訪問RDF數據集合中的陳述(Statements),OntModel對此進行了擴展,以便支持本體中的各種數據對象:類(classes)、屬性(properties)、實例(個體individuals)。
本部分簡單介紹要用到的幾個java類或者接口。
1.本體模型OntModel
本體模型(OntModel)是對Jena RDF模型的擴展(繼承自RDF模型),提供了處理本體數據的功能。使用Jena處理本體首先就是要建立一個本體模型,之后就能夠通過本體模型中所定義的方法操作模型,比如導入子模型()、獲取模型中本體的信息、操作本體屬性以及將本體的表示輸出到磁盤文件等等。Jena通過model包中的ModelFactory創建本體模型,ModelFactory是Jena提供用來創建各種模型的類,在類中定義了具體實現模型的成員數據以及創建模型的二十多種方法。一個最簡單的創建本體模型的語句如下:
OntModel ontModel = ModelFactory.createOntologyModel();
該語句不含參數,應用默認設置創建一個本體模型ontModel,也就是說:它使用OWL語言、基於內存,支持RDFS推理。可以通過創建時應用模型類別(OntModelSpec)參數創建不同的模型,以實現不同語言不同類型不同推理層次的本體操作。例如,下面的語句創建了一個使用DAML語言內存本體模型。直觀地講,內存模型就是只在程序運行時存在的模型,它沒有將數據寫回磁盤文件或者數據庫表。
OntModel ontModel = ModelFactory.createOntologyModel( OntModelSpec.DAML_MEM );
更多類型設置可以參照OntModelSpec類中的數據成員的說明。
我們所使用的本體是從OWL文件獲得的,也就是說,是從磁盤讀取的。讀取的方法是調用Jena OntoModel提供的Read方法。例如
ontModel.read("file:D:/temp/Creatrue/Creature.owl");
就是讀取位於D盤相應目錄下的Creature.owl文件以建立本體模型。Read方法也有很多重載,上面調用的方法以文件的絕對路徑作為參數。其他的方法聲明如下
read( String url );
read( Reader reader, String base );
read( InputStream reader, String base );
read( String url, String lang );
read( Reader reader, String base, String Lang );
read( InputStream reader, String base, String Lang );
2.文檔管理器Document manager
本體文檔管理器(OntDocumentManager)是用來幫助管理本體文檔的類,它包含了導入本體文檔創建本體模型、幫助緩存下載網絡上的本體等功能。每個本體模型都有一個相關聯的文檔管理器。在創建本體模型時,可以創建獨立的文檔管理器並作為參數傳遞給模型工廠(ModelFactory)。文檔管理器有非常多的配置選項,基本可以滿足應用的需求。首先,每個文檔管理器的參數都可以通過Java代碼來設置(注:OntDocumentManager有五種重載的構造函數)。另外,文檔管理器也可以在創建的時候從一個RDF格式的策略文件讀取相應設定值。
下面的例子創建一個文檔管理器並將它與以創建的本體模型關聯。
OntModel m = ModelFactory.createOntologyModel();
OntDocumentManager dm = m.getDocumentManager();
3.接口OntClass
這個接口中定義了本體種與概念(也就是類Class)相關的操作,通過OntModel中的listClasses()
便可以返回模型中的所有概念組成的迭代器(Iterator),然后調用OntClass的各種方法具體進行具體操作。OntoClass對概念之間的各種關系都有相應的定義方法,典型的有添加子類、添加約束、創建互斥概念、迭代返回某種類型的概念以及相關的邏輯判斷等等。
第四部分的例子主要是應用這個類的方法。
4.基本本體類型OntResource
所有本體API中用於表示本體的類繼承自OntResource,這樣就可以在OntResource中放置所有類公用的功能,並可以為一般的方法設置通用的返回值。Java接口OntResource擴展了Jena的RDF資源接口,所以任何可以接受資源或者RDFNode的方法都可以接受OntResource,並且也就可以接受任何其他本體值。雖然這個類涵蓋了涉及本體的所有類,在例子中並沒有使用它。從Jena Java Doc可以獲得它的詳細信息。
四、例子
本文實現了一個簡單的例子。通過Protégé 3.1創建一個Creature本體,並將其存儲到OWL文件Creature.owl,然后使用和Jena通過讀取該文件創建本體模型,實踐Jena中的一些Ontology API。本文不涉及如何使用Protégé 3.1創建本體,您可以到Protégé的主頁或者是http://www.chengtao.name/modules/wordpress/尋找詳細的資料,后者雖然只是一個博客,但確實提供了很多我們需要的資源,比如一個完整的Protégé使用教程。本文例子中對Jena的使用主要參照Jena文檔中 Jena-2.4 src-examples jena examples ontology下面的describeClass。它讀取food.owl和wine.owl兩個文件建立本體模型,並顯示模型中概念以及相關關系的詳細信息。DescribeClass.java主要負責查詢詳細信息並顯示出來,Main.java只是創建本體模型並調用DescribeClass.java的功能。
例子的主要代碼如下列出。
// 創建使用OWL語言的內存模型
OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
ontModel.read("file:./Creature.owl"); // 讀取當前路徑下的文件,加載模型
// 定義一個類作為模型中Animal類的等等價類,並添加注釋
OntClass cls = ontModel.createClass(":DongwuClass");
cls.addComment("the EquivalentClass of Animal...", "EN");
// 通過完整的URI取得模型中的Animal類
OntClass oc = ontModel.
getOntClass("http://www.owl-ontologies.com/marine.owl#Animal");
oc.addEquivalentClass(cls); // 將先前定義的類添加為Animal的等價類
// 迭代顯示模型中的類,在迭代過程中完成各種操作
for (Iterator i = ontModel.listClasses(); i.hasNext();) {
OntClass c = (OntClass) i.next(); // 返回類型強制轉換
if (!c.isAnon()) { // 如果不是匿名類,則打印類的名字
System.out.print("Class");
// 獲取類的URI並輸出,在輸出時對URI做了簡化(將命名空間前綴省略)
System.out.println(c.getModel().getGraph().
getPrefixMapping().shortForm(c.getURI()));
// 處理Animal類
if (c.getLocalName().equals("Animal")) { // 如果當前類是Animal
System.out.println(" URI@" + c.getURI()); // 輸出它的完整URI // 取得它的的等價類並打印
System.out.print(" Animal's EquivalentClass is "+
c.getEquivalentClass());
// 輸出等價類的注釋
System.out.println(" [comments:" +
c.getEquivalentClass().getComment("EN")+"]");
}// 處理Animal結束
// 迭代顯示當前類的直接父類
for (Iterator it = c.listSuperClasses(); it.hasNext();)
{
OntClass sp = (OntClass) it.next();
String str = c.getModel().getGraph()
.getPrefixMapping().shortForm(c.getURI()) // 獲取URI
+ "'s superClass is " ;
String strSP = sp.getURI();
try{ // 另一種簡化處理URI的方法
str = str + ":" + strSP.substring(strSP.indexOf('#')+1);
System.out.println(" Class" +str);
}catch( Exception e ){}
} // super class ends
// 迭代顯示當前類的直接子類
for (Iterator it = c.listSubClasses(); it.hasNext();){
System.out.print(" Class");
OntClass sb = (OntClass) it.next();
System.out.println(c.getModel().getGraph().getPrefixMapping()
.shortForm(c.getURI())+ "'s suberClass is "
+ sb.getModel().getGraph().getPrefixMapping()
.shortForm(sb.getURI()));
}// suber class ends
// 迭代顯示與當前類相關的所有屬性
for(Iterator ipp = c.listDeclaredProperties(); ipp.hasNext();){
OntProperty p = (OntProperty)ipp.next();
System.out.println(" associated property: " + p.getLocalName());
}// property ends
}// anonymity ends
else // 是匿名類
{}
}// for ends
部分輸出結果如下,說明部分不在輸出中。
Class:Animal
URI@http://www.owl-ontologies.com/marine.owl#Animal // 完整的URI
// 等價類及其注釋
Animal's EquivalentClass is :DongwuClass [comments:the EquivalentClass of Animal...] Class:Animal's superClass is :Creature // 直接父類
Class:Animal's suberClass is :MixAnimal // 直接子類
Class:Animal's suberClass is :GrassAnimal
Class:Animal's suberClass is :MeatAnimal
associated property: eat // 關聯屬性
associated property: beEated
associated property: mainEat
后注:該例子沒有涉及Jena的推理功能,沒有實現屬性的過濾(只返回以當前類為主體的屬性),不能輸出間接父類(父類的父類)或間接子類,等等。因此,有待對Jena進一步熟悉之后作更多的改進。
五、參考資料
[1] Jena-2.4 doc ontology Jena 2 Ontology API文檔
[2] Jena-2.4 doc javadoc Jena 2 Java文檔
[3] Jena-2.4 src-examples jena examples ontology describeClass
[4] http://www.chengtao.name/modules/wordpress 維基博客
http://marine02.blog.163.com/blog/static/10656842006111210338756/#