WordNet 是普林斯頓大學的一個研究項目,目標是建立英語詞匯及其詞法關系的數據庫。這樣的工具可以為 XML 語義應用程序建立很好的基礎,比如 Uche Ogbuji 在本專欄以前文章中所提到的能識別同義詞的搜索的例子。本期文章中他回顧了基本原理,給出了查詢 XML 文檔格式的 WordNet 2.0 的代碼,這是構建更通用的 XML WordNet 應用程序的第一步。
我曾經在以前的一期文章中提到過 WordNet,主要討論了在 RDF 格式中的應用。從那以後,又發生了很多變化:WordNet 項目從 1.7 版發展到了 2.0 版,詞匯的分類有一些細微的變化;以前討論的 RDF 表示仍然停留在 WordNet 1.6 ;其間 2.0 版發生了一些變化,不能保持以前所有版本的向後兼容性。
隨著越來越多的開發人員開始關注解決語義透明性問題的方法——這也是整個 Thinking XML 專欄的核心,語義 Web 技術悄然成為主流。在這一領域,更多地討論從這類技術的實用性轉移到了最佳實踐和應用程序接口問題。一些有興趣的團體,包括我本人,繼續尋找利用語義 Web 技術但又不把一切都明確用 RDF 序列化編碼的方法。WordNet 是一個很大的基於數據的項目,數據的基礎都有非常嚴格的定義。其應用也非常廣泛。(以前的文章中我曾經介紹過如何使用 WordNet 為特定的應用程序搜索功能增加更多的智能。)因此,它也不可避免地成為了關於應用語義 Web 技術的討論焦點。
我們將通過一系列文章來重新考察 WordNet 2.0 及其在 XML 和 RDF 技術中的應用,這是第一部分。
建立 WordNet 基礎設施
很多 WordNet 項目由於過時的數據版本而日漸衰微,很多情況是因為沒有解決數據庫格式的轉化問題。我認為,這正說明了討論可重用的創建格式方法的必要性,比如 XML WordNet 文件(可能包括 XML/RDF)。一種好辦法是編寫代碼,從喜歡的編程語言中利用訪問 WordNet 數據庫的很多項目。對於我而言,這種語言自然就是 Python。在 Python 中有兩個適用於 WordNet 的 Python 項目,PyWN 是其中的一個,它也是基於老版本的,因此我選擇使用 PyWordNet(請參閱參考資料)。我已經安裝了 Python 2.4, 下載 PyWordNet 2.0.1 之後使用 Python setup.py install 安裝它。
PyWordNet 沒有附帶 WordNet 數據庫文件,這些文件必須單獨下載。不需要構建 WordNet 包,只要將下載的文件解壓到適當位置就足夠了。PyWordNet 需要的文件放在 dict 子目錄中。 PyWordNet 在 WNHOME 環境變量所指定的位置查找 WordNet 文件,如果沒有在 UNIX 機器上指定該變量,則在默認位置 /usr/local/Wordnet2.0 中查找。設置好這些之後,可以運行 Python -c "from wntools import *" 看看是否正常。我在運行中發現了 4 個以下顯然無害的錯誤消息:
Exception exceptions.AttributeError:
"DbfilenameShelf instance has no attribute 'writeback'" in ignored
我認為,該錯誤消息是由眾所周知的 Python shelve 模塊中的問題造成的,它負責讀入 WordNet 使用的某些散列數據庫文件。雖然出現這些錯誤消息,仍然可以毫無問題的繼續處理。
從數據庫到數據
PyWordNet 通過一些專門的工具方法將 WordNet 數據公開為一組 Python 數據結構。代碼中有很詳細的說明,雖然沒有單獨的說明資料。因此,從 PyWordNet 主頁上的例子入手導航和練習的時候,完全可以使用內置的 Python help 函數。現在的任務是利用這種數據結構創建一個工具將 WordNet 序列化為所需要的 XML。只要很小的代價就可以滿足語義查詢的需要,或者如果願意的話,也可以作為工具的輸入來生成完全獨立的 WordNet 數據文件(關於這種方法以後的文章還將詳細討論)。序列化 WordNet 有很多方法,我們從最簡單的開始:只有少量名稱空間的簡單的老式 XML。這個模塊如清單 1 所示。這些代碼需要 Python 2.2 或更新版本、4Suite 1.0a3 或更新版本以及 PyWordNet 2.0.2(有關的下載細節,請參閱參考資料)。
清單 1. 將 WordNet 2.0 同義詞組序列化為 XML 的 Python 例程(wn-XML-synset-query.py)
import sys
import cStringIO
#Import PyWordNet librarIEs
from wntools import *
#Import 4Suite XML generation librarIEs
from Ft.Xml.Xslt.XmlWriter import XMLWriter
from Ft.XML.Xslt.OutputParameters import OutputParameters
from xml.dom import EMPTY_NAMESPACE, XML_NAMESPACE
def serialize_synset(synset):
'''
Return an XML serialization of a synset as a byte string
'''
#Buffer the output into a byte string
stream = cStringIO.StringIO()
#Set up the XML output parameters
oparams = OutputParameters()
oparams.indent = 'yes'
#Create an XML writer instance
writer = XMLWriter(oparams, stream)
writer.startDocument()
writer.startElement(unicode(synset.pos))
#use the offset as the ID
writer.attribute(u'xml:id', unicode(synset.offset), XML_NAMESPACE)
writer.startElement(u'gloss')
writer.text(unicode(synset.gloss))
writer.endElement(u'gloss')
#Write out the lexical Word forms
for sense in synset:
writer.startElement(u'Word-form')
writer.text(unicode(sense.form))
writer.endElement(u'Word-form')
#Write out all the "pointers" (relationships between Words, or
#to be more precise, between synsets)
for ptr in synset.pointers():
writer.startElement(unicode(ptr.type))
writer.attribute(u'part-of-speech', unicode(ptr.pos))
writer.attribute(u'target', unicode(ptr.targetOffset))
writer.endElement(unicode(ptr.type))
writer.endElement(unicode(synset.pos))
writer.endDocument()
#Extract the text from the buffer
return stream.getvalue()
def serialized_synsets_for_word(Word_form):
'''
Return a list of all serializations of synsets associated
with a Word form
'''
synsets = []
for d in DictionarIEs:
part = d.pos
try:
word = getWord(Word_form, part)
#Get all synonym sets associated with a Word form
#In this part of speech
synsets.extend([ w.synset for w in Word ])
except:
pass
#Iterate over each synset and return the list of serializations
return [ serialize_synset(ss) for ss in synsets ]
PyWordNet 被組織成 4 個詞典,分別對應言語 WordNet 2.0 的 4 個部分 —— 名詞、動詞、形容詞和副詞。詞匯的單詞形式是主鍵,每個記錄都包括含義(sense)、同義詞組(synonym set)、注釋(glosse) 和指針(pointer)。黑體字都是 WordNet 中的常見說法。
我認為,語義透明的多數 WordNet 應用程序都需要處理指針。關於 WordNet 的早期文章中,我對上義/下義關系做了詳細介紹。 根據這個預期的重點,我選擇查詢結果的粒度時以同義詞組的序列化為中心。如果用 serialized_synsets_for_Word_form('selection') 這樣的代碼調用清單 1,得到的結果就是一組 XML 文檔。第一個 XML 文檔如清單 2 所示,第三個文檔如清單 3 所示。(這是從 5 個文件中隨意選擇的。)
清單 2. 關於單詞“selection”的第一個同義詞組
<?XML version="1.0" encoding="UTF-8"?>
<noun XML:id="152253">
<gloss>the act of choosing or selecting; "your choice of colors was
unfortunate"; "you can take your pick"</gloss>
<word-form>choice</Word-form>
<word-form>selection</Word-form>
<word-form>option</Word-form>
<word-form>pick</Word-form>
<hypernym part-of-speech="noun" target="32816"/>
<frames part-of-speech="verb" target="653781"/>
<frames part-of-speech="verb" target="656613"/>
<frames part-of-speech="verb" target="652154"/>
<hyponym part-of-speech="noun" target="152613"/>
<hyponym part-of-speech="noun" target="152749"/>
<hyponym part-of-speech="noun" target="152898"/>
<hyponym part-of-speech="noun" target="153642"/>
<hyponym part-of-speech="noun" target="154057"/>
<hyponym part-of-speech="noun" target="170871"/>
<hyponym part-of-speech="noun" target="173378"/>
</noun>
清單 3. 關於單詞“selection”的第三個同義詞組
<?XML version="1.0" encoding="UTF-8"?>
<noun XML:id="5455460">
<gloss>the person or thing chosen or selected; "he was my pick
for mayor"</gloss>
<word-form>choice</Word-form>
<word-form>pick</Word-form>
<word-form>selection</Word-form>
<hypernym part-of-speech="noun" target="5453619"/>
<frames part-of-speech="verb" target="653781"/>
<hyponym part-of-speech="noun" target="5455670"/>
<hyponym part-of-speech="noun" target="5455968"/>
<hyponym part-of-speech="noun" target="5456920"/>
</noun>
為了更好的格式化,我將 gloss 分成了幾行。這些 XML 結果包含很多值得注意的信息。
文檔中的要點
指針的形式為:
<hypernym part-of-speech="noun" target="32816"/>
屬性 part-of-speech 和 target 提供了在整個 WordNet 數據庫中惟一標識一個同義詞組所需要的全部信息。target 的值表示在原始數據庫中的偏移量。我不知道跨越不同的 WordNet 版本是否安全,但通常不需要這樣做。在特定版本中,可以使用 PyWordNet 的 getSynset 函數解析上述形式中的指針,向其傳遞言語部分和指針中的偏移量。注意,我也在 synset 輸出中通過 xsml:id 使用這些偏移量作為惟一的 XML 標識符(請參閱參考資料)。
結束語
關於 WordNet 作為一項資源的重要價值怎麼說都不嫌多。語義透明性仍然是一個極其困難的問題,但是有這樣的項目為分析單詞之間的關系提供一個計算機可讀的框架將很有幫助。以後的文章中,我准備進一步探討應用程序如何通過編程來使用 WordNet,並以本文中 XML 查詢作為基礎,其中一些文章將涉及到 RDF,另一些則討論普通的 XML,因此這方面不用擔心忽略您喜好的技術。如果對 WordNet 的應用有什麼想法,或者有自己的經驗,請通過 Thinking XML 討論論壇和大家一起分享。