owl_cpp,一個用於操作OWL本體的C++類庫(owl_cpp, a C++ Library for Working with OWL Ontologies)

說明:由於我近期工作涉及生物本體,然而國內有關本體的時新文章較少,因此翻譯ICBO2011會議的部分論文,與本體領域的研究者和愛好者分享。本人翻譯水平有限,如果大家英文水平不錯,還是推薦直接看原文。


摘要:這裏我們介紹owl_cpp(http://sf.net/projects/owl-cpp/),它是一個開源的C++類庫,用於對OWL2本體進行語法分析、查詢和推理。owl_cpp使用Raptor、FaCT++和Boost類庫。它用標準C++編寫而成,因此在大部分的平臺均可使用。owl_cpp執行嚴格的語法分析,能夠檢測出被其他語法分析器所忽略的錯誤。這一類庫的另外一個優點就是它有很高的性能,並且是一個緊湊的內存內部表示。


1 引言

OWL(Web Ontology Language)是語義網技術的一種,它被設計用來形式化地表示人類知識以促進對它的計算分析和解釋。OWL和其他語義網技術一樣,都成功地應用於生物醫學的諸多領域。它們的成功部分來源於用來支持語義網的軟件的廣泛開發。

運用本體時經常涉及一些任務,如:對OWL文檔進行語法分析,查詢它們的內存內部表示,將信息傳送到描述邏輯(Description Logic,DL)推理機(reasoner),以及執行DL查詢等。在計算機內存中,本體或者被表示爲RDF三元組(triple),或者是公理(axiom)和註釋(annotation)。三元組是一種簡單的描述方式,包括三個節點,其中謂詞(predicate)節點表達主體(subject)節點和客體(object)節點之間的關係。雖然三元組的集合可以表示一個複雜的相互關聯的實體圖,在計算機內存中,還是存儲爲統一的數組更方便高效地搜索和查詢。所以當需要高效執行相對簡單的查詢時,我們使用三元組存儲。公理是對本體中類與實例的描述。每一個公理可以被看做是一個對應於一個或多個RDF三元組的圖。因爲公理比三元組更復雜,因此對它們的查詢也更低效。然而,在推理機的幫助下,它可以執行更復雜的DL查詢,並且發現本體包含的潛在知識。

儘管已有充分開發的軟件可用,處理大量生物醫學本體仍然面臨挑戰。我們面臨的部分問題有:

a) 檢測並消除OWL文檔中的錯誤;

b) 有些高性能計算平臺缺乏對Java虛擬機的支持;

c) 用C++、Python、Perl等編程語言編寫的語義網工具十分有限;

d) 本體內存內部表示的開銷大;

e) 語法分析和查詢的性能較差。

爲了處理這些問題,我們開發了owl cpp。它是一個用來對本體進行語法分析、查詢和推理的類庫。它的關鍵特色包括:

a) 嚴格的語法分析,能夠檢測OWL文檔中的錯誤;

b) 用標準C++編寫,在大部分平臺上均可編譯;

c) 無需虛擬機;

d) 能夠爲諸如Java、Perl、Python等其他編程語言創建高效的API;

e) 內存開銷小;

f) 高性能。


2 實現

owl_cpp能支持下面幾種基本操作:

a) 在用戶提供的地點對OWL2和RDF/XML文檔編制目錄;

b) 對OWL2和RDF/XML文檔進行語法分析;

c) 對RDF三元組表示的結果進行存儲和檢索;

d) 將三元組轉化爲公理,並將其加載到推理機中;

e) 執行描述邏輯查詢。

上述功能是按下面的準則予以實現的:

  • 正確性和可重複性應當通過大量單元測試來驗證
  • 嚴格的句法驗證在語法分析和公理生成過程中應當被執行以防止可能的語法錯誤
  • 錯誤提示應當包括足夠的信息以找到並糾正錯誤
  • 性能無論在速度上還是內存開銷上都應當最大化以保證可以處理大規模本體
  • 可移植性應當通過僅使用標準C++特性來實現
  • 可維護性應當通過將owl_cpp設計爲解耦合模塊結構以及採用良構建的類庫如C++標準類庫、Boost等來實現

當前,owl_cpp由三個模塊組成。語法分析模塊是用C++對Raptor進行的包裝。Raptor是一個流行的用C語言寫成的對RDF進行語法分析的類庫。據我們所知,Raptor是目前活躍開發的RDF語法分析器中唯一用C/C++編寫的。爲了解析XML,Raptor使用Libxml2類庫的SAX接口。owl_cpp僅從STL輸入流和用戶指定的文件系統位置中讀入本體。雖然Raptor默認試圖從互聯網上獲取本體,但是在owl_cpp中,出於可靠性、安全性和性能的考慮,該功能被禁止。

