如图1-5所示,下面的例子说明了一个完整的数据集成方案。
数据源和中介模式
在这个例子中,我们有5个数据源。第一个是最左边的S1,它存储电影数据,包括电影的名字、演员、导演和类型。接下来的3个数据源S2~S4存储有关场次的数据。数据源S2包括了整个国家的影院,而S3和S4仅代表性地存储了纽约和旧金山的影院数据。需要注意的是,虽然这3个数据源都存储同一类型的数据,但它们使用的属性名是不同的。最右边的数据源S5则存储影评数据。
中介模式包括4个关系:Movie(电影)、Actors(演员)、Plays(场次)和Reviews(评论)。注意在中介模式中Review(影评)并不包含date(日期)属性,但数据源S5中保存着相关信息。
数据源描述中的语义映射描述了数据源和中介模式之间的关系。例如,数据源S1到中介模式的映射将描述它包含表Movies,并且表Movies中的属性name与中介模式中表Movie的属性title相对应。它还将指定中介模式中的表Actors是数据源S1表Movies中name和actors两列的投影。
同样,语义映射将指定中介模式的Plays关系中的元组可以从数据源S2、S3、S4得到,并且S3中元组的属性location都为纽约(类似地,S4中元组的属性location都为旧金山)。
除了语义映射之外,数据源描述还指明了数据源其他方面的一些信息。首先,它们指明数据源是否是完整的。例如,数据源S2可能不包含整个国家所有的电影放映时间,而数据源S3包含所有在纽约的电影放映时间。其次,数据源描述可以指定对数据源访问方式的限制。例如,S1的描述指定,要想得到查询结果,输入的查询语句中至少要给出一个属性值作为限制条件。同样,要对其他提供电影播放场次的数据源进行查询,必须输入影片名称。
查询处理
我们使用中介模式中的数据来向数据集成系统发起查询。下面的这个查询语句想要查找Woody Allen(伍迪·艾伦)导演的电影在纽约的放映时间。
如图1-6所示,查询的过程按照如下步骤进行。
查询重写 如前所述,用户查询是用中介模式中的术语构成的。因此,系统要做的第一步是把查询语句重写成与数据源模式对应的形式。要做到这一点,数据集成系统就要使用数据源描述。重写的结果是一组与数据源模式相对应的查询语句,把它们的执行结果组合起来就可以得到原始查询的结果。我们把这个重写的结果称为逻辑查询计划。
重写过程如下:
Movie(电影)的元组可以从数据源S1直接获得,但需要将属性title转换为S1中的name。
Plays(场次)元组可以从数据源S2或S3得到。由于已知S3包含了纽约市的完整数据,所以我们选择S3而不选择S2。
由于数据源S3需要输入电影的名称进行查询,所以查询计划必须首先访问数据源S1,然后把从S1中得到的电影名称作为S3的查询输入。
因此,查询重写引擎所产生的第一个逻辑查询计划就是访问S1和S3以便得到查询结果。然而,第二个逻辑查询计划也是正确的,即先访问S1,再访问S2,虽然得到的结果可能不完整。
查询优化 和传统的数据库系统一样,查询处理的下一个步骤是查询优化。查询优化把一个逻辑查询计划转化为一个物理查询计划,物理查询计划指定访问各个数据源的确切顺序,在组合查询结果时,要用哪些算法来对数据进行操作(例如,数据源之间的连接),以及给每个操作分配多少资源。如前所述,该系统还必须处理数据的分布性所带来的挑战。
在我们的例子中,优化器将决定使用哪种算法来连接S1和S3。例如,连接算法可能以流水线的形式把电影名称从S1输入到S3,或者可能把结果先缓存起来,然后再整批发送到S3。
查询执行 最后,执行引擎负责物理查询计划的实际执行。执行引擎通过包装器调度各个数据源,然后将返回的结果按照查询计划指定的形式组合起来。
数据集成系统与传统数据库系统的另一个显著区别在于,传统数据库系统的执行引擎只是执行由查询优化器发给它的查询计划,而数据集成系统的执行引擎可能会根据其监测的查询计划的执行进展,要求优化器重新考虑查询计划。在我们的例子中,执行引擎可能会发现数据源S3异常缓慢,因此可能会询问优化器能否使用其他数据源来代替S3。
当然,另一种可选办法是在优化器中为原始计划设定好一些突发事件。但是,如果意外执行的事件很多,原计划就可能变得很庞大。因此,在设计查询处理引擎时,一个有趣的技术挑战就是如何平衡计划的复杂性以及应对意想不到的执行事件的能力。