一个用OWL-S组装Web服务的例子

OWL-S可以用来描述Web服务,这个帖子将介绍一个非常简单的例子,也许对理解Web服务的组装有些作用。这个服务是对已有Web服务进行组装和执行,所以你并不需要发布自己的Web服务。你需要安装ProtegeOWL-S Editor插件,我用的版本前者是3.1 beta build 191,后者是build 15,它们在一起运行得还不错。

所用的Web服务在http://www.bs-byg.dk/hashclass.wsdl,它包含两个方法:HashString和CheckHash,前者用指定编码方式(MD5、SHA1等等)对指定字符串编码,后者根据指定编码方式检查一个字符串(HashString)是否是另一个字符串(OriginString)的编码结果。我们将把这两个方法组装成一个服务,对输入的编码方式和待编码字符串先进行编码,然后检查编码的结果是否正确,如果正确返回true,否则返回false。下面是组装步骤,完整的工程在这里下载

1、确认你的OWL-S Editor已经安装到Protege里,启动Protege,新建一个owl文件类型的工程,在菜单project->config里勾选上owls选项,按确定后Protege的主界面会多出一个OWL-S Editor页。

2、转到OWL-S Editor页,按左上角的WSDL按钮,在弹出的对话框里输入Web服务的地址http://www.bs-byg.dk/hashclass.wsdl,然后按回车,过一会儿在对话框里会显示出这个Web服务的信息,左边是Operations列表。

file
图1 用来导入WSDL的对话框

3、因为每次只能import一个Operation,所以先选择HashString,然后按右下方的Import按钮,这时系统会提示要把生成的owls文件(扩展名为.owl)保存在一个位置,你可以选择任何位置。

4、使用同样的方法把CheckHash方法也导入进来,这样我们就有了两个可用于组装的Web服务了。如果你愿意的话,可以单独执行看看,方法是选择一个Service,然后按绿色的执行按钮。

file
图2 导入的两个服务

5、现在开始组装它们。为此我们新建一个Service实例(按Create Service按钮)、一个Profile实例、一个CompositeProcess实例和一个WSDLGrounding实例,分别命名为myservice、myprofile、myprocess和mygrounding好了。

6、接下来把它们连接起来,首先选中myservice,把它的describedBy属性置为myprocess,presents属性置为myprofile,supports属性置为mygrounding。

7、现在对myprocess进行编辑,OWL-S Editor提供了一个可视化的编辑界面(Visual Editor),利用它可以很方便的定义CompositeProcess的各个步骤。选中myprocess,右边切换到Visual Editor,这里有一些粉红色的按钮用来定制流程。我们首先创建一个Sequence(表示按顺序执行),然后选中这个Sequence,创建两个Perform和一个Produce,每个Perform代表调用一个Web服务,而Produce的作用是在最后得到返回值。这时右边的图形应该像下面这样,因为我们尚未对Perform和Produce进行定制。

file
图3 包含三个有用节点的process图

8、在图形的Perform/Produce节点上点一下就可以修改它的属性,先来修改第一个。点一下第一个矩形节点(第一个Perform),在对话框里把process属性设置为wi1:HashStringProcess(注意:如果导入WSDL时改变了前缀,这里就不是wi1),为了方便阅读,把Name属性改为hashPerform。类似的,第二个矩形节点的process属性应该是wi2:CheckHashProcess,Name则改为checkPerform;对于唯一的Produce节点,改名为produce。现在右边的图如下所示。

file
图4 改名后的process图

9、现在从Visual Editor切换到Properties页,在这里为myprocess定义输入和输出参数。它的输入应该是wi1:HashType和wi1:Str,而输出应该是wi2:CheckHashResult,也就是说,对于我们组装出来的Web服务来说,输入是编码类型和待编码字符串,而输出是验证结果。

