本專欄文章是這個系列的第三部分,它演示了如何通過合並 WordNet 同義詞集將語義知識添加到 RDF 應用程序。有了添加的 WordNet 詞匯數據庫知識,可以一次性搜索具有相關概念的一組 RDF 數據,而不是一次只能搜索一個關鍵字。如同演示問題跟蹤器應用程序所示,那意味著搜索一次以獲得符合“selection”概念的實例,而不是對“vote”、“choice”、“vote”以及 86 個其它的相關術語進行單獨查找。專欄作家 Uche Ogbuji 用 Python 編寫的示例代碼演示了這項技術。
既然我已經在以前的專欄文章裡概述了從 XML 應用程序抽取數據到 RDF 模型中去的基本技術,那麼可以繼續獲取這一工作所帶來的好處。如果最近沒有閱讀過前兩個專題,則在繼續向下讀之前,可能需要回顧一下它們(請參閱本專欄文章右側“內容”表中“相關內容”這一部分中的鏈接)。
您可能會想起演示應用程序是管理以 XML 格式表示的事件數據的問題跟蹤器。至此,本專欄已經涉及了從這些數據抽取 RDF 的技術,以及查詢結果 RDF 模型的基本技術。現在,讓我們來仔細研究一個實例,來說明為什麼這些努力是非常有價值的。
WordNet 簡介
WordNet 是普林斯頓大學的一個項目。該項目被稱為“英語詞匯數據庫”,它是這樣一個系統,通過將同義詞的集合集中到稱為 同義詞集(synonym sets)或 同義集(synsets)的組中來描述和分類單詞和概念。我不能過分吹捧這一重要的長期項目,該項目代表了如此有前景的產業。因為它的開放性意味著實際上任何開發人員都可以使用它,所以它十分重要。WordNet 有“不受限制的”許可證。它很象 BSD 許可證,因為唯一真正的限制是不可以盜用普林斯頓大學的商標來宣傳 WordNet 的任何派生產品。
必須指出的是,智力勞動的一些最重要的成果被自由用於公益事業總是件好事。這些天,我們經常聽到太多有關一些組織企圖通過免費獲取公共知識但又拒絕無償做出貢獻來獲取可能有問題的利潤的新聞。
WordNet 目前的版本是 1.7,它包括一個表示成千上萬名詞的同義集詞匯表。同義集是有關大量概念(包括 上義關系(hyponyms))、其它概念類型的概念以及子類( 上義關系(hypernym)是下義關系的超類)。WordNet 還包含相似但不同義的概念之間的映射。
普林斯頓分發的 WordNet 本身是作為用於各種平台的數據文件和命令行查詢工具。許多項目都對 WordNet 進行了更改和增強,並且由於它表示了構造如此良好的資源網絡,所以 RDF 社區對采用 WordNet 尤為積極。幾個相關的項目包括 Dan Brickley 的用於 Web 的 WordNet,和 Jonathan Borden 博士的將其改寫成可浏覽的 XHtml 格式。在本文中,我使用了從 WordNet 數據庫到 RDF 的直接轉換,感謝 Sergey Melnik 和 Stefan Decker,和 Brickley 和 Borden 一樣,他們倆都忙碌於 RDF 社區。我所提到的大多數項目(包括這裡使用的 Melnik 和 Decker RDF 轉換)仍然是基於 WordNet 1.6。
安裝 WordNet/RDF
本專欄舉例說明了使用 RDF 工具和 WordNet RDF 模型將語義特性添加到 RDF 構建的問題跟蹤器。可以使用任何 RDF 工具,對其作一些更改來遵循該過程。我將使用我公司的開放源碼 4Suite 的 4RDF。以 RDF 形式表示的 WordNet 非常巨大,因此將使用 4RDF 的持久數據庫後端來管理 WordNet。4RDF 允許在內存中管理這些模型(這也是到目前為止本系列中一直使用的方法),它也允許在持久存儲(以平面文件的形式存儲的諸如 PostgreSQL 和 Oracle 這樣的 SQL DBMS 中,或存儲在我所編寫的實驗性定制 RDF 後端 Mangrove 中)中管理模型。因為 Mangrove 將可能在 4Suite 的下一個發行版本 0.12.0 中首次出現,而它在發行之前是不能出現的,所以本專欄文章中的示例使用 PostgreSQL。PostgreSQL 是開放源代碼,企業級的關系數據庫,許多 Linux 的分發版(distribution)都帶有它,並且還有可供許多其它平台使用的包。
要安裝它,請首先下載 WordNet/RDF 文件。我必須修正幾個地方,因為 Wordnet_hyponyms-20010201.rdf 文件被毀壞。我將 58268 行
<rdf:Descripout="&a;103178459">
修改為
<rdf:Description rdf:about="&a;103178459">
將 109228 行
<b:hyponymOf rdf:resof rdf:resource="&a;105862019"/>
修改為
<b:hyponymOf rdf:resource="&a;105862019"/>
接下來,(對於語義問題跟蹤器)將名詞和下義關系數據庫 WordNet RDF 文件添加到基於 PostgreSQL 名為 sit的 RDF 模型:
清單 1. 將 WordNet RDF 文件添加到名為 sit 的數據庫 RDF 模型中
$ 4rdf --driver=Postgres --dbName=sit Wordnet_nouns-20010201.rdf
$ 4rdf --driver=Postgres --dbName=sit Wordnet_hyponyms-20010201.rdf
如同在清單 1 中所見到的一樣,必須指定 Postgres 驅動程序,這需要指定數據庫名稱。如果具有該名稱的數據庫不存在,那麼將創建該數據庫;如果該數據庫存在,將向該數據庫中添加生成的語句。
在返回到問題跟蹤器之前,請試著在目前所創建的 WordNet 模型上運行簡單的測試腳本。
清單 2:練習 WordNet RDF 模型的小測試程序(wn-test.py)
from Ft.Rdf.Drivers import Postgres
from Ft.Rdf import Model, Util
WN_RDF_BASE = "http://www.cogsci.princeton.edu/~wn/schema/"
def Test():
db = Postgres.GetDb('Wordnet')
db.begin()
m = Model.Model(db)
print "Size of the model (number of statements): ", m.size()
print "Synonyms of the Word 'knowledge':"
noun = Util.GetSubject(m, WN_RDF_BASE+'WordForm', 'knowledge')
print Util.GetObjects(m, noun, WN_RDF_BASE+'WordForm')
print "Classification chain for 'knowledge':"
HypernymChain(noun, 'knowledge', m)
db.rollback()
return
def HypernymChain(noun, wform, m):
hyper = Util.GetObject(m, noun, WN_RDF_BASE+'hyponymOf')
if hyper:
hwform = Util.GetObject(m, hyper, WN_RDF_BASE+'WordForm')
print "%s is a kind of %s"%(wform, hwform)
HypernymChain(hyper, hwform, m)
return
if __name__ == "__main__":
Test()
在清單 2 中, Postgres.GetDb('sit') 建立到所創建的 RDF 數據庫後端的連接。在建立該連接之後,在後端開始了一個事務,並使用它來建立可供查詢的模型對象。首先,只要查看一下模型中的語句的數目。然後,使用在上一篇文章中所介紹的一些 RDF 查詢的基本類型來查找單詞 “knowledge”的同義詞,並跟蹤概念間分類鏈。
WordNet/RDF 以如下形式使用 URI
http://www.cogsci.princeton.edu/~wn/concept#100001740
來表示名詞同義集,其中 100001740 是同義集的標識符。然後,每個詞(同義集中的每一個詞)都有一條 WordForm 語句。如果適當,還有一條 hyponymOf 語句以將每個同義集同其超類相聯系。因此,測試程序按照這一模式使用幾個簡單查詢就可以獲取同義詞。 HypernymChain 是遞歸函數,該函數先取得同義集資源以及同義詞中的某一詞的單詞形式,然後查找上義關系。將該清單保存到稱為 wn-test.py 的文件中,並按如下所示運行它:
$ Python wn-test.py
Size of the model (number of statements): 351632
Synonyms of the Word 'knowledge':
['cognition', 'knowledge']
Classification chain for 'knowledge':
knowledge is a kind of psychological feature
問題跟蹤器詞匯層
上一個專題論述了為了抽取序列化 RDF 如何轉換多個 XML 文件,然後如何通過 RDF 處理器傳遞結果。現在該是將那些語句添加到含有 WordNet 語句的同一個模型中的時候了:
$ 4rdf --driver=Postgres --dbName=sit issues.rdf
該代碼再一次指定 Postgres 驅動程序以及與前面相同的數據庫名稱,但是,這一次它從 issues.rdf 文件讀取數據,如果還記得的話,該文件包含從樣本問題跟蹤器文件中抽取的元數據。
現在,可以重新運行我們已經見過的查詢,但這次具有語義能力。例如,在上一個專題中,演示了使用正則表達式查找賦予 uogbuji所有操作(這些操作的主體裡含有字符串 vote)的查詢示例。現在,比如說,想查找賦予 uogbuji有關一般意義上“選擇”的所有操作。這時,不用再查找一些字符串模式,取而代之的是,需要語言認知層上的真正詞匯模式。正在查找的單詞都帶有“selection”的含義:不僅僅是 “vote”,而且還有 “choice”和 “ballot”。
清單 3 是執行該搜索的程序。
清單 3:使用 WordNet,通過英語語義概念執行搜索的程序(seman-search.py)
from Ft.Rdf.Drivers import Postgres
from Ft.Rdf import Model, Util
from Ft.Rdf.Model import REGEX
USER_ID_BASE = 'http://users.rdfinference.org/ril/issue-tracker#'
IT_SCHEMA_BASE = 'http://XMLns.rdfinference.org/ril/issue-tracker#'
WN_RDF_BASE = "http://www.cogsci.princeton.edu/~wn/schema/"
g_relatedWords = []
def SemanSearch(Word):
db = Postgres.GetDb('Wordnet')
db.begin()
model = Model.Model(db)
#Find the synset resource of which we have the Word form
noun = Util.GetSubject(model, WN_RDF_BASE+'wordForm', Word)
print 'Actions assigned to uogbuji related to "%s":'%(Word)
#Get all Word forms of this synset and its hyponyms
HyponymWords(noun, model)
#Combine all the Words into one large regular expression
pattern = ".*" + "|".join(g_relatedWords) + ".*"
#Use this regex to search for the appopriate concepts
actions = Util.GetSubjects(model, IT_SCHEMA_BASE+'body', pattern,
objectFlags=REGEX)
#Iterate over the bodIEs of the matching actions
for action in actions:
#See if this action is assigned to uogbuji
assignee = Util.GetObject(model, action, IT_SCHEMA_BASE+'assign-to')
body = Util.GetObject(model, action, IT_SCHEMA_BASE+'body')
if assignee == USER_ID_BASE+'uogbuji':
print "*", body
db.rollback()
return
def HyponymWords(noun, model):
words = Util.GetObjects(model, noun, WN_RDF_BASE+'WordForm')
print "words", Words
g_relatedWords.extend(Words)
hypos = Util.GetSubjects(model, WN_RDF_BASE+'hyponymOf', noun)
print "hypos", hypos
for h in hypos:
HyponymWords(h, model)
return
if __name__ == "__main__":
import sys
SemanSearch(sys.argv[1])
在清單 3 中, SemanSearch 是主函數。它從訪問帶有 WordNet 和問題跟蹤器數據的 RDF 模型開始執行。該函數帶有一個 word 參數:作為概念性搜索基礎的單詞。第一步是將該單詞轉換到 WordNet 同義集資源。然後,該程序將該同義集所有其它單詞形式(同義詞),以及下義關系同義集中所有單詞形式添加到搜索列表。例如,在給定最初的概念: “selection”的情況下開始搜索,清單 4 顯示了這次搜索到的所有 89 個與“selection”的單詞。
清單 4. 搜索“selection”的同義詞和下義關系的結果
['choice', 'pick', 'selection', 'casting', 'sampling', 'random
sampling', 'proportional sampling', 'representative sampling',
'stratifIEd sampling', 'conclusion', 'decision', 'determination',
'appointment', 'assignment', 'designation', 'naming', 'nominating',
'nomination', 'co-optation', 'co-option', 'delegacy', 'ordaining',
'ordination', 'laying on of hands', 'call', 'move', 'demarche',
'maneuver', 'maneuvering', 'manoeuvering', 'manoeuvre',
'tactical maneuver', 'tactical manoeuver', 'parking', 'device',
'gimmick', 'twist', 'fast one', 'trick', 'feint', 'gambit', 'ploy',
'stratagem', 'artifice', 'ruse', 'measure', 'step', 'countermeasure',
'countermine', 'porcupine provision', 'shark repellent', 'golden
parachute', 'greenmail', 'pac-man strategy', 'poison pill', 'suicide
pill', 'safe harbor', 'scorched-earth policy', 'casting lots', 'drawing
lots', 'sortition', 'finding', 'finding of fact', 'verdict', 'compromise
verdict', 'quotIEnt verdict', 'directed verdict', 'false verdict',
'general verdict', 'partial verdict', 'special verdict', 'conclusion
of law', 'finding of law', 'volition', 'willing', 'election', 'co-optation',
'co-option', 'ballot', 'balloting', 'vote', 'voting', 'secret ballot',
'split ticket', 'straight ticket', 'multiple voting', 'casting vote',
'veto', 'pocket veto']
為了對該搜索列表中的單詞(問題操作)執行一次性搜索,該程序將這些單詞形式放進了一個大的正則表達式。然後,如同以前專欄文章所說明的那樣,操作結果列表進一步縮小到賦給“uogbuji”的操作。以下是運行清單 3 中程序(seman-search.py)的結果:
$ Python seman-search.py selection
Actions assigned to uogbuji related to "selection":
* Organize a vote on this topic
在命令行中傳入基本概念(這裡是 “selection”),並且打印匹配的操作。
並非一切都十全十美
當然,這種語義搜索方法還有些問題。最明顯的是性能問題。WordNet/RDF 圖表的大小使得遍歷的代價非常高昂。以上面的樣本會話為例,使用 “selection”作為搜索的基本概念,在 PIII 1GHz 膝上電腦上運行,花了兩分多鐘,嚴重影響了磁盤上的 DBMS。幾乎所有時間都花在遞歸向下遍歷下義關系鏈上。如果搜索諸如 “thing”這樣抽象的概念,我幾乎不敢推測這要花多長時間,它可能會將機器掛起(也可能使機器崩潰)。
和以前專題中一樣,存在該問題的部分原因是這個示例仍然使用一些真正的蠻力的方法來查詢 RDF 模型。它沒有真正地利用任何優化。當在本系列中隨後的文章中,討論 RDF Inference Language (RIL)時,將提出一些優化措施。然而,即便經過優化,象這樣功能強大的搜索可能還是有一些難以解決的性能問題。
可以通過策略來處理一些性能問題。譬如,可以禁止搜索超過某一抽象級別。一個比較原始的用以衡量抽象級別的標准,可能是從同義集到它的最遠下義關系的最長距離。由於大多數的處理時間花費在遍歷 WordNet 圖表上,因此另外一個可能的解決方案是,通過使用搜尋器(crawler)以准備相關概念的列表,來優化常見搜索。
另外一個問題是,在 WordNet 上所做的努力還不夠。WordNet 中幾乎映射了所有的常用的名詞或名詞詞組,但卻沒有映射動詞、修飾語以及語言的其它部分。這一點限制了搜索。而且,還有一個事實,WordNet 是英語項目,因此其它語言可能還無法用這種具有強大功能的語義搜索。現在 EuroWordNet 在開發針對歐洲語言的映射,但它仍處於開發之中。當然,還有許多重要的語系,諸如東亞和中東,可能還沒有這樣的設施。
結束語
我一直很高興地看到人們對我通過使用 RDF 語義查詢使用 RDF 所引起的種種可能性進行演示所產生的興奮反應。它能幫助人們了解半結構化關系和元數據管理的價值,因此這簡直是恩賜,因為向生意人甚至許多開發人員解釋這一概念都不是一件容易的事。我將通過討論 RDF 驅動的問題跟蹤器的詳細信息,來繼續探索使用知識管理以改進應用程序。然而,在下一專題中,將暫時放下這一點,先討論我們在本專欄早些時候討論的一些事物的更新。