三元組存儲模塊負責存儲、檢索和獲取RDF三元組。存儲內部爲命名空間URI、節點和三元組提供獨立的容器。容器通過將其與輕量ID映射的方式來追蹤客體。通過這種ID獲取客體就像數組索引一樣高效。每一個RDF三元組被存儲在其對應節點的三個ID中。雖然一個本體文檔中同一節點可能多次出現,但同一個節點在存儲時僅保存一個實例。

對三元組的檢索非常頻繁,因此該操作應當充分優化。雖然該任務明確易懂,然而潛在的排列組合總數卻使之變得複雜。根據用戶給出的節點ID,我們可以用八種不同的方式來檢索該三元組:通過主體,通過謂詞,通過客體,或者通過上述三者任何一個的組合,包括不提供ID時的組合和返回存儲的所有三元組的配置。此外,作爲檢索的結果,用戶可能對返回的三種類型的結果感興趣:一個匹配給出ID的三元組的完整列表,只顯示找到的第一個三元組,僅通過一個布爾值表明該檢索是否成功。對上面八種檢索配置的任意一種情況,用戶都可能需要這三種類型的結果,因此可能的組合總數是24。

很顯然,要爲每一個檢索組合實現一個單獨的方法不可避免地會造成混亂。而另一方面,要實現一個完成所有檢索組合的方法又難免要犧牲性能。所以,根據“you pay only for what you use”原則,該檢索使用非成員模板函數實現,它既能接受Node_id類型,又能接受Blank類型。返回值是boost::iterator_range,它可以隱式地轉換爲一個布爾類型或者用於對匹配三元組的進行迭代。

推理模塊的功能是用FaCT++來實現的。FaCT++也是據我們所知唯一一個開源的C/C++編寫的DL推理機類庫。owl_cpp通過將三元組轉換爲公理來將三元組存儲的信息傳遞給FaCT++。當前該轉換採用了訪問者設計模式。在owl_cpp提供的參與者和謂詞類的輔助下,DL查詢可以直接通過FaCT++接口來執行。

 

3 結果與討論

owl_cpp的接口被設計用來簡化本體的基本操作。例如,我們可以通過調用load("ontology.owl", store)將文件ontology.owl讀入並存儲爲三元組。我們想要根據輸入流、本體ID的目錄和位置來加載本體,我們可以用這樣的語句:load("ontology.owl", store, catalog)

一旦加載入內存,三元組即可被查詢。例如,表達式find_triples(blank, T_rdf_type::id(), Towl Class::id(), store)能夠找到聲明類的所有三元組。通過調用add(store, kernel),公理可以從三元組存儲store複製到FaCT++推理內核kernel。

owl_cpp語法分析和推理的準確性可以通過許多本體來得到驗證。一些較小的OWL文檔被合併入單元測試,這樣保證了它們的一致性和可滿足性。在開發生物代謝途徑本體時,我們通過執行領域專家構建的DL查詢並與protege(FaCT++和HermiT推理機)得出的結果進行比較來完成了更近一步的測試。結果是一致的。

owl_cpp與其他OWL類庫相比的一個優點就是它能夠發現語法錯誤,這樣就阻止不正確的語義插入本體。在我們小組的本體開發過程中,owl_cpp已經檢測出不一致的輸入表述,未聲明的屬性和註釋謂詞,拼寫錯誤的標準OWL術語以及其他問題。owl_cpp的語法分析性能使用OWL/RDF格式的OpenGALEN本體(版本8)進行測試。該本體佔硬盤大小0.5GB,包括970萬個三元組。糾正幾個錯誤如將owl:propertyChain替換爲owl:propertyChainAxiom之後,它們的語法分析是成功的。語法分析的速率估計爲每秒10萬8千個三元組。該處理的瓶頸出現在將新術語插入三元組存儲的時候。我們正在研究將該步驟流水線化的方法。

owl_cpp未來的開發包括下面幾項任務:

a) 爲語法分析、三元組存儲和推理機定義更高水平的C++ API;

b) 設計基於公理的API;

c) 提高錯誤消息的可讀性;

d) 爲其他編程語言設計API;

e) 爲其他OWL2句法提供支持,如Manchester,Turtle,OWL/XML;

f) 爲批處理執行OWL2的測試用例設計模塊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章