本文摘录并翻译自:Ontology Development 101: A Guide to Creating Your First Ontology
0x00 为什么要构建本体?#
本体定义了一个通用的词典共研究人员在共享特定领域内的信息的时候使用。其中包含了可以被机器解释的领域内的基本概念以及概念之间的关系。开发标准化的本体的许多规则能够为许多领域专家所用。构建一个本体就像是定义了一组数据以及他们的结构供其他程序使用。
构建本体的原因有:
- 在人或者机器见共享结构化信息
- 复用领域知识
- 让领域的假设更鲜明
- 从即用知识中分离出领域知识
- 分析领域知识
如果网页分享和发布基于相同本体的信息,那么机器就能够从不同的页面抽取并整合信息,从而相应各种问答请求。
硬编码的假设不仅难以被找出和理解,而且难以更新,尤其是对于没有编码能力的领域专家。另外,显示的特定领域知识对于领域新手而言十分有必要。
0x01 什么是本体?#
本体是一个格式规范的,对领域概念的描述。其中的概念(concept)称为class,描述每一个概念的特征和属性的叫槽(slot),也称为role或者property。对slot的约束叫做facet,又称为role restrictions。
本体和各个概念(类)的实例集合构成了知识库。
class是整个本体的重点。class描述这领域内的概念。slot描述了类和实例的属性。
在实践中,构建一个本体包含一下内容:
- 定义本体中的类
- 将类分类形成层次结构
- 定义属性槽,规定可以填入槽中的属性值
- 为每一个实例填入属性值
这样,我们就通过定义不同类的各个实例、并给实例赋予属性指的方式建立了一个知识库。
0x02 构建本体的知识工程方法论#
从来没有一种方法论是绝对“正确”且适用所有情况的构建本体的方法。
构建垂直领域本体的原则:
- 没有一个绝对正确的方法来描述一个领域。最佳的解决方案经常适合应用结合,在业务中不断优化拓展得到的;
- 本体构建必须是一个迭代的过程;
- 本题中的概念应该贴近现实事物并反映其间的关系。很有可能句子中的名词就反映了事物,动词反映了事物间的关系。
构建本体是对现实事件建模,本体中的概念必须反映现实。
第一步:确定本体涵盖的领域与范围##
不妨问自己几个问题:
- 我要构建的本体要覆盖什么领域?
- 我为了什么需求要构建本体?
- 我构建的这个本体是为了回答什么问题?
- 谁会使用并维护这个本体?
第二步:考虑复用现有的本体##
第三步:在本体中枚举重要的条目##
一开始,获取一个全面的综合的概念清单是非常重要的,先不用担心概念的重叠。
第四步: 定义类以及类的层次结构##
有几种可行的方法来构建层次结构:
- 自顶向下
- 自底向上
- 自顶向下与自底向上相结合
我们可以从少量的上层概念和下层概念共同出发,归纳得到与之相关的中间层次的概念。这种混合方法对于许多本体的构建者来说是最简单的方式。
第五步:定义类的属性——槽##
第六步:定义对槽slot的约束##
我们需要定义不同的槽能够填入的属性值的数据类型、属性值的个数、属性的主语对应的类domain和宾语对应的类range(对于属性值是实例类型的槽而言)。
槽的值如果是实例类型,就要规定能够填入的实例应该属于何种类。能够填入的实例的类叫做这个槽的range。而有这种槽的类(或者实例的类)叫做这个槽的domain。不能将domain和range的类定义得太宽泛,比方说不要定义所有类的父类THING为domain或者range。
如果你定义的domain或者range的类包含了某一个类以及这个类的子类,那么把子类去除,仅保留这些子类的父类。
如果你定义的domain或者range的类包含了一个类的所有子类,但是没有包含这个类它本身,那么range中应该仅保留这个类本身,把这个类的子类从facet中去除。
第七步:创建实例##
- 为每个实例选择类
- 建立实例
- 填入属性值
0x03 定义类和类层次结构需要注意的地方#
3.1 保证类层次的正确性##
一个类的子类和其超类是一种**kind of **关系。
一个实例并不是所有这类实例的子类。因此在给类命名的时候,要么全部使用单数,要么全部使用复数,以避免产生这种错误。
同时,还要检查层次结构中的传递关系,比方说B是A的子类,C又是B的子类,那么C应该是A的子类。
还要注意,一个类要表达的概念(本体)和这个类的类名其实是没有必然联系的(参见本体论)。
而且,同义词表达的是同一个概念,不应该将它们设置为不同的类。
最后要避免类环路。比如A的子类是B,那么所有属于A的实例都应该是属于B的实例;不能在其他路径上体现出B又成了A的子类,那就不对了。
3.2 分析在类层次结构中同层次的兄弟类##
如果一个类仅有一个直接的子类,那么这个模型就是不完整的。
如果一个类的子类太多,那么在这个类和其现在这众多的子类之间可能需要一个中介分类来将这众多的子类划分为不同的类。
3.3 多继承##
许多知识表示系统允许类层级结构中有多继承现象的存在,即一个类可以使多个超类的子类。
3.4 何时引入新的类?##
- 一个类的子类有新的属性而其超类中没有
- 一个类的子类的约束条件不同于其超类
- 一个类的子类参与了其超类没有参与的关联
换言之,只有当仅用其超类不足以描述一个类的时候,我们需要引入一个新的类。
在实践中,每一个子类要么是有新的槽被随之定义,要么就是有新的属性值被定义,要么就是复写了其从超类那里继承下来的对于属性槽的约束。
3.5 新的类 OR 新的属性值?##
如果一个概念的属性值能够将这个概念同其他类区分开来,那么我们应该新建一个类以示区别;否则我们就是用一个新的属性值来表示这种特殊性就可以了。
如果在某个领域中,我们十分看重事物之间的区分度,我们应该考虑把某种事物的不同属性值划分为几个不同种类的事物,然后建立新的类以示区别。
3.6 实例 OR 类?##
决定讲一个概念定义为一个类还是一个实例,取决于这个本体的应用场景的本质需求。类的层级分类结束位置和实例的开始位置(模式层和实例层的界线)与知识表达的粒度相关。
实例是知识库中最特定的概念表示。
只有类才需要层级结构,知识表示系统不需要有”子实例“这种声明。即使一些类可能尚没有实例,我们也应该基于真实反映现实世界的事实这一原则,创建这个类。
3.7 限定本体模型的范围##
你所构建的本体应该紧贴你的业务需要,所以涵盖的领域知识的粒度不用一味只求最大或最小。应该从任务出发来限定模型涵盖的范围。
3.8 不相交的子类##
有许多的系统允许我们显性地生命不同类的相互独立。只要不同的类没有共用任何实例,那么他们就属于不相交。声明不相交的类能使我们构建的本体更合理。
0x04 定义property时需要知道的更多细节#
4.1 互逆slot##
存储两个互逆的slot是多余的。
4.2 预设值##
许多基于框架的系统允许为实例的槽预设属性值。如果一个类的大部分实例的某一个slot有相同的值,那么可以定义这个值为预设值default value。注意,这和模式层的属性值不同。概念的slot values不能改变。
0x05 命名规则#
5.1 大写和分隔符##
通常使用大写类名首字母,小写槽名(假设系统的大小写敏感的)的方式给类和槽命名。
5.2 单数和复数##
不管选择单数还是复数,你选择的命名规则都应该贯穿本体构建过程的始终
5.3 前缀和后缀##
在实践中,常见的方法是使用has-前缀或者-of后缀来命名槽名。
5.4 其他命名时需要注意的事情##
不要使用"class"、"property"、"slot"等等这种“关键字”给概念命名。而且应该避免使用缩写形式给概念命名。
0x06 总结#
没有一种绝对“正确”的本体构建方法是适用于所有领域的。