10、上面我们定义了myprocess拥有的参数,现在就要用到它们了。切换回Visual Editor,在树型列表里选则第一个Perform(hashPerform),把右边切换到Properties页,现在ToParameter属性里还是空白,我们要把myprocess的输入映射到这个Perform,所以按添加按钮把两个输入参数(wi1:HashType和wi1:  Str)加到ToParameter里。选中它们中的一个,可以看到右边有BindingType选项,缺省为valueSource这一项,就用它即可,在下面的FromPerform下拉框里只有一个选项TheParentPerform,选中它。在最下面的FromParameter里选择和你选择的ToParameter项一样的那个选项(wi1:HashType->wi1:HashType,wi1:Str->wi1:Str)。

file
图5 通过参数传递产生“数据流”

11、对于checkPerform,它有三个输入参数,我们希望HashType和hashPerform具有同样的值,所以它的设置和上一步里对HashType的设置一样;OriginalString的设置和上一步的Str一样;HashString属性是上一步得到的结果,所以FromPerform属性应该是hashPerform,FromParameter属性则是wi1:HashStringResult。

12、对produce的设置很简单,在ToParameter属性里加入我们要的结果wi2:CheckHashResult,FromPerform选checkPerform,FromParameter选wi2:CheckHashResult。现在,myprocess对应的process图如下所示。

file
图6 可以从图中看到服务的结构

13、对myprocess的设置到此就结束了,最困难的部分完成了,剩下的工作都很简单和显而易见。选中mygrounding,在它的hasAtomicProcessGrounding属性里加上wi1:HashStringAtomicProcessGrounding和wi2:CheckHashAtomicProcessGrounding。

14、现在myservice已经可以执行了(myprofile里还可以增加一些信息用来描述这个服务)。现在选中myservice,按下执行按钮,在弹出的对话框里HashType框填MD5,Str框填test(任意字符串都可以),然后按Execute按钮就会看到结果,当然,这个服务不论你输入什么字符串都会得到true值,原因不用我说了吧。

file
图7 执行组装后的服务

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/06/12/173302.html

关于本体编程的实现

临近期末,我有一门课程的期末项目是做一个教育领域的本体应用系统,所以最近经常思考本体在这样一个系统中所起的作用,以及该如何实现。(本体是否只能在web环境下发挥作用,使用本体描述一个独立系统的模型是否值得?)

假设要做的是选课系统,很容易看出系统里应该有这些对象:课程、学生、教师,它们之间互有联系。现在的问题是,本体、Java类和数据库各扮演怎样的角色?我目前想到的方法有以下几个:

  1. 在本体(owl)里建立这些类和关系,在Java里建立同样的Bean类,运行时系统把本体里的individuals转换为Java类的实例,也就是在内存里得到一个Java实例的集合,选课的各种操作就是对这个集合的修改,退出系统时再进行反向转换,把修改反映到本体里。在这样的实现方法中,本体实际上扮演了数据库的角色,所以当数据(individuals)很多的时候,效率会很成问题。(Protege的owl编辑工具提供了从本体生成EMF模型代码的功能,虽然目前还是alpha版,这也许将成为同步两种模型的不错选择。)

  2. 对上面的方法进行修改,让本体不保存individuals,对Java实例集合的修改最终反映到关系数据库里(利用hibernate不会很困难),运行时系统直接从数据库里取得数据转换为Java实例。这样的实现可以解决效率问题,但和传统应用区别不大,本体的作用几乎为零。

  3. 另一种比较极端的做法是只用本体维护类和individuals,Java方面没有任何与应用有关的模型,系统一开始把本体读入内存以rdf图的方式存在,选课操作转换为对此图的修改(利用Jena等API)。这个方法存在两个问题,一是效率,二是Java代码的可读性下降,这就相当于直接使用JDBC而不是hibernate对数据库操作的区别。

在solo项目里我使用的是第一种方式,各方面效果还可以接受,但本体的作用发挥得很不够。这是很重要的方面,因为如果和传统项目没有区别,辛辛苦苦引入本体又是为了什么,特别是对本体推理的功能,我想最关键的问题还是要找出最适合应用的本体,定义本体的确是一门学问。

