-- 作者:oceans
-- 发布时间:3/3/2005 3:24:00 PM
-- Thinking XML: 查询 XML 格式的 WordNet
使用英语词汇数据库建立语义 XML 应用程序的基础 级别: 中级 Uche Ogbuji (uche.ogbuji@fourthought.com) 首席顾问, Fourthought, Inc. 2005 年 2 月 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 中的常见说法。 同义词组(synset):一组同义词 —— 含义基本相同的概念。 含义:特定词汇的特殊含义;通过特定的词汇形式说明同义词组中各词的细微差别。 注释:同义词组的简短定义。 指针:同义词组之间的关系。 我认为,语义透明的多数 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 讨论论坛和大家一起分享。
|