530 likes | 631 Views
第十四章 关联对象访问 Associative Object Access. 本章重点讲述 GOM 对关联对象查询的支持,即如何实现一个查询和如何描述用户的查询要求 在 O-O DBMS 中,实现一个查询是通过多态的 Select 函数来实现的 GOM 支持二种查询语言 GOMql 、 GOMsql 其中 GOMql 是基于关系语言 QUEL 在面向对象上的扩展 GOMsql 是 SQL 在面向对象上的扩展 关联查询的操作对象为:类型范围 (Type Extention) ,用户定义的集合对象和表对象. 多态的关联选择操作定义及其实现.
E N D
第十四章 关联对象访问Associative Object Access • 本章重点讲述GOM对关联对象查询的支持,即如何实现一个查询和如何描述用户的查询要求 • 在O-O DBMS中,实现一个查询是通过多态的Select函数来实现的 • GOM支持二种查询语言GOMql、GOMsql • 其中GOMql是基于关系语言QUEL在面向对象上的扩展 • GOMsql是SQL在面向对象上的扩展 • 关联查询的操作对象为:类型范围(Type Extention),用户定义的集合对象和表对象
多态的关联选择操作定义及其实现 • 关联选择操作需要一个操作对象说明—在某个对象实例集合上,需要一个条件表达式作为选择的依据—选择谓词 • 当定义一个多态的选择操作时,选择谓词将以函数变元的方式作为操作变元 • 当选择谓词本身需要参数时,该参数必须在选择操作的参数表中说明 • 多态的选择操作的共同名字为Select
无参数的选择谓词—简单的布尔函数 • 多态选择操作说明为 Polymorph overload select (\t1<={\t2}) :\t1 || ( \t2 || -> bool ) -> \t1 Code selectNoParam • 语义为 • 类型\t1,是一个集合类型,其元素类型为\t2 • Select操作有两个变元:接受者类型为\t1,另一个变元是一个布尔函数,它对类型为\t2的对象进行选择,返回一个布尔型结果 • Select语义对t1的元素用布尔函数进行筛选;
多态选择操作的实现 define selectNoParam(selPred) is var result: \t1; candidate: \t2; begin result.create; !! 生成空结果集 foreach (candidate in self) if candidate.selPred then result.insert(candidate); return result; end define selectNoParam
应用举例 • 在立方体实例库中,查找某一个顶点是原点的立方体 • 分析:其选择谓词需要顺次检查一个立方体的8个点,是否有一个点的x、y、z坐标值为0,0±ε —— inOrigin 操作 • 其结果应当是下面二个集合的交集: • 包含在立方体实例集合中的实例——myCuboid所引用 • 满足谓词inOrigin 的实例 • 多态的Select操作可以应用于任何一个集合类型
inOrigin定义 declare inOrigin: Cuboid || bool; define inOrigin is !!判断任何一个顶点是否处于坐标原点 return (( self.v1.x=0.0 ±ε and self.v1.y=0.0 ±ε and self.v1.z=0.0 ±ε)OR … ( self.v8.x=0.0 ±ε and self.v8.y=0.0 ±ε and self.v8.z=0.0 ±ε)); • 变量定义和引用 var myCuboids, theCuboidsInOrigin:CuboidSet; …… theCuboidsInOrigin:=myCuboids.select(inOrigin);
示例2——查询退休职员 declare isRetired: Employee || bool; var retiredEmps: EmployeeSet; … retiredEmps:=ext(Employee).select(isRetired);
示例3——无名的选择谓词的使用 • 当布尔选择谓词比较简单,则可以λ 符号来实现操作过程的传递 • 示例:选择红色苹果的选择操作 Ⅰ.选择谓词用命名isRed表达 declare isRed: Apple ||bool; define isRed is … Ⅱ.选择谓词用λ表达——直接传递过程 redApples:=myApples.select (λ x: x.color = “red”) GoldCuboid=mycuboid.select (λ x: x.met.name = “gold”)
带参数的选择谓词 • 该参数是为选择谓词服务的,所以需要在谓词函数中说明 • 由于在引用时,显然需要由Select来引用,因此,在Select的参数表中也要说明,规则如下: poly overload select (\t1<={\t2}):\t1||(\t2||\t3 -> bool), \t3 -> \t1 • 语义:其中类型\t3可以是任何类型,它的约束条件是Select的第三个参数类型\t3,必须与选择谓词所需一个参数类型一致
Select的重载 • Select函数不但是多态的,而且是重载的,它可以根据选择谓词的需要,设定多个参数 • 编译器根据重载规则,从参数的个数,寻找到正确的实现版本 • 其约束条件为:在哑、实结合时,Select的参数个数和各自类型必须与选择谓词的参数个数、类型完全一致
示例1——一个参数的选择谓词 • 对Cuboid定义一个选择谓词bigCuboid,它能选择体积大于某个阈值的立方体对象 • 定义 declare bigCuboid: Cuboid || float -> bool code bigCuboidCode; define bigCuboidCode(threshold) is return(self.volume > threshold); • 引用 var myCuboids, myBigCuboids: CuboidSet; …… myBigCuboids:= myCuboids.select(bigCuboid, 200.0);
示例2——二个参数的选择谓词 • 选择体积在一个范围(上限high,下限为low)的立方体 declare volumeRange: Cuboid || float, float -> bool; define volumeRange(low, high) is return (self.volume<=high and self.volume >=low);
迭代Iterators • 可以在筛选的基础上利用循环进行各种进一步的操作 • 例如:求符合体积要求的Cylinders的体积累加值 declare bigCyl: Cylinder || float -> bool code bigCylCode; define bigCylCode(threshold) return(self.volume>= threshold); …… var c: Cylinder; myCylinders: CylinderSet; bigCylindersTotalWeight: float:=0.0; …… foreach (c in myCylinders.select(bigCyl, 20.0)) bigCylindersTotalWeight:=bigCylindersTotalWeight + c.weight;
说明性查询语言GOMql • 多态选择函数只是一个关联查询实现的基础,对于复杂的嵌套查询及其优化,表达力度不够,需要通过定义相关的查询语言来实现 • 查询优化有两个方面解决 • 关系代数的优化:编译时进行 • 物理查询路径的优化:执行时进行 • 下面的内容从用户角度出发,如何查询需求正确地用相应的查询语言序列来表达 • GOMql是基于QUEL的扩展
一个对象实例库 • 类型定义 Type Emp is • {name:string ; • working:Dept; • salary:int;} • type Dept is • {name:string; • mgr:Manager; • profit:int;}; Type Manager • Supertype Emp is • [cars:{Car};]; • type Car is • [license:string; • make:string; • horsepower:int;];
worksIn ------------ mgr ----- cars ----> make -- Emp Dept Manager Car string 1 N N 1 M 1 Dept EMP Manager mgr workIn cars Dept Manager Car • 路径表达式为查找引用链的引用序列 示例: P≡Emp.worksIn.mgr.cars.make • 示例的类型定义中,关联对象的联接,仅仅采用一个进入点的方式
GOMql表达式 • 单目标查询表达式 rang r1:s1,…,rm:sm retrieve ri where p(r1,…, rm) • 多目标查询表达式 rang r1:s1,…,rm:sm retrieve a1:r1,…,aj:rj where p(r1,…, rm) • Range子句:范围说明子句 其中:rj(1≤j≤m)为范围变量表达式,它用于range子句中
其中,sj(1≤j≤m)必须是下列情况之一 • Sj是一个类型扩展EXT(用类型名表达) • 一个集合对象变量 • 一个列表对象变量 • 一个包含有集合结构的对象变量 • 一个包含有表结构的对象变量 • 一个计算一个集合结构对象的表达式 • 一个计算一个表结构对象的表达式 总之,变量rj被约束到一个相应的聚集类型sj的元素类型
retrieve子句 查询说明子句 • 简单形式:只有一个范围变量——单目标查询 • 复杂形式:通过投影到多个范围变量,构造的多元组——多目标查询 • 实现方法:对目标的范围变量与相应的对象分别进行捆绑,并进行选择谓词查询 • Where子句:选择谓词中,P的变元(r1…rm)∈(s1xs2…xsm)(m个联接) 当目标rj(或者多目标r1…rj)与某一对象捆绑,使P (r1…rj)为真,则该对象被选中
GOMql查询示例(一) • 简单选择谓词示例 查询所有工资超过100000的Emps range e:Emp retrieve e where e.salary>100000.0 查询结果为{id3,id4,id8,id9,id10} • 上述查询需要输出姓名,则为: range e:Emp retrieve e.name where e.salary>100000.0 name “LeMond” “Hinault” “Boss”
GOMql查询示例(二) • 问题:找出其经理为驾驶Jaguar汽车的Emps • 该查询的路径表达式为: p=Emp.workIn.mgr.cars.make = “Jaguar” • 查询表达式为: range e:Emp retrieve e where “Jaguar” in e.worksIn.mgr.cars.make
系统检测范围变量e的每个捆绑的对象,通过路径可以达到的串值是否为给定的“Jaguar”,若是,则该对象被选中系统检测范围变量e的每个捆绑的对象,通过路径可以达到的串值是否为给定的“Jaguar”,若是,则该对象被选中 • 该选择查询代价巨大,它需要进行如下多个联接: Emp x Dept x Manager x Car • 选择结果为{id1,id2,id8}
更复杂的查询(一) • 例3:找出选择的经理:他的部门亏损,但仍支付给至少一个雇员工资超过二十万元 range e:Emp,m:Manager retrieve m where m=e.workIn.mgr and e.salary>200000.0 and e.workIn.profit<0.0 • 这里,m=e.worksIn.mgr称为功能联接(对象的“相等”操作子隐含地表示为“标识”)
例3的优化处理 • 如果在Dept类型中增加一个关联属性{Emp},则例3可以表示为: range d:Dept,m:Manager retrieve m where m=d.mgr and d.profit<0.0 and d.Emp.salary>200000.0
更复杂的查询(二) • 例4:查找这样的经理:他驾驶过贵重的汽车,而他管理的部门获利很低 range d:Dept,m:Manager,c:Car retrieve m where m=d.mgr and d.profit<100000.0 and c in m.cars and (c.horsepower>150 or c.make=“Jaguar”)
量词的使用(一) • (一)全称量词表达式 for all rj in sj p 语义为:若集合sj中所有成员rj均满足选择谓词p(rj),则表达式为真,否则为假 示例:查询其经理只开宝马车的雇员 range e: Emps,c: Char retrieve e where forall c in e.worksIn.mgr.cars (c.make=”BMW”)
量词的使用(二) • (二)存在量词表达式 EXIST rj IN sj P(rj) 语义为:若在集合S中至少有一个成员rj满足P(rj) ,则表达式为真,否则为假 示例:查询其经理所用额轿车中有一辆为美洲虎的雇员 range e: Emps,c: Car retrieve e where exists c in e.worksIn.mgr.cars (c.make=”Jaguar”)
嵌套查询 • 在任何一个集合可以出现的地方,都可以使用range-retrive-where表达式,因此,Gomql允许表达式嵌套 • 表达式嵌套可以发生在三个子句的任何一个中,因为三个子句本身均要求一个集合表达式 • 示例:查询那些只驾驶美洲虎牌或宝马牌,或马力>200的汽车经理
range m: Manager , c: Car retrieve m where forall c in m.cars (c in (range v: Car retrieve v where v.horsePower>200 or v.make=”Jaguar” or v.make=”BMW”))
查询表达式中聚集函数和类型操作的使用 • 关系查询语言QUEL仅提供少量的聚集函数如count,sum,min,max,avg等 • Gomql允许类型操作作为函数使用。其约束条件为:类型操作不会改变对象的状态,且应当返回一个值 • 函数的范围:在where子句和retrieve子句中都可以使用 • 由于类型操作含有子类型的继承,因此,在执行时,每个对象实例仍然需要动态捆绑相应精化的操作
示例 • 示例1:查许体积大于150.0的圆柱体 range c: Cylinder retrieve c where c.volume>150.0 • 示例2:查询所有金子做的几何体的总重量 range g: GeometricPrimitive retrieve sum(g.weight) where g.mat.name=”Gold”
基于SQL的对象查询语言GOMsql • GOMsql是O2SQL的一个子集,它是针对Gom的ODL设计的查询语言 • GOMsql的目标是向用户以供基于SQL的声明和面向集合的查询接口 • 面向对象的基于SQL的查询语言强调的是对象类型,而对象-关系的SQL扩展(SQL-99)强调的仍然是关系,即如何通过关系模型的扩展将对象和类引入 • 其他的面向对象的查询语言--OQL。它是针对ODL设计的查询语言,而ODL是IDL(接口描述语言)--CORBA的一个组件的扩展。 *CORBA是分布式面向对象的计算的一种标准
示例数据库--边界标识的几何体数据库 type BRep with extension is body [name: string; weight: float; faces: FaceSet;]; … end type BRep; type FaceSet is body {Face} … end type FaceSet; type EdgeSet is body {Edge} … end type EdgeSet; 查找引用链 type Face is body [surface: float; edegs: EdgeSet;]; … end type Face; type VertexSet is body {Vertex} … end type VertexSet; type Edge is body [length: float; vertices: VertexSet;]; … end type Edge; type Vertex is body [x,y,z: float;]; … end type Vertex;
GOMsql的基本查询结构 • GOMsql的基本结构为:select-from-where--记为SFW表达式 • 示例 • selectb.weight from bin BRep whereb.name = “cubo#5” • 在Select子句中,可以引入类型操作函数 • 在from子句中,给出了一个显式定义的范围变量b,b属于BRep类型的对象实例集 • 在where子句中,b的名字要等于cubo#5
与GOMsql等价的SQL查询表达式 (1) select weight from BRep where name = “cubo#5” (2) selectb.weight from BRep as b whereb.name = “cubo#5” • 范围变量在SQL中被称为别名(aliases) • 方式(1)没有显式的范围变量 • 方式(2)通过别名,定义了一个显式的范围变量b
GOMsql与SQL的主要区别 • SQL:From子句中范围变量必须约束到一个已存在的,旦已被命名的元组赋值的对象集合上,即捆绑到一个关系或一个已建立的 视图上 • 结论:SQL的From子句中不允许嵌套SFW的结构 • GOMsql:From子句中的范围变量可以定义在任何的对象集合上。即无论是持久的命名集合,还是一个临时建立的对象集合,即允许捆绑到另一个SFW表达式上。 • 结论:GOMsql的From子句支持SFW结构的嵌套 • ∆范围变量在From子句中必须显式说明
范围变量的形式化定义 • GOMsql中,范围变量被捆绑到From子句中的对象集合上 • 形式化描述为: • <form-clause>:: from<rangeVar>in<objectCollection> {,<rangeVar> in < objectCollection >} • < objectCollection >::=(<SFW>)|<Set>|<List>
嵌套查询表达式 • 示例:查找重量大于1000的几何体中表面积大于10的表面集合。 • 方法:先查找重量大于1000的几何体,再从中挑出表面积大于10的子集 • Select f Form f in (select b.faces from b in Brep where b.weight>1000) where f.surface>10
Brep Face • 这里,外层范围变量f被限定在内部的SFW表达式所返回的Face对象集合上。 • 需要注意的约束条件是:保证范围变量必须有一个唯一的类型,这个类型可以在编译时推导出来 • 一个嵌套查询表达了查询的路径表达式是 faces • 更广泛地,一个范围变量不仅被限定在通过路径表达式检索的对象集合上,而且可以捆绑在任何一个集合上。
示例2 • 查询重量在100-1000之间的几何体 • 笨办法:先找出重量大于100的几何体,再从中挑出小于1000的来 • select b2.name form b2 in (select b1 from b1 in Brep where b1.weight>100) where b2.weight<1000 • 优化的结果 • select b.name form b in Brep where b.weight<1000 and b.weight>100
范围变量可以限定到实例集合的属性域上 • 示例:查询立方体cubo#5的8个顶点坐标。 select v.x, v.y, v.z from v in ( select e.vertices from e in ( select f.edges from f in ( select b.faces from b in BRep where b.name="cubo#5" ) ) )
从最内层的SFW开始(7-9句):b被限定在BRep的类型扩展上从最内层的SFW开始(7-9句):b被限定在BRep的类型扩展上 • 谓词b.name=Cubo#5将b限定到满足谓词的BRep的一个子集上,返回每个几何体的6个面f1-f6。 • 5-6行的SFW接受由内层返回的6个面,并计算它们的边的并集: 产生12个不同的edge对象 • 语句3-4产生24个点的并集--为8个不同的点 • 语句1-2产生8个点x.y.z值
嵌套查询和路径表达式 • 如下抽象的类型模式 • type T0 is … type Tn-1 is type Tn is body body body [… ; [… ; […] A1: {T1}; An: {Tn}; … …] ; …] ; end type Tn … … end type T0 end type Tn-1 • 即元组类型Ti通过它的属性Ai+1产生对类型Ti的引用
一个嵌套查询的SFW表达式 • 假如从引用链的始端T0开始,到Tn终止,查询一个原子类型SomeAttr的值,那么它的查询如下: • select an.someAttr from anin ( select an-1.An from an-1in ( select a1.A2 from a1in ( select s.A1 from s in someSet ) )…) • 利用路径表达式,其查询可以缩短为: • select an.someAttr from anin someSet.A1.A2.….An
嵌套查询的数学表示 • 数学上的表示:结果集合可以表示为并集Un,其中Ui被递归定义成:
不同的Join类型 • 不同类型的联系 • 基于值的Join:关系查询传统的Join操作 • 标识Join • 函数Join
基于值的Join • 传统的连接操作,通过给定的Join属性的值的比较来联系对象 • 示例:查询两个BRep对象,它们之间,第二个变量为第一个的两倍 • select b1.name,b2.namefrom b1in BRep, b2 in BRepwhere b1.weight * 2.0 = b2.weight+є • 对象b1,b2之间通过变量值来关联
标识Join--同一Jion • 标识Join--基于对象的相等,而不是值相等,因此,是基于OID值相等的连接 • 示例. • 谓词O1=O2--表示O1与O2OID相等而不是O1与O2的状态相等 • 谓词OЄ<Object>--当且仅当O是Object集合中的一个对象实例时为真,而不是说Object中有一个对象状态与O的状态相等
标识Join示例 • 父,母,子三个对象类型及其实例库 • type Man withextentionis [name: string;...;hasKids:{Child};];type WOMan with extention is [name: string;...;hasKids:{Child};];type Child with extention is [name: string;...;father:Man;mother:Woman;];
查询同一个父亲的两个孩子C1,C2 • select c1.name,c2.nameform c1in child;c2in childwhere c1.father=c2.father and c1!=c2 • 这里c1.father=c2.father是标识相等,而不是值相等 • 如果是这样的谓词 Where c1.father.name=c2.father.name and c1!=c2 --值相等查询