Update:IBM Alphaworks也提供了一组本体工具(包括Orient、EODM和RStar),对EMF的支持应该不错。今天初步试了一下Orient,它只支持RDF(S),而不支持OWL,所以无法满足课程项目的要求,Orient的目前版本还有一些小bug,除已知的那些以外,我把.ontology文件输出为ecore模型总是不成功,而输出为rdf是可以的。

Update:推荐一个关于本体和模型驱动的幻灯片,主要内容是介绍应该如何利用UML的可视化编辑功能和元模型的扩展功能来构造本体,这里面介绍了相当多的相关概念(其中很多我甚至没听说过),以及它们出现的原因,比较有利于我们理清思路。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/06/05/168240.html

用Jena获得本体的缺省名称空间

这个标题其实有点问题,因为本体/RDF本身并没有名称空间的概念,它们只关心绝对的URI;在Jena里一旦模型读进内存,就都是使用绝对URI标识资源的,而当使用xml格式存储的时候,才会引出这些xml中的概念。

最近遇到一个问题,在一个程序里要读取多个xml格式的本体文件(*.owl),它们之间有import关系,在读一个文件之前,我需要先确认该文件需要import的那些名称空间所对应的本体(此本体的缺省名称空间是import的值)是否存在,所以我必须知道每个.owl文件的缺省名称空间和import值(后者在这里暂不讨论),这样做的一个好处是不需要让Jena在找不到本地文件时去访问网络,造成延迟。

虽然Jena API没有提供直接得到它的方法,从一个.owl文件得到缺省名称空间的方法其实很简单,但com.hp.hpl.jena.shared.PrefixMapping接口有一个getNsPrefixURI()方法,利用它可以得到xml文档中每个prefix对应的名称空间。

什么是前缀(prefix)呢?prefix主要是为了简化xml的书写,例如下面的语句中,rdf就是prefix,这样在xml文档的其他地方就可以用"rdf:xxx"表示"http://www.w3.org/1999/02/22-rdf-syntax-ns#xxx"这一长串了。

xmlns:rdf="[http://www.w3.org/1999/02/22-rdf-syntax-ns](http://www.w3.org/1999/02/22-rdf-syntax-ns)#"

有了这个方法,我们就可以得到rdf、owl、xsd等前缀对应的名称空间,而缺省名称空间对应的前缀是空字符串(""),因此使用model.getNsPrefixURI(""),而OntModel对象是实现PrefixMapping接口的。

当然,要得到一个xml文件的缺省名称空间有很多方法,只是在一个面向本体而不是xml的应用程序里,使用本体这个层次的API可能更合适一些。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/03/16/119960.html

在应用程序中利用Jena API处理OWL本体

接触Semantic Web的时间还不是很长,所以现在写的这方面内容算是笔记性质,很可能存在很多误解,欢迎指出或讨论:)

一般来说,我们在Protege这样的编辑器里构建了本体,就会想在应用程序里使用它,这就需要一些开发接口。用程序操作本体是很必要的,因为在很多情况下,我们要自动生成本体,靠人手通过Protege创建所有本体是不现实的。Jena是HP公司开发的这样一套API,似乎HP公司在本体这方面走得很靠前,其他大公司还在观望吗?

可以这样说,Jena对应用程序就像Protege对我们,我们使用Protege操作本体,应用程序则是使用Jena来做同样的工作,当然这些应用程序还是得由我们来编写。其实Protege本身也是在Jena的基础上开发的,你看如果Protege的console里报异常的话,多半会和Jena有关。最近出了一个Protege OWL API,相当于对Jena的包装,据说使用起来更方便,这个API就是Protege的OWL Plugin所使用的,相信作者经过OWL Plugin的开发以后,说这些话是有一定依据的。

题目是说用Jena处理OWL,其实Jena当然不只能处理OWL,就像Protege除了能处理OWL外还能处理RDF(S)一样。Jena最基本的使用是处理RDF(S),但毕竟OWL已经成为W3C的推荐标准,所以对它的支持也是大势所趋。

