SQL Server 2005数据挖掘开发者指南(3)
[b]OLE DB[/b][b]作为通用API [/b]
在微软Windows操作系统中,OLE DB是进行数据访问最常用的API。OLE DB是针对OLE对象的规范。这些OLE对象有一系列标准接口。这些接口的标准化使得一个编程模型几乎可以访问所有类型的数据源。微软SQL Server数据挖掘有一个OLE DB提供程序。这个提供程序能将OLE DB编程模型翻译成数据挖掘所需要的内容。
关于 OLE DB的更多内容,请访问MSDN OLE DB页。
OLE DB可以被很多种编程语言直接使用。在本机(非托管)C++中,可以创建OLE DB对象,并且可以直接调用OLE DB的方法。ALT使用者模版(ALT Consumer Templates)也为OLE DB使用者应用程序提供了一系列有用的类。在Visual Basic或者VBA中,OLE DB提供程序可以在ADO(ActiveX Data Objects,ActiveX数据对象)中使用。在托管语言中,我们可以使用ADO.NET 库来调用OLE DB提供程序。
OLEDB编程模型以如下对象为中心。首先,数据源必须由服务器端初始化和控制。其次,在这个数据源上必须初始化一个通讯对话。OLE DB架构的第三个重要组成部分就是命令,它们将服务器请求打包。每个服务器请求都是对话的一部分。OLE DB架构的第四个组成部分是服务器响应。大多数数据挖掘任务可以被OLE DB命令所执行。例如,可以使用一个命令来传输DMX语句,也可以传输一个DDL语句来创建一个新的元数据。但是命令并不能传输一个发现元数据语句(Discovery)。所以针对此点,OLE DB定义了一个可以被对话执行的[b]IDBSchemaRowset[/b]接口。这里我们需要注意的是,ADO和ADO.NET有一个封装了数据源和OLE DB对话的连接对象(Connection)。这两种标准的OLE DE对象(数据源和OLE DB对话)公开的功能在ADO和ADO.NET的连接对象中可用。
所有的OLE DB对象(数据源、对话、命令和响应)经常在COM组件中执行来调用OLE提供程序。
下面的图1给出了一个OLE DB解决方案的框架:
[align=center][attach]61874[/attach]
[b]图 1. OLE DB解决方案框架图[/b][/align]
如图中所示,首先,各个客户端上安装的OLE DB提供程序使用OLE DB来连接服务器。Microsoft Analysis Services 2005的OLE DB提供程序是在安装SQL Server 2005的连接组件时安装的。
OLEDB连接经常通过连接字符串的方法来初始化。连接字符串包含一系列有分号分隔开的“名字-值”字符对,即属性。这些属性描述了OLE DB连接初始化时的各个参数。所有的OLE DB包(如ATL使用者模版、ADO、或者ADO.NET)都根据连接字符串来进行初始化。这里给出一个用来连接Microsoft Analysis Services 2005的OLE DB连接字符串的例子:
[color=#000080]"Provider=MSOLAP; Data Source=localhost; "[/color]
[color=#000080] [/color]
第一个属性 [b]Provider[/b]描述示例中指定的提供程序。
"MSOLAP" 是微软分析服务中OLE DB提供程序的名字。请注意这个名字是依赖版本的。如果一台机器上安装了多个分析服务OLE DB提供程序(如一个来自Analysis Services 2005,一个来自Analysis Services 2000),就需要使用更加准确的名字来区分版本:Analysis Services 2000使用“MSOLAP.2”,Analysis Services 2005使用“MSOLAP.3”。第二个属性“Data Source”表示要连接的数据源。它一般都是一个机器名,但是也可以是其它表达方式。例如,它可以是一个文件名,或者是一个网络URL,如我们将在下文“HTTP Pump”章所见到的一样。关于分析服务OLE DB提供程序属性的更多信息,你可以从SQL Server在线信息中得到。
下面这段代码是一个VBA应用程序中使用OLE DB的例子,它使用了ADO。具有相似功能的C#代码(使用ADO.NET)和非托管C++代码在附录2中。
为使用ADO,需要为你的Visual Basic (或者VBA)工程添加一个指向Microsoft ActiveX Data Object库(你机器中最新版本的库)的引用。以下的代码片段是在2.8版本上进行测试的:
[color=#000080]1 Dim Conn As ADODB.Connection[/color]
[color=#000080]2[/color]
[color=#000080]3 Set Conn = New ADODB.Connection[/color]
[color=#000080]4 Conn.Open ("Provider=MSOLAP.3; Data Source=localhost;" _[/color]
[color=#000080]5 & "Initial Catalog=MyCatalog")[/color]
[color=#000080] [/color]
在第一行和第三行创建并初始化了一个ADODB连接对象。在第四行,就像我们前边所说的,ADO连接对象封装了两种OLE DB对象:数据源和对话。在连接字符串中,你将看到一个之前没有讨论过的属性:“Initial Catalog”。它定义服务器上将被这个连接使用的数据库。让我们使用这个连接对象来完成我们之前列举的数据挖掘任务。
对于元数据发现(Discovery),ADO连接提供了一个[b]OpenSchema[/b]函数(在OLE DB对话中打包了[b]IDBSchemaRowset[/b]接口)。
[b]OpenSchema[/b] 包含3个参数:
· 枚举,用来描述将要被发现的计划。
· 约束集,将被应用于发现操作的一系列约束。
· 全局唯一标识符(GUID),描述提供程序指定的计划。
我们尝试在MyCatalog 数据库上发现服务器端的挖掘模型。这不是数据挖掘模型计划(指定的提供程序计划)中预先计划好的枚举,所以第一个参数就是[b]adSchemaProviderSpecific[/b]。第二个参数,约束集,包含用来查找模型(“MyCatalog”)的目录名。第三个参数包含Analysis Services OLE DB提供程序中,能识别挖掘模型计划的GUID的字符表。
[color=#000080]6 Const DMSCHEMA_MINING_MODELS="{3add8a77-d8b9-11d2-8d2a-00e029154fde}"[/color]
[color=#000080]7 Dim Restrictions()[/color]
[color=#000080]8 Restrictions = Array("MyCatalog")[/color]
[color=#000080]9 Dim rsSchema As ADODB.Recordset[/color]
[color=#000080]10 Set rsSchema = Conn.OpenSchema([/color]
[color=#000080]adSchemaProviderSpecific, [/color]
[color=#000080]Restrictions, [/color]
[color=#000080]DMSCHEMA_MINING_MODELS)[/color]
[color=#000080] [/color]
数据挖掘的OLE DB规范包含分析服务的OLE DB提供程序支持的计划的完整定义,包括发现(Discovery)语句返回的列和约束。
[b]OpenSchema[/b]返回一个[b]ADODB.Recordset[/b]对象。[b]Recordset[/b]对象封装了一个表型服务器响应。下面我们将看到如何遍历这个对象以及如何从中提取信息。这段代码的目的是枚举挖掘模型的名字。 像我们所知道的一样,在数据挖掘OLE DB里,挖掘模型计划中的每一行对应一种挖掘模型,并且包含一个“MODEL_NAME”列,列中存储挖掘模型的名字。
下面一段代码显示如何从[b]Recordset[/b] 对象中查找指定的列,以及如何从这些列中提取信息。
[color=#000080]11 [/color]' 从(MODEL_NAME)中查找列
[color=#000080]12 Dim iModelNameColumn As Integer[/color]
[color=#000080]13 For iModelNameColumn = 0 To rsSchema.Fields.Count - 1[/color]
[color=#000080]14 If rsSchema.Fields(iModelNameColumn).Name = "MODEL_NAME" Then [/color]
[color=#000080]15 GoTo Found[/color]
[color=#000080]16 End If[/color]
[color=#000080]17 Next[/color]
[color=#000080]18 Error (1)[/color]
[color=#000080]19 Found:[/color]
[color=#000080]20 [/color]' 读取Recordset的返回值
[color=#000080]21 rsSchema.MoveFirst[/color]
[color=#000080]22 While Not rsSchema.EOF[/color]
[color=#000080]23 Debug.Print rsSchema.Fields(iModelNameColumn).Value[/color]
[color=#000080]24 rsSchema.MoveNext[/color]
[color=#000080]25 Wend[/color]
[color=#000080] [/color]
如你所看到的一样,这段代码先遍历了[b]Recordset[/b] 对象的所有字段。每个字段表示响应的一列。我们根据这些字段的索引MODEL_NAME进行查找。如果找到了这样的一列,就开始遍历它的行内容,否则就报错。
为了遍历行, [b]Recordset[/b]指针先移到数据的开始位置。之后一行一行的读取行数据。对于每一行都读取和使用MODEL_NAME字段的值。一些数据挖掘任务(如创建新元数据对象或训练已存在的对象)可以通过发送DDL语句到服务器来执行。让我们看看DDL语句是如何被OLE DB通过ADO来传输的。我们将使用与之前一样的连接对象,并介绍一个新的OLE DB对象的ADO包, [b]ADODB.Command[/b]对象:
[align=center][attach]61875[/attach][/align]
命令在一个活跃连接中执行。这个活跃的连接就是第28行中的内容。一般来说,这个命令包含着执行语句。这在[b]CommandText[/b] 属性(第40行)中设置。当ADO为Analysis Services 2005打包OLE DB提供程序时,[b]CommandText[/b]属性支持DMX语句和DDL语句(就像之前所展示的一样)。命令的执行被“执行(Execute)”方法初始化(第41行)。执行经常返回一个[b]ADODB.Recordset[/b] 对象(可用于之前的发现(Discovery)代码段的表型服务器响应)。但是,处理操作是没有服务器响应的,它不返回成功或失败。如果出现了一个错误,ADO将报一个异常并停止正在运行的代码。因此,如果执行到了第42行,就说明执行成功了。
在之前的代码中,可以将[b]CommandText[/b] 属性改为一个DDL语句,比如[b]Alter[/b]、[b]Create[/b]或者[b]Dro[/b][b]p[/b];或改为一个DMX语句,如CREATE MINING MODEL或者INSERT INTO,它可以实现绝大多数挖掘任务。唯一一个需要附加补充的是查询挖掘模型。DMX查询与一般的无响应信息语句不同,因为:
· 它返回一个表型结果。
· 表型结果可能包含多级的表(嵌套表)。
· DMX 支持参数。
我们可以从返回单级表的DMX查询开始看起,使用我们最开始使用的对象来对比(命令和连接):
[color=#000080]43 Cmd.ActiveConnection = Conn[/color]
[color=#000080]44 Cmd.CommandText = "SELECT NODE_CAPTION FROM DecisionTree1.CONTENT" _[/color]
[color=#000080]45 &"where NODE_TYPE=2"[/color]
[color=#000080]46[/color]
[color=#000080]47 Dim rs As ADODB.Recordset[/color]
[color=#000080]48 Set rs = Cmd.Execute()[/color]
[color=#000080] [/color]
[color=#000080]49 rs.MoveFirst[/color]
[color=#000080]50 While Not rs.EOF[/color]
[color=#000080]51 Debug.Print rs.Fields(0).Value[/color]
[color=#000080]52 Wend[/color]
[color=#000080]53 rs.Close[/color]
[color=#000080] [/color]
如我们之前所提到的一样,DMX语句由[b]CommandText[/b]属性来传输。与发现(Discovery)使用相同的方式来遍历[b]Recordset[/b]。第44行用到的查询只返回一列,这里并不真正需要从recordset 字段来查找列;相反的,它应该由它的索引得到(第51行)第0字段的内容。也请注意第53行中对[b]Recordset[/b] 的配置。当[b]Recordset[/b] 是活跃的时候,命令对象不能执行之后的语句。
OLE DB规范也允许返回更加复杂的结果集,如表型列或者嵌套表。下面给出一个服务器响应是嵌套表的例子,我们将使用DMX语句来添加查询更复杂的第二列NODE_DISTRIBUTION。所以新的查询如下所示:
[color=#000080]"SELECT NODE_CAPTION, NODE_DISTRIBUTION FROM DecisionTree1.CONTENT WHERE NODE_TYPE=2"[/color]
[color=#000080] [/color]
NODE_DISTRIBUTION 是一个典型的嵌套表例子。根据数据挖掘的OLE DB规范,模型中的NODE_DISTRIBUTION列包含当前行所在节点的属性值的分布。例如,在一棵预测头发颜色的决策树中,对每一个树节点,这一列都描述有多少实例是黑发,多少实例是金发,多少实例是灰发。
执行命令在新的一列中并不改变。实际上唯一需要改变的就是[b]Recordset[/b]的遍历代码,需要进行适合表的新列的改变。在代码中可以很容易的从[b]Recordset[/b] 作为字段值的属性返回一列的值。如果实例中的列是一个嵌套表,列值将产生一个新的[b]Recordset[/b],再遍历整个嵌套表。
所以,在51行以下应该执行如下的代码:
[color=#000080]52 Debug.Assert( rs.Fields(1).Type = adChapter)[/color]
[color=#000080]53 Dim nestedRS As ADODB.Recordset[/color]
[color=#000080]54 Set nestedRS = rs.Fields(1)[/color]
[color=#000080]55 nestedRS.MoveFirst[/color]
[color=#000080]56 While Not nestedRS.EOF[/color]
[color=#000080]57 Debug.Print nestedRS.Fields(0).Value[/color]
[color=#000080]58 Wend[/color]
[color=#000080]59 nestedRS.Close[/color]
[color=#000080] [/color]
第52行语句用来在将值写入嵌套[b]Recordset[/b]前,确认列的类型是正确的。这行语句也可以用来判断制定的列是不是一个嵌套表。
应为拥有遍历嵌套表的能力,此时数据挖掘查询产生的任何返回值都可以在你的应用中被使用了。
DMX也支持查询中的参数。参数可以取代DMX查询中的任何值。例如,可以使用一个参数来代替上述查询语句中[b]where[/b]子句里的NODE_TYPE 的值“2”。在数据挖掘应用中,也有少数参数非常有用的场景,比如生成一个单独的查询(关于单独查询的详细内容,请看“Adomd.NET”一节)。
想在DMX查询中将一个值变为一个参数,我们使用参数指示标志[b]@[/b]来开始替换,使用“[b]@[/b]唯一的参数名”。这样VBA代码片段中的第45行就可以变成:
45 &"where NODE_TYPE=@typeParam"
然后,在执行命令之前,我们应该插入这样的一段代码来确保能正确的使用新的参数。请注意,尽管实际数据可能与参数的值很不同,但是使用参数并不会改变服务器响应的格式。所以上述遍历[b]Recordset[/b] 的代码可以并不改变。
[color=#000080]46 Cmd.NamedParameters = True[/color]
[color=#000080]47[/color]
[color=#000080]48 Dim typeParameter As ADODB.Parameter[/color]
[color=#000080]49 Set typeParameter = Cmd.CreateParameter()[/color]
[color=#000080]50 typeParameter.Direction = adParamInput[/color]
[color=#000080]51 typeParameter.Name = "typeParam"[/color]
[color=#000080]52 typeParameter.Value = 2[/color]
[color=#000080]53 typeParameter.Type = adInteger[/color]
[color=#000080]54 typeParameter.Size = 4[/color]
[color=#000080]55[/color]
[color=#000080]56 Cmd.Parameters.Append typeParameter[/color]
[color=#000080] [/color]
在分析服务的OLE DB提供程序中使用参数时,如下的几步非常重要:
· 命令必须使NamedParameters可用(第46行)。分析服务的OLE DB提供程序只支持命名了的参数。
· 参数的名字必须符合查询中的相应参数,但是在这里不使用[b]@[/b]前缀(第51行)。
· 可以只传输参数(第50行)。
· 参数的类型和大小必须声明(第53和54行)。
想对数据挖掘的OLE DB规则进行很好的理解,需要充分使用Microsoft Analysis Services 2005数据挖掘的特性。一旦设计好了数据挖掘查询,OLE DB就成为了一个可以执行它们、可以管理数据挖掘服务器的完整且具有通用性的API。关于在非托管C++或ADO.NET中C#使用OLE DB 的代码,请看本文附录2中的代码片段。 |