好了,现在来点实际的,怎样用Jena读我们用Protege创建的OWL本体呢,假设你有一个OWL本体文件(.owl),里面定义了动物类(http://www.zoo.com/ont/Animal,注意这并不是一个实际存在的URL,不要试图去访问它),并且它有一些实例,现在看如下代码:

OntModel m = ModelFactory.createOntologyModel();
File myFile = ...;
m.read(new FileInputStream(myFile), "");
ResIterator iter = m.listSubjectsWithProperty(RDF.type, m.getResource("http://www.zoo.com/ont/Animal"));
while (iter.hasNext()) {
    Resource animal = (Resource) iter.next();
    System.out.println(animal.getLocalName());
}

和操作RDF(S)不同,com.hp.hpl.jena.ontology.OntModel是专门处理本体(Ontology)的,它是com.hp.hpl.jena.rdf.model.Model的子接口,具有Model的全部功能,同时还有一些Model没有的功能,例如listClasses()、listObjectProperties(),因为只有在本体里才有“类”和“属性”的概念。

上面的代码很简单,从ModelFactory创建一个OntModel,从指定文件把模型读到内存里。再下面的代码是一个例子,作用是取出模型中所有Animal的实例(Individual,也叫个体),并打印它们的名称。要从OntModel里取实例,也可以用listIndividuals()方法,只不过你得在得到的实例中判断它们是不是Animal的实例,我觉得不如用上面这种简易查询的方式来得方便。

Jena里扩展了很多Iterator,比如ResIterator、StmtIterator和NodeIterator等等,刚开始用会觉得很别扭,好象还不如都用java标准的Iterator,不知道Jena的设计者是怎么考虑的。要熟练掌握还是得对整个Jena的API有全局掌握才好。

在循环里,我们得到的每个元素都是一个Resource,因为本体里的任何东西都是资源,不论你想得到Subject、Property还是Object,在Jena里实际得到的都是资源(Resource),在Jena里,Property是Resource的子接口,而Jena并没有Subject或Object接口。(注:在OWL本体中,Subject->Property->Object组成一个三元组,例如:张小刚->父亲->张大刚;或者:绵羊多利->rdf:type->动物,rdf:type是一个特殊的属性,表示前者是后者的实例)

暂时先写到这,关于在本体中引入其他本体和使用推理,下次继续。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/06/87598.html

[翻译]什么是OWL本体

译注:本文是对文档A Practical Guide To Building OWL Ontologies Using The Protege-OWL Plugin and CO-ODE Tools Edition 1.0第三章的翻译,并省略了其中的图片。Protégé是一个斯坦福大学开发的本体编辑器,为开放源码软件,具有优秀的设计和众多的插件,是目前使用最广泛的本体编辑器之一。

什么是OWL本体

  我们使用本体(Ontology)来获取某一领域的知识,本体描述该领域的概念,以及这些概念之间的关系。目前有很多种不同的本体语言,它们各有千秋,而W3C(World Wide Web Consortium)目前的最新标准是OWL。和Protégé一样,OWL让描述各种概念成为可能,与此同时,它还提供了其他很多功能。它具有更丰富的操作符——例如与、或和非;它立足于一个不同的逻辑模型(logical model),该模型能够更好的定义概念,可以用从简单概念构造出复杂的概念,不仅如此,该模型还允许你使用推理机(reasoner)来检查本体中的陈述(statement)和定义(definition)是否一致,或者判断出哪个概念更适合于哪个概念,从而帮你维护一个正确的本体等等,当允许一个类(Class)拥有多个父类的时候,这一点至关重要。

一、三类OWL

  可以把OWL分为三个子语言:OWL-Lite、OWL-DL和OWL-Full,主要的分类依据就是它们的表达能力。其中,OWL-Lite是表达能力最弱的子语言,OWL-Full具有最强的表达能力,而OWL-DL的表达能力则在它们之间。我们可以认为OWL-DL是OWL-Lite的扩展,而OWL-Full是OWL-DL的扩展。

1.1 OWL-Lite

  从语法上来说,OWL-Lite是三个之中最简单的一个,当你的本体中类的层次结构很简单,并且只有简单的约束(constraint)时适合使用它来描述本体。例如,在需要把一个已存在的辞典(thesauri)移植到另一个差不多简单的概念层次时,OWL-Lite可以做得又快又好。

1.2 OWL-DL

  和OWL-Lite相比,OWL-DL的表达能力要丰富许多,它的基础是描述逻辑(Description Logics,即DL的由来)。描述逻辑是一阶逻辑(First Order Logic)的一个可判定的变种(译注:不一定准确,原文decidable fragment),因此可以用来进行自动推理,计算机从而可以知道本体中的分类层次,以及本体中的各种概念是否一致。

1.3 OWL-Full

  OWL-Full是OWL的三种子语言中表达能力最强的一个,适合在那些需要非常强的表达能力,而不用太关心可判定性(decidability)或是计算完全性的场合下使用。不过也正是由于表达能力太强这个原因,用OWL-Full表示的本体是不能进行自动推理的。

二、该使用哪一种子语言

  首先,要想确切的知道这三种子语言之间的区别,请参考OWL Web本体语言概要。尽管有很多因素需要考虑以决定该使用它们中的哪一个,但这里是一些最简单常用的原则。

  • 对于OWL-Lite和OWL-DL,考虑OWL-Lite提供的那些简单构造子(construct)是否足以描述你的本体,若是使用OWL-Lite,否则使用OWL-DL。
  • 对于OWL-DL和OWL-Full,考虑在你的应用中,是自动推理比较重要还是高表达能力(例如是否需要元类来建模)更重要,如果是前者,请使用OWL-DL,否则该使用OWL-Full。

  Protégé的OWL插件在编辑OWL-Lite和OWL-DL的本体时不做区分,但可以在选项里选择以OWL-DL或是OWL-Full方式编辑本体。

三、OWL本体的组成

  OWL本体的组成与Protégé提供的本体相似,基本上,只是在对组成部分的称呼有一些分别。例如OWL有个体(Individual)、属性(Property)和类(Class),而Protégé则分别称它们为实例(Instance)、槽(Slot)和类(Class)。

3.1 个体(Individual)

  个体代表(领域中)我们实际感兴趣的那些对象,Protégé和OWL有一个重要的区别就是OWL不使用唯一命名假设(Unique Name Assumption,UNA),也就是说,两个不同的名称可以对应到同一个个体。例如“伊丽莎白女王”、“女王”和“伊丽莎白?温莎”可能都对应同一个人。在OWL里,你必须明确的表达个体之间是否为相同的,否则它们可能相同也可能不相同。

  注:个体(Individual)有时也被称作实例(Instance),个体相当于类的实例。

3.2 属性(Property)

  属性是个体之间的二元关系,也就是说,属性把两个个体连接在一起。例如,属性hasSibling可能会把Matthew和Gemma这两个个体连接起来,而属性hasChild会把Peter和Matthew这两个个体连接起来;属性可以有反向属性(Inverse),例如hasOwner的反向属性是isOwnedBy;属性也可以被限制为只能拥有一个值,即所谓的函数属性(functional);属性还可以是具有传递性(transitive)或是对称的(symmetric)。

  注:这里所说的属性即Protégé中槽(Slot)的概念,在描述逻辑中它们就是角色(Role),在UML等面向对象方法中它们就是关系(Relation),而在GRAIL等形式化表达中将它们称作特性(Attribute)。

3.3 类(Class)

  OWL中的类代表一些个体的集合,OWL使用形式化(数学的)的方法精确描述出该类中成员必须具有的条件,例如,领域中全部猫的个体都属于Cat类。类可以通过继承关系组成层次结构,子类是父类中的特殊情况,例如考虑Animal和Cat这两个类,Cat可以是Animal的一个子类(即Animal是Cat的父类),这就表示了:所有的猫都是动物,所有Cat类的成员都是Animal类的成员,如果你是猫那么你也是动物,Cat类被Animal类所包含,等等。OWL-DL的一个重要特征就是父类和子类之间的(包含)关系可以被推理机自动计算出来。

  注:概念(Concept)这个词有时被用来代替类,实际上,类是概念的一个具体表现。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/12/17/78368.html