作者:
Bogdan Crivat,微软公司
时间: 2005年3月
适用于:
微软 SQL Server 2005
SQL Server 数据挖掘(SQL Server Data Mining)
摘要: 介绍SQL Server 2005数据挖掘的新API以及几种常用的开发场景。
版权
在这篇文章中所包含的信息代表了从发布日起微软对所讨论的问题的当前观点。因为微软必须对市场的变换做出响应,它不应该被理解为微软所必须承担的任务的一部分,微软也不能保证在发布日之后所提出的信息的精确性。
这个白皮书仅仅是为了信息的目的,微软对本文中的信息不做任何授权、表示、暗含或规定。
依从所有可适用的版权法是用户的责任。没有限制权利在版权之下,这个文档的部分不允许被再生产,存放或介绍入检索系统, 或被以任何形式传送或通过任何手段(电子, 机械, 影印, 记录, 或其他) 或为任何目的,没有微软的明确书面允许。
微软对于在这篇文章中所包含的主题拥有专利、专利申请、商标、版权或其他的一些知识产权。除了微软明确提供的一些书面的特许契约,这个文档的并不提供给您任何专利、商标、版权或其他知识产权的执照。
版权所有2005 Microsoft Corporation。
Microsoft 和Visual Studio在美国或其他国家都有注册商标或微软的商标。
在这里的实际的公司和产品的名字可能是他们各自的商标。
随着微软SQL Server 2005的诞生,统计技术和机器学习算法的综合产物,也就是众所周知的数据挖掘,被带入了一个新的阶段。在SQL Server 2005中,数据挖掘最重要的转变是改变了它的目标用户。除了作为一个科学的实验工具,面向有限的专业人士,如今SQL Server 数据挖掘已广泛存在,成为开发者捶手可得的工具,并且已经做好了在更广阔的领域中应用的准备。从电子数据表格到网络游戏,从点到点通讯系统到应用服务器,绝大多数应用都有这样一个共同点:它们不得不进行数据处理。在进行数据处理的时候,它们使用特定的标准API来访问数据。在SQL Server 2005数据挖掘的数据处理系统中,这些API也同样可以被智能的嵌入到应用中。
这篇文章带你思考将SQL Server数据挖掘嵌入到应用中的契机。文章重点关注可编程内容,即通过写代码来使用数据挖掘技术和增强服务器特性。我们将给出一系列可以被数据挖掘引擎执行的常用任务,并针对它们展示微软SQL Server数据挖掘体系结构的解决方案。之后,我们将列举一些客户端产品(Adomd.NET 和 OLE DB)的可编程API。之后的一个章节专注于Analysis Management Objects所管理的API。随后,我们将展示服务器创建新的存储过程以及添加新的算法插件和查看器等扩展功能.
数据挖掘应用也可以结合联机分析处理(OLAP)、Reporting Services或者Integration Services来创建。然而,这篇文章不介绍这些内容,而是严格通过代码来介绍数据挖掘功能和如何增强数据挖掘功能。
数据挖掘和联机分析处理都是微软分析服务的组件。本篇文章中介绍的客户端API同时适用于这两种组件。但是,本文的介绍仅针对数据挖掘。其中的场景、代码实例、元数据对象都是针对数据挖掘的。
与 Microsoft Analysis Services 2005 通讯
让我们从Microsoft Analysis Services 2005(与数据挖掘服务器之间)的通讯协议开始。客户端通过Analysis Services 2005来执行这个通讯协议(比如使用Microsoft OLE DB Provider for Analysis Services 9.0 或者 Adomd.NET),并且这个协议也必须被其它客户端执行。
Microsoft Analysis Services 2005 使用SOAP作为最外层的通讯层。(更多关于SOAP的内容请访问这个网页。)SOAP为应用程序定义了一系列可以通过XML消息来调用的方法。 这些方法由Microsoft Analysis Services 发布,使用XML for Analysis或者 XMLA来定义。
XMLA规范是由一个超过20家研究商业智能的龙头企业(包括微软公司、Hyperion和SAS 学会)组成的组织提出的,它是一个标准的OLAP和数据挖掘技术接口。 更多关于XMLA的信息,请点击这里。
XMLA定义了两种发送给服务器的请求,以及服务器进行响应返回的信息的格式。请求的类型是“发现(Discover)”和“执行(Execute)”。“发现”用来从服务器获取信息和元数据。例如, “发现”可以用来获取服务器上一系列挖掘模型以及它们的属性(列描述、算法等等)。“执行”用来执行对服务器的命令,如创建一个新的目录或者挖掘模型、训练一个模型、或者执行一个查询。
数据定义语言( DDL) 和 数据挖掘扩展语言(DMX)
XMLA的“执行”命令可应用于多种任务。这里有几个例子:
· 创建(Create)命令:这些命令在服务器上创建一个新的元数据对象,它们包含被创建的对象的全部或部分属性,例如名称、数据绑定、挖掘模型和挖掘结构中的列、挖掘模型的数据挖掘算法等等。
· 修改(Alter)命令:这些命令修改已存在的服务器元数据对象的属性。
· 删除(Drop)命令:这些命令用来从服务器上去掉元数据对象。
· 处理(Process)命令:这些命令用来初始化那些基于当前绑定的训练数据集定义的元数据对象上的训练序列。
· 语句 (查询语句)。
当一个XMLA“执行”请求描述一个对象(如创建Create或者修改Alter语句)或者将一个对象定义为一个动作的目标(如处理Process或删除Drop)时,命令的内容由Microsoft Analysis Services 数据定义语言(Data Definition Language —— DDL)组成。DDL是Analysis Services 2005中元数据以及元数据操作的内部表示方法。 服务器上的对象存储在DDL中,商业智能化项目由若干DDL片段组成。关于DDL的更多细节,请查看SQL Server 2005 在线文档中的“分析服务脚本语言(Analysis Services scripting language)”。
另一方面,在数据挖掘任务中,当XMLA请求是一个语句的时候,XMLA “执行”请求使用一种查询语言——DMX(数据挖掘扩展Data Mining eXtensions语言)作为它的请求的内容。DMX语言在针对数据挖掘的OLE DB 规范中定义,在这里可以使用。
Microsoft Analysis Service 2005 也可以使用另一种查询语言来执行语句——MDX。MDX语言是为OLAP组件所设计的。所以,这里我们只关注DMX。
区分DDL和DMX是非常重要的:DDL是一种由Analysis Services 2005使用的类XML语言,用来描述、管理和指定元数据。DDL可以很方便的扩展到XMLA。
而DMX是一种为数据挖掘而设计出的类SQL语言。DMX与SQL非常类似,DMX包含这样的结构,它们允许创建和操作元数据对象(想想SQL中的CREATE TABLE 或者INSERT INTO语句,DMX中有与其等价的CREATE MINING MODEL 和INSERT INTO 语句)。然而,对于管理元数据对象的任务来说,DMX的灵活性比DDL要差。DMX语句无法扩展到XMLA;但是它们可以被固定的XMLA结构所包括。
文章结尾处的附录1提供更多Microsoft Analysis Services 2005协议部署的细节内容。
SOAP相对来说比较容易操作;大多数开发工具都提供针对创建、传输、接收SOAP包的帮助。但是,选择使用DDL请求还是DMX请求,并把它按照适当的格式封装到XMLA语句中就不是一件那么容易的事情了。所以开发者需要比仅仅使用XML流作为通讯方法更好的工具。这也就是为什么如今可编程API存在的原因。这些API将XMLA请求的相关操作作业打包,分析XMLA的响应信息,并且向开发者提供一个更具逻辑性的通讯视图,用来操作内部细节。也有一小部分API可以被Microsoft SQL Server 数据挖掘应用。选择哪个API取决于客户端执行的请求的类型和客户端的开发环境。
下一节将分析典型的数据挖掘在客户端/服务器端通讯(C/S)时的客户端请求。之后的章节将从各种数据挖掘可编程API处理典型请求时的方法以及它们支持的客户端环境的角度,具体展示这些API以及它们之间的差别。
数据挖掘任务
SQL Server数据挖掘服务器支持多种请求。对于每一种请求,我们将给出可用的DDL命令和等价的DMX:
· 元数据的发现:这些请求允许客户端应用根据一些属性,如挖掘模型的列、使用的算法、被训练的数据集,迭代服务器上已存在的元数据对象,并且从中选择一个或多个有用的元数据。XMLA规范为这类请求定义了发现(Discover)命令,没有与其直接对应的DMX或DDL。
· 元数据的定义:这些请求是一系列对服务器上的数据结构的定义。这些数据结构是挖掘结构和挖掘模型,它们由目录(数据库)组合在一起。针对这些请求的XMLA命令是执行(Execute),包括DDL用来创建和修改的Create 或 Alter 语句。也可以使用DMX的 CREATE语句,尽管它的灵活性要比DDL 的Create语句差。
· 模型的训练:这些请求为服务器端的数据挖掘模型执行训练处理。训练可以使用预先绑定的数据(在元数据定义时决定),也可以只描述当前正在处理的操作的数据集。XMLA命令还是 执行(Execute),包含一个DDL的处理(Process)语句。在DMX中,训练可以由插入(INSERT INTO)命令得到。
· 查询模型:这些请求包括(但不局限于)在数据挖掘中我们常说的记分(Scoring)和预测(Predicting)。 我们将查询定义为使用数据挖掘所建立的模型的过程。这些请求由发送到服务器端的DMX语句组成。
· 订阅进度通知:这些请求非常方便地显示一个进度条,这个进度条用来显示在执行一个很长的操作时或者在指定时间检查服务器状态时的实际进展情况。这类请求不能使用DMX创建。它们拥有跟踪的功能,作为带DDL订阅(Subscribe)语句的XMLA执行(Execute)命令来进行传输。
对这些任务有了基本概念后,我们可以正式开始列举可编程API及它们的特性了。上述任务中的最后一项,关于进度的通知,我们将单立一节的内容进行讲解,下面的API章节就不再讨论这个任务了。
通用API
我们将探讨两种常用的API:Adomd.NET和OLE DB。它们的差别在于它们的目标环境不同: OLEDB (OLE for Databases)主要针对非托管应用(尽管它也可以被用于托管应用);而Adomd.NET针对托管应用。下边我们将看到,这些API具有非常相似的结构。它们都基于非常有名的数据库访问范例。
Adomd.NET 作为通用API
Adomd.NET是由Microsoft Analysis Services 2000提供的旧ADOMD库的托管版本。这个库专门为Microsoft Analysis Services 2005的客户端而设计。它执行ADO.NET数据访问范例(包括一系列标准接口,如 IDbConnection、IDbCommand、 IDataReader 等等),并且使用Microsoft Analysis Services 2005提供的许多特性来扩展这些范例。
在.NET框架中, System.Data 命名空间使你可以建立从多个数据源有效管理数据的组件。关于此点的更多内容请参考关于 System.Data 命名空间的MSDN文档。 System.Data 拥有多种特性,它定义一系列可以被.NET数据提供程序执行的用来访问关系型数据库的接口。微软分析服务(Microsoft Analysis Services)是一个多维数据库,它比普通关系型数据库拥有更强大的功能。Adomd.NET是一个.NET数据提供程序,能执行提供给.NET数据提供程序的一系列标准 System.Data 接口,这些接口的功能在Analysis Services 2005中得以增强,也增加了很多在关系型数据库中不使用的新特性。
Adomd.NET作为SQL Server 2005连接组件的一部份被安装,也可以单独下载进行安装。在从应用程序使用它之前,必须在机器上安装Adomd.NET数据提供程序。
这一节的代码示例使用Visual Studio 2005的C# 2.0实现。经过一个简单的“翻译”过程,它们也可以被Visual Studio 套件的任意托管语言(如Visual Basic .NET或Visual C++ .NET)运转。
在应用程序中使用 Adomd.NET时,必须先添加一个 Microsoft.AnalysisServices.AdomdClient. dll程序集,使用类似如下的代码进行添加:
using Microsoft.AnalysisServices.AdomdClient;
下一步,连接Microsoft Analysis Services 2005 服务器:
AdomdConnectionconn = new AdomdConnection();
conn.ConnectionString = "Data Source=localhost; " +
"Initial Catalog=MyCatalog";
conn.Open();
在数据挖掘任务列表中,第一个是元数据对象的发现。就像我们前边所说的一样,元数据的发现由XMLA发现(Discover)命令实现。Adomd.NET提供两种简单的方法来发现元数据。第一种与AMO非常相似:
foreach (MiningModel model in conn.MiningModels)
{
Console.WriteLine(model.Name);
}
微软分析服务开发团队尽了很大的努力来确认常用的计划都已包含于Adomd.NET Connection类所发布的程序集中。你可以使用之前的这些代码来访问数据库中的挖掘结构集、一个结构中或者整个数据库中的挖掘模型列表、以及模型和结构中的列。Adomd.NET 拥有远超过AMO 的功能,它允许代码这样构成分级模型:
foreach (MiningContentNode node in model.Content)
{
foreach( MiningContentNode in node.Children )
{
// 使用节点的属性
}
}
对Microsoft Analysis Services 2005中的OLAP计划来说,Adomd.NET Connection 对象所发布的程序集比数据挖掘所提供的程序集更加适用。所以在Adomd.NET中你可以使用相同的方法来浏览立方体和维度。
发现服务器元数据的第二种方法与OLE DB的方法非常相似,也就是执行一个发现(Discovery)命令来传输一个GUID计划和一系列约束,然后返回一个可以被遍历的表型结果。 有些计划返回的是分级表型结果(嵌套表)。这也就是为什么在Adomd.NET 中,一个发现操作的返回值是一个 数据集 (DataSet ) ;对比ADO.NET ,它返回的是一个数据表。数据集可以描述表之间的关系,所以数据集可以包含一些发现操作的嵌套表型结果。下边的一段代码片段发现了一个挖掘模型的内容,并且使用数据集得到了响应NODE_DISTRIBUTION嵌套表计划的嵌套行:
Guid modelContent = new Guid("{3ADD8A76-D8B9-11D2-8D2A-00E029154FDE}");
object[] arRestrictions = new object[3];
// 约束发现(Discovery)MyCatalog目录中DecisionTree1模型的内容。
// 第二个约束(MODEL_SCHEMA) 在这里忽略。
arRestrictions[0] = "MyCatalog";
arRestrictions[1] = null;
arRestrictions[2] = "DecisionTree1";
DataSet dsContent = conn.GetSchemaDataSet(
modelContent, arRestrictions);
// 一致性检查:确认关系值为1
Debug.Assert( dsContent.Relations.Count == 1);
DataRelation relation = dsContent.Relations[0];
DataTable topTable = relation.ParentTable;
foreach (DataRow row in topTable.Rows)
{
// 使用最上层表中的列
Console.WriteLine("NODE_CAPTION=" + row["NODE_CAPTION"]);
Console.WriteLine("NODE_UNIQUE_NAME" + row["NODE_UNIQUE_NAME"]);
// 根据关系描述,取得嵌套行
DataRow[]distRows = row.GetChildRows(relation);
foreach (DataRow distRow in distRows)
{
// 使用嵌套表中的列
Console.WriteLine(distRow["ATTRIBUTE_VALUE"]);
}
}
与OLE DB非常相似,Adomd.NET提供发送请求到服务器的命令。这些请求可以是DDL或者DMX的;所以它们可以创建或者修改已经存在的、用来训练挖掘结构和挖掘模型的元数据对象(DDL和DMX),也可以查询已存在的模型(只支持DMX)。我们也就可以通过此点来区分元数据的创建、处理,和DMX的查询。它们的区别在于:DMX查询返回一个表型结果(分层的或者单层的),而元数据创建和处理语句只返回一个成功或者失败。Adomd.NET公开了一些执行(Execute)方法,其中两种对于返回成功/失败的请求和返回表格型数据的请求非常有用。
第一种:我们使用一个DDL处理语句作为示例,任何其它的DDL语句(如Alter、Create或者Drop)也可以使用相同的代码。
AdomdCommand cmd = new AdomdCommand();
cmd.Connection = conn;
cmd.CommandText = "
"xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">"+"<Type>ProcessDefault</Type>" +
" <Object>" +
" <DatabaseID>MyCatalog</DatabaseID>" +
" <MiningStructureID>Structure1</MiningStructureID>" +
" </Object>" +
"</Process>";
cmd.ExecuteNonQuery();
同样, ExecuteNonQuery 也可以执行一个DMX语句来产生相同的结果:
"INSERT INTO MINING STRUCTURE Structure1"
当 ExecuteNonQuery 被调用的时候,如果请求执行成功了,语句将返回;如果执行失败将报一个异常。在之后的例子中,将给出异常的具体信息,如服务器返回的错误信息。
第二种执行方法是 ExecuteReader 。这种方法应该在语句的返回值肯定是表型的时候被调用。就像我们前边所提到的一样,Microsoft Analysis Services 2005返回的结果有时会是分层表型结果。例如,让我们考虑这样的一个模型, Model1,它根据消费者的年龄、他/她汽车的颜色来预测消费者的性别和购买商品的清单。当然,这样的模型可能并没有现实意义,但是,它却是一个很容易使DMX语句返回分层表结构结果的例子。
下面的代码使用 AdomdCommand 来传输一个预测查询给服务器,并读取最上层返回值(预测的性别)和嵌套返回值(预测的商品列表):
cmd.CommandText = "SELECT Gender, Products FROM Model2 " +
"NATURAL PREDICTION JOIN "+
"( SELECT 30 AS Age, 'Black' as CarColor) AS T";
AdomdDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
// 使用上层结果,预测性别
Console.WriteLine( rdr.GetString(0) );
// 为第一列的嵌套内容获得一个nested reader
AdomdDataReader nestedReader = rdr.GetDataReader(1);
// 读嵌套内容并使用嵌套数据
while (nestedReader.Read())
{
Console.WriteLine(nestedReader.GetString(0));
}
nestedReader.Close();
}
调用 GetDataReader 将返回一个新的实例 AdomdDatareader 类,它被初始化后用来访问对列编号了的嵌套表。如果指定的列并不是一个被嵌套的表,“执行”方法将返回一个异常。我们可以使用类似如下代码的语言来判断Datareader中的列是不是一个嵌套表:
if (rdr.GetFieldType(1) == typeof(AdomdDataReader) )
{
// 如果进入If循环,rdr的第一列是一个嵌套表
}
在现实生活中,最有可能根据用户的实际输入来进行预测。一个常见的Web应用场景是这样的,用户给出年龄和汽车的颜色,应用程序代码产生一个DMX请求来预测该客户购买商品的清单。当开发者对DMX和相关的数据类型有一个很好的理解的时候,查询可以使用将客户录入的所有字符串连接起来的方式进行创建。 然而,这样的方法具有潜在的威胁,它可能引起DMX嵌入错误或研发错误。一种更好的方式是使用参数来建立查询,将用户输入的内容作为参数的值。Adomd.NET对DMX的参数化查询提供了大量的支持,就像下面的例子一样。这段代码不包括读取返回值的内容,因为它与之前的代码片段是一样的。
cmd.CommandText = "SELECT Gender, Products FROM Model2 " +
"NATURAL PREDICTION JOIN "+
"( SELECT @Age AS Age, @Color as CarColor) AS T";
AdomdParameter paramAge, paramColor;
paramAge = cmd.CreateParameter();
paramAge.Direction = ParameterDirection.Input;
paramAge.ParameterName = "Age";
cmd.Parameters.Add(paramAge);
paramColor = cmd.CreateParameter();
paramColor.Direction = ParameterDirection.Input;
paramColor.ParameterName = "Color";
cmd.Parameters.Add(paramColor);
cmd.Parameters["Age"].Value = 30; // 用户在这里输入
cmd.Parameters["Color"].Value = "Black"; // 用户在这里输入
AdomdDataReader rdr = cmd.ExecuteReader();
请注意,参数不一定非是数值。请考虑这样的DMX语句:
INSERT INTO MyModel(Col1, Col2)
OPENQUERY(DataSource, "SELECT ColA, ColB FROM Table") AS T
或者是:
SELECT PREDICT(Products, 5) FROM MyModel NATURAL PREDICTION JOIN
OPENQUERY(DataSource, "SELECT ColA, ColB FROM Table") AS T
这两个语句都用了一个OPENQUERY 函数来描述执行时被服务器使用的表型内容(训练挖据模型,分别进行预测)。使用Adomd.NET,我们可以使用一个参数来取代OPENQUERY函数,并且向服务器传输一些表型内容。查询可能是这样的:
INSERT INTO MyModel(Col1, Col2)
@MyTabularContent AS T
或者是:
SELECT PREDICT(Products, 5) FROM MyModel NATURAL PREDICTION JOIN
@MyTabularContent AS T
在这些例子中, 参数 MyTabularContent 可以是一个 数据表(DataTable ) 或者执行一个 IDataReader .NET接口。相比来说,数据表更容易使用, IDataReader 接口具有不需要将所有数据保存在内存中的优势。 IDataReader 执行的一个例子是客户端应用执行的SQL查询所返回的 SqlDatareader 。当然,一个SQL查询请求也可以在OPENQUERY 功能中被提交,但是这种请求的前提是服务器已经访问到了SQL数据库。表型参数为两种情况所设计:
· 数据库中的数据是客户端可见但是服务器端不可见的(这种情况应该使用 IDataReader )
· 数据在客户端应用程序所占用的内存中( DataTable 可以在这种情况时使用)
Adomd.NET 一个独有的特点是可以使用XML返回选定的列。Microsoft Analysis Services 2005为指定的查询返回这样的列。例如:
SELECT * FROM MyModel.PMML
这个语句将返回PMML 2.1格式下MyModel 模型的内容(即被支持PMML的MyModel使用的数据挖掘算法)。除了例如模型名称、PMML缓冲区大小这类元信息外,这个语句的返回值还包括指定的列和包含PMML的MODEL_PMML(一种被数据挖掘团队设计出来的XML格式,用来描述挖掘模型的内容)。
这个XML的内容可以以字符串方式被访问,但是Adomd.NET拥有分析XML列的能力(基于服务器端发来的指定的列类型来判断) 并且将它们发布为一个 System.Xml.XmlReader 对象。这些列也可以作为字符串被读取。以下的示例代码使用这一特性来访问带XML目录的列,同时使用字符串和 XmlReader 两种方法。
cmd.CommandText = "SELECT * from [MyModel].PMML";
AdomdDataReader rdr = cmd.ExecuteReader();
// 遍历响应结果,读取第5列,MODEL_PMML
while (rdr.Read())
{
// 取得列值
object objXMLValue = rdr.GetValue(5);
if (objXMLValue is System.Xml.XmlReader)
{
//使用一个XML reader
System.Xml.XmlReader pmmlReader =
(System.Xml.XmlReader)objXMLValue;
//在这里读PMML
}
// 使用字符串来获取这列
string strPMMLAsString = rdr.GetString(5);
}
Adomd.NET 的另一个特性是连续访问服务器响应,将在 进度通知:使用跟踪对象 一节中具体阐述。
Adomd.NET是Microsoft Analysis Services 2005中最具灵活性,最容易使用的客户端API。在编写以微软分析服务为目标的.NET应用操作时也同样推荐使用它。它提供了类AMO访问服务器元数据的大量特性,它允许执行DDL和DMX语句,并且它对DMX语句的参数也有很好的支持。
OLE DB作为通用API
在微软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定义了一个可以被对话执行的 IDBSchemaRowset 接口。这里我们需要注意的是,ADO和ADO.NET有一个封装了数据源和OLE DB对话的连接对象(Connection)。这两种标准的OLE DE对象(数据源和OLE DB对话)公开的功能在ADO和ADO.NET的连接对象中可用。
所有的OLE DB对象(数据源、对话、命令和响应)经常在COM组件中执行来调用OLE提供程序。
下面的图1给出了一个OLE DB解决方案的框架:
如图中所示,首先,各个客户端上安装的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连接字符串的例子:
"Provider=MSOLAP; Data Source=localhost; "
第一个属性 Provider 描述示例中指定的提供程序。
"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版本上进行测试的:
1 Dim Conn As ADODB.Connection
2
3 Set Conn = New ADODB.Connection
4 Conn.Open ("Provider=MSOLAP.3; Data Source=localhost;" _
5 & "Initial Catalog=MyCatalog")
在第一行和第三行创建并初始化了一个ADODB连接对象。在第四行,就像我们前边所说的,ADO连接对象封装了两种OLE DB对象:数据源和对话。在连接字符串中,你将看到一个之前没有讨论过的属性:“Initial Catalog”。它定义服务器上将被这个连接使用的数据库。让我们使用这个连接对象来完成我们之前列举的数据挖掘任务。
对于元数据发现(Discovery),ADO连接提供了一个 OpenSchema 函数(在OLE DB对话中打包了 IDBSchemaRowset 接口)。
OpenSchema 包含3个参数:
· 枚举,用来描述将要被发现的计划。
· 约束集,将被应用于发现操作的一系列约束。
· 全局唯一标识符(GUID),描述提供程序指定的计划。
我们尝试在MyCatalog 数据库上发现服务器端的挖掘模型。这不是数据挖掘模型计划(指定的提供程序计划)中预先计划好的枚举,所以第一个参数就是 adSchemaProviderSpecific 。第二个参数,约束集,包含用来查找模型(“MyCatalog”)的目录名。第三个参数包含Analysis Services OLE DB提供程序中,能识别挖掘模型计划的GUID的字符表。
6 Const DMSCHEMA_MINING_MODELS="{3add8a77-d8b9-11d2-8d2a-00e029154fde}"
7 Dim Restrictions()
8 Restrictions = Array("MyCatalog")
9 Dim rsSchema As ADODB.Recordset
10 Set rsSchema = Conn.OpenSchema(
adSchemaProviderSpecific,
Restrictions,
DMSCHEMA_MINING_MODELS)
数据挖掘的OLE DB规范包含分析服务的OLE DB提供程序支持的计划的完整定义,包括发现(Discovery)语句返回的列和约束。
OpenSchema 返回一个 ADODB.Recordset 对象。 Recordset 对象封装了一个表型服务器响应。下面我们将看到如何遍历这个对象以及如何从中提取信息。这段代码的目的是枚举挖掘模型的名字。 像我们所知道的一样,在数据挖掘OLE DB里,挖掘模型计划中的每一行对应一种挖掘模型,并且包含一个“MODEL_NAME”列,列中存储挖掘模型的名字。
下面一段代码显示如何从 Recordset 对象中查找指定的列,以及如何从这些列中提取信息。
11 ' 从(MODEL_NAME)中查找列
12 Dim iModelNameColumn As Integer
13 For iModelNameColumn = 0 To rsSchema.Fields.Count - 1
14 If rsSchema.Fields(iModelNameColumn).Name = "MODEL_NAME" Then
15 GoTo Found
16 End If
17 Next
18 Error (1)
19 Found:
20 ' 读取Recordset的返回值
21 rsSchema.MoveFirst
22 While Not rsSchema.EOF
23 Debug.Print rsSchema.Fields(iModelNameColumn).Value
24 rsSchema.MoveNext
25 Wend
如你所看到的一样,这段代码先遍历了 Recordset 对象的所有字段。每个字段表示响应的一列。我们根据这些字段的索引MODEL_NAME进行查找。如果找到了这样的一列,就开始遍历它的行内容,否则就报错。
为了遍历行, Recordset 指针先移到数据的开始位置。之后一行一行的读取行数据。对于每一行都读取和使用MODEL_NAME字段的值。
一些数据挖掘任务(如创建新元数据对象或训练已存在的对象)可以通过发送DDL语句到服务器来执行。让我们看看DDL语句是如何被OLE DB通过ADO来传输的。我们将使用与之前一样的连接对象,并介绍一个新的OLE DB对象的ADO包, ADODB.Command 对象:
26 Dim Cmd As ADODB.Command
27 Set Cmd = New ADODB.Command
28 Cmd.ActiveConnection = Conn
29
30 Dim strProcessDDLStmt As String
31 strProcessDDLStmt = "" _
32 & "</Process
xmlns=""http://schemas.microsoft.com/analysisservices/2003/engine"">" _
33 & " <Type>ProcessStructure</Type>" _
34 & " <Object>" _
35 & " <DatabaseID>CheckInTestDB</DatabaseID>" _
36 & " </Object>Structure1" _
37 & " </Process>" _
38 & ""
39
40 Cmd.CommandText = strProcessDDLStmt
41 Cmd.Execute
42
命令在一个活跃连接中执行。这个活跃的连接就是第28行中的内容。一般来说,这个命令包含着执行语句。这在 CommandText 属性(第40行)中设置。当ADO为Analysis Services 2005打包OLE DB提供程序时, CommandText 属性支持DMX语句和DDL语句(就像之前所展示的一样)。命令的执行被“执行(Execute)”方法初始化(第41行)。执行经常返回一个 ADODB.Recordset 对象(可用于之前的发现(Discovery)代码段的表型服务器响应)。但是,处理操作是没有服务器响应的,它不返回成功或失败。如果出现了一个错误,ADO将报一个异常并停止正在运行的代码。因此,如果执行到了第42行,就说明执行成功了。
在之前的代码中,可以将 CommandText 属性改为一个DDL语句,比如 Alter 、 Create 或者 Dro p ;或改为一个DMX语句,如CREATE MINING MODEL或者INSERT INTO,它可以实现绝大多数挖掘任务。唯一一个需要附加补充的是查询挖掘模型。DMX查询与一般的无响应信息语句不同,因为:
· 它返回一个表型结果。
· 表型结果可能包含多级的表(嵌套表)。
· DMX 支持参数。
我们可以从返回单级表的DMX查询开始看起,使用我们最开始使用的对象来对比(命令和连接):
43 Cmd.ActiveConnection = Conn
44 Cmd.CommandText = "SELECT NODE_CAPTION FROM DecisionTree1.CONTENT" _
45 &"where NODE_TYPE=2"
46
47 Dim rs As ADODB.Recordset
48 Set rs = Cmd.Execute()
49 rs.MoveFirst
50 While Not rs.EOF
51 Debug.Print rs.Fields(0).Value
52 Wend
53 rs.Close
如我们之前所提到的一样,DMX语句由 CommandText 属性来传输。与发现(Discovery)使用相同的方式来遍历 Recordset 。第44行用到的查询只返回一列,这里并不真正需要从recordset 字段来查找列;相反的,它应该由它的索引得到(第51行)第0字段的内容。也请注意第53行中对 Recordset 的配置。当 Recordset 是活跃的时候,命令对象不能执行之后的语句。
OLE DB规范也允许返回更加复杂的结果集,如表型列或者嵌套表。下面给出一个服务器响应是嵌套表的例子,我们将使用DMX语句来添加查询更复杂的第二列NODE_DISTRIBUTION。所以新的查询如下所示:
"SELECT NODE_CAPTION, NODE_DISTRIBUTION FROM DecisionTree1.CONTENT WHERE NODE_TYPE=2"
NODE_DISTRIBUTION 是一个典型的嵌套表例子。根据数据挖掘的OLE DB规范,模型中的NODE_DISTRIBUTION列包含当前行所在节点的属性值的分布。例如,在一棵预测头发颜色的决策树中,对每一个树节点,这一列都描述有多少实例是黑发,多少实例是金发,多少实例是灰发。
执行命令在新的一列中并不改变。实际上唯一需要改变的就是 Recordset 的遍历代码,需要进行适合表的新列的改变。在代码中可以很容易的从 Recordset 作为字段值的属性返回一列的值。如果实例中的列是一个嵌套表,列值将产生一个新的 Recordset ,再遍历整个嵌套表。
所以,在51行以下应该执行如下的代码:
52 Debug.Assert( rs.Fields(1).Type = adChapter)
53 Dim nestedRS As ADODB.Recordset
54 Set nestedRS = rs.Fields(1)
55 nestedRS.MoveFirst
56 While Not nestedRS.EOF
57 Debug.Print nestedRS.Fields(0).Value
58 Wend
59 nestedRS.Close
第52行语句用来在将值写入嵌套 Recordset 前,确认列的类型是正确的。这行语句也可以用来判断制定的列是不是一个嵌套表。
应为拥有遍历嵌套表的能力,此时数据挖掘查询产生的任何返回值都可以在你的应用中被使用了。
DMX也支持查询中的参数。参数可以取代DMX查询中的任何值。例如,可以使用一个参数来代替上述查询语句中 where 子句里的NODE_TYPE 的值“2”。在数据挖掘应用中,也有少数参数非常有用的场景,比如生成一个单独的查询(关于单独查询的详细内容,请看“Adomd.NET”一节)。
想在DMX查询中将一个值变为一个参数,我们使用参数指示标志 @ 来开始替换,使用“ @ 唯一的参数名”。这样VBA代码片段中的第45行就可以变成:
45 &"where NODE_TYPE=@typeParam"
然后,在执行命令之前,我们应该插入这样的一段代码来确保能正确的使用新的参数。请注意,尽管实际数据可能与参数的值很不同,但是使用参数并不会改变服务器响应的格式。所以上述遍历 Recordset 的代码可以并不改变。
46 Cmd.NamedParameters = True
47
48 Dim typeParameter As ADODB.Parameter
49 Set typeParameter = Cmd.CreateParameter()
50 typeParameter.Direction = adParamInput
51 typeParameter.Name = "typeParam"
52 typeParameter.Value = 2
53 typeParameter.Type = adInteger
54 typeParameter.Size = 4
55
56 Cmd.Parameters.Append typeParameter
在分析服务的OLE DB提供程序中使用参数时,如下的几步非常重要:
· 命令必须使NamedParameters可用(第46行)。分析服务的OLE DB提供程序只支持命名了的参数。
· 参数的名字必须符合查询中的相应参数,但是在这里不使用 @ 前缀(第51行)。
· 可以只传输参数(第50行)。
· 参数的类型和大小必须声明(第53和54行)。
想对数据挖掘的OLE DB规则进行很好的理解,需要充分使用Microsoft Analysis Services 2005数据挖掘的特性。一旦设计好了数据挖掘查询,OLE DB就成为了一个可以执行它们、可以管理数据挖掘服务器的完整且具有通用性的API。关于在非托管C++或ADO.NET中C#使用OLEDB 的代码,请看本文附录2中的代码片段。
Analysis Management Objects – AMO
如同名字所显示的一样,AMO是一个用来管理任务的API。它非常适用于描述元数据属性的细节信息。AMO是一种非常符合微软分析服务的数据定义语言(DDL)的对象模型,在AMO中描述元数据对象。它允许迭代元数据对象、创建新对象、修改已存在对象。在AMO对象模型中,用DDL描述的每个属性都可以被检查和修改。AMO也可以用来检查和修改服务器属性,包括注册/非注册型插件算法,或者可注册/不可注册数据挖掘算法。AMO在元数据的定义和发现,以及服务器对象的训练上都非常有用。但是,它并不支持执行查询语句。
在讨论细节信息之前,我们应该先来说明一下AMO是一个托管库。所以,它可以在由通用执行时间组件(CLR——Common Language Runtime)兼容的编程语言开发的应用程序中使用,如C#、托管执行的C++、或者Visual Basic .NET。要想使用AMO, 我们需要在客户机上安装SQL Server 2005连接组件。
在使用AMO的时候,我们首先应该在应用程序的开始处引用 Microsoft.AnalysisServices.dll 库。之后,AMO对象模型就可以使用了。先来连接服务器:
Microsoft.AnalysisServices.Server server = new Server();
Server.Connect("localhost");
一旦连接成功,服务器端的元数据对象就可以被分级检查到:
Databases dbCollection = server.Databases;
foreach( Database db in dbCollection )
{
MiningStructures structCollection = db.MiningStructures;
foreach( MiningStructure struct in structCollection)
{
Console.WriteLine( struct.Name );
}
}
如果想修改已存在的元数据对象,我们只需要修改它的属性。使用如下代码:
model.Algorithm="Microsoft_Decision_Trees".
then call "Update".
model.Update();
当Update被调用时,你所做的修改就将被提交到服务器,同时刷新本地的信息集。
在服务器上添加一个新的元数据、在各自的集合上创建新成员这两个方法,与修改功能也是非常相似的:
MiningStructure myStructure;
MiningModel myModel = myStructure.Models.Add();
之后填充对象的内容:
myModel.Name = "New Model"
myModel.Algorithm = "Microsoft_Clustering"
然后通过调用 Update() 来提交对服务器端所作的修改:
myModel.Update();
当操作未能成功执行完毕时,更新操作(Update)将返回一个异常。通常产生异常的情况是:
· 被更新的属性不完整或者不一致。
· 由于当前用户未能拥有足够的权限而引起的服务器不能更新对象。
当出现异常的时候,我们可以找到问题的所在并修复它。
AMO在处理Analysis Services 2005服务器端元数据上具有很强的功能,但是它并不支持之前所提到的数据挖掘任务中的部分任务。它不提供进度通知的功能,也不提供查询挖掘模型的功能(一般情况下,它不支持DMX语句的执行)。如果你的应用需要浏览和检查Analysis Services 2005服务器,使用AMO是最好的选择。但是,如果除此以外你还需要执行语句或者显示进度通知,AMO的功能就不够了。下一章将为大家介绍两种通用API,它们支持分析服务所公开的所有特性。
进度通知:使用跟踪对象
当在服务器端同时执行多个事件时,微软分析服务就会发送一系列通知。这些事件包括用户的登入登出、 执行请求的开始位置和结束位置、不同服务器对象正在执行的进度情况。在接收到通知以后,管理员就可以检查服务器在每一刻的状态。正在处理服务器对象的用户也可以从中了解正在执行的操作是什么,以及还需要执行多长时间。
这一节中,我们将讨论应用程序是如何从Microsoft Analysis Services 2005服务器来接收进度通知的。我们从如何发现服务器发出的通知看起。 之后,我们简短的介绍应用程序如何订阅它所感兴趣的服务器通知。最后,我们给出一个需要处理进度通知的应用程序的编程模型。
在进行深入的讨论之前,我们先来明确一下,SQL Server 2005使用一个客户端分析器(Profiler)来处理这些通知。使用这个分析器,用户可以真正根据自己的需要进行通知的选择,然后检查这些通知的具体内容。分析器应用程序也允许记录服务器通知,可以为了以后检查通知内容而先将它们保存下来。它也可以使用性能计数器(Performance Counter)将正在执行的不同的性能指示器的相关服务器通知整合起来。大多数应用程序并不需要在代码中执行服务器通知,这一节针对那些需要使用数据挖掘客户端高级用户接口的开发者来进行讲解。
服务器发出的每种通知都是一个表型行。这一行包含一些基本信息,例如通知的种类、时间戳、服务器进程ID、以及服务器的名称。其它列分别对应特定的事件,例如处理通知的Progress Total、起始时间、结束时间、在服务器上已经执行的时间。服务器发出的所有通知被存放在一张虚拟表中,它为每个事件保留一行,以及被任何服务器事件支持的所有列的集合。这意味着:如果列A只被一个指定事件支持,它将在这张虚拟表中所有的事件行中出现,但是不支持A的事件的列A字段是空值。说这张表是一张虚拟表,是因为它并不存放在内存中,也不能被直接访问到。当没有人去看服务器事件进展情况的时候,它被存放在一个只有管理员可以访问到的“flight-recorder”文件中,用来提供过去出现错误的原因相关的有价值的信息。
这张虚拟表中的列集可以用常规XMLA发现语句(Discovery)来发现。这个计划的XMLA名称是DISCOVER_TRACE_COLUMNS,它的GUID是{a07ccd18-8148-11d0-87bb-00c04fc33942}。这个计划中的每一行描述事件表中的一列,计划至少有一列,使用事件的XML格式进行描述。XML格式的描述如下所示:
<COLUMN>
<ID>0</ID>
<TYPE>1</TYPE>
<NAME>EventClass</NAME>
<DESCRIPTION>Event Class is used to categorize events.</DESCRIPTION>
<FILTERABLE>false</FILTERABLE>
<REPEATABLE>false</REPEATABLE>
<REPEATEDBASE>false</REPEATEDBASE>
</COLUMN>
就这本白皮书来说,我们所感兴趣的属性有 ID 、 名字( Name )和描述( Description )。
ID 是列的数值型标志符。像我们关于事件的讨论一样,一个事件通过定义ID来指定列。列的名字和描述对于客户端来说非常重要。基于这些属性,客户端应用程序可以判断哪些列是自己所感兴趣的列,哪些列是可以忽略的。 ID 为 0 的列是“服务器通知”这张虚拟表中最重要的列,因为它是用来定义事件类型的。Microsoft Analysis Services 2005发布的所有通知都包含此列。
发现服务器发布的事件是一个与发现列很相似的任务。使用的XMLA计划是 DISCOVER_TRACE_EVENT_CATEGORIES,它的GUID是 {a07ccd19-8148-11d0-87bb-00c04fc33942}。这个任务中的每一行描述一个服务器发布的事件类别,任务记录事件类别中的全部事件。当使用XML形式定义事件类别时,任务中的代码如下所示:
<EVENTCATEGORY>
<NAME>Queries Events</NAME>
<TYPE>0</TYPE>
<DESCRITION>Collection of events for queries.</DESCRITION>
<EVENTLIST>
<EVENT>
<ID>9</ID>
<NAME>Query Begin</NAME>
<DESCRIPTION>Query begin.</DESCRIPTION>
<EVENTCOLUMNLIST>
<EVENTCOLUMN>
<ID>0</ID>
</EVENTCOLUMN>
<EVENTCOLUMN>
<ID>2<ID>
</EVENTCOLUMN>
...
</EVENTCOLUMNLIST>
</EVENT>
<EVENT>
<ID>10</ID>
<NAME>Query End</NAME>
<DESCRIPTION>Query end.</DESCRIPTION>
<EVENTCOLUMNLIST>
<EVENTCOLUMN>
<ID>0</ID>
</EVENTCOLUMN>
<EVENTCOLUMN>
<ID>2</ID>
</EVENTCOLUMN>
...
</EVENTCOLUMNLIST>
</EVENT>
....
</EVENTLIST>
</EVENTCATEGORY>
所以,一个事件类别可以包含多个带不同ID的事件。如之前所说的一样,每个事件拥有它们自己的列,并且它们都包含提供事件类信息的列0。
另一个特殊的列是列1,事件子类(event subclass)。它被多个事件共享。事件子类这一列允许跟踪用户,例如,我们可以用它来区一个 ProgressStart 事件到底是来自于数据挖掘,还是OLAP维度处理。如果一个事件中出现了列1,这一列要比其它列的定义复杂一些。如下文所示:
<EVENTCOLUMN>
<ID>1</ID>
<EVENTCOLUMNSUBCLASSLIST>
<EVENTCOLUMNSUBCLASS>
<ID>1</ID>
<NAME>Process</NAME>
</EVENTCOLUMNSUBCLASS>
<EVENTCOLUMNSUBCLASS>
<ID>2</ID>
<NAME>Merge</NAME>
</EVENTCOLUMNSUBCLASS>
...
</EVENTCOLUMNSUBCLASSLIST>
</EVENTCOLUMN>
这个更加复杂的定义描述了当前事件中列1可能出现的所有值的含义。
当一个应用程序决定了它感兴趣的事件或者事件列是哪些的时候,它可以订阅这些信息作为服务器通知。这个订阅功能在服务器创建跟踪对象的时候被创建。跟踪对象的功能与包含服务器通知的虚拟表的视图的功能相似。除此功能以外,跟踪对象存有服务器对象的所有属性。它可以被创建、修改、删除以及根据许可情况进行约束。一个跟踪声明会指定它感兴趣的事件(类似于关系型视图中的WHERE子句)以及事件将返回哪些列。定义跟踪的DDL可以包含更多的过滤条件,如“只返回那些列C是特定值的返回值”,但是这些过滤条件并不是本文要讨论的内容。这些高级选项可以从SQL Server 2005 在线文档中进行了解,在文档中有专门一节“跟踪要素(分析服务脚本语言)”。
让我们来考虑这样的一个应用程序,它用来训练挖掘模型,而且只订阅了如下进度报告事件:
· Progress Report Begin (事件ID是5)
· Progress Report Current (事件ID是7)
· Progress Report End (事件ID是6)
· Progress Report Error(事件ID是8)
对每一个事件来说,感兴趣的列是:
· 列 0, EventClass 。
· 列9, ProgressTotal ,完成当前任务所需要执行的步骤数(此列仅在Progress Report Current事件可用)。
· 列10, IntegerData ,数据挖掘进度通知中的属性,存储正在执行的任务的当前步骤(此列仅在Progress Report Current事件可用)。
· 列42, TextData ,包含当前步骤的详细描述。
我们使用下面的DDL语句创建这个跟踪:
<Create
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">
<ObjectDefinition>
<Trace>
<ID>DemoTrace</ID>
<Name>DemoTrace</Name>
<Events>
<Event>
<EventID>5</EventID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<Event ID>6</Event ID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<EventID>7</EventID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>9</ColumnID>
<ColumnID>10</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<EventID>8</EventID>
<Columns>
<Columns>0</Columns>
<Columns>42</Columns>
</Columns>
</Event>
</Events>
</Trace>
</ObjectDefinition>
</Create>
一旦跟踪被创建,客户端应用程序就将订阅这个跟踪。订阅跟踪的功能与执行返回表型
时间: 2005年3月
适用于:
微软 SQL Server 2005
SQL Server 数据挖掘(SQL Server Data Mining)
摘要: 介绍SQL Server 2005数据挖掘的新API以及几种常用的开发场景。
版权
在这篇文章中所包含的信息代表了从发布日起微软对所讨论的问题的当前观点。因为微软必须对市场的变换做出响应,它不应该被理解为微软所必须承担的任务的一部分,微软也不能保证在发布日之后所提出的信息的精确性。
这个白皮书仅仅是为了信息的目的,微软对本文中的信息不做任何授权、表示、暗含或规定。
依从所有可适用的版权法是用户的责任。没有限制权利在版权之下,这个文档的部分不允许被再生产,存放或介绍入检索系统, 或被以任何形式传送或通过任何手段(电子, 机械, 影印, 记录, 或其他) 或为任何目的,没有微软的明确书面允许。
微软对于在这篇文章中所包含的主题拥有专利、专利申请、商标、版权或其他的一些知识产权。除了微软明确提供的一些书面的特许契约,这个文档的并不提供给您任何专利、商标、版权或其他知识产权的执照。
版权所有2005 Microsoft Corporation。
Microsoft 和Visual Studio在美国或其他国家都有注册商标或微软的商标。
在这里的实际的公司和产品的名字可能是他们各自的商标。
QUOTE:
目录
概述
与 Microsoft Analysis Services 2005通讯
数据定义语言(DDL) 和 数据挖掘扩展语言(DMX)
数据挖掘任务
通用API
Adomd.NET 作为通用API
OLE DB作为通用API
Analysis Management Objects – AMO
进度通知:使用跟踪对象
无服务器的数据挖掘:本地挖掘模型
扩展SQL Server 数据挖掘功能
使用Adomd.NET Server 扩展DMX
插件算法和内容查看器
应用场景建议
应用场景1:简单的数据挖掘预测
应用场景2:Web应用——使用服务器上现有模型的规则
应用场景3:为当前数据在服务器上创建和训练一个新的模型
小结
附录 1:Microsoft Analysis Services 2005服务器上的常用操作以及请求的协议格式
附录 2:在Ado.NET 和 C++中使用 OLE DB
非托管 C++
ADO.NET
概述
概述
与 Microsoft Analysis Services 2005通讯
数据定义语言(DDL) 和 数据挖掘扩展语言(DMX)
数据挖掘任务
通用API
Adomd.NET 作为通用API
OLE DB作为通用API
Analysis Management Objects – AMO
进度通知:使用跟踪对象
无服务器的数据挖掘:本地挖掘模型
扩展SQL Server 数据挖掘功能
使用Adomd.NET Server 扩展DMX
插件算法和内容查看器
应用场景建议
应用场景1:简单的数据挖掘预测
应用场景2:Web应用——使用服务器上现有模型的规则
应用场景3:为当前数据在服务器上创建和训练一个新的模型
小结
附录 1:Microsoft Analysis Services 2005服务器上的常用操作以及请求的协议格式
附录 2:在Ado.NET 和 C++中使用 OLE DB
非托管 C++
ADO.NET
随着微软SQL Server 2005的诞生,统计技术和机器学习算法的综合产物,也就是众所周知的数据挖掘,被带入了一个新的阶段。在SQL Server 2005中,数据挖掘最重要的转变是改变了它的目标用户。除了作为一个科学的实验工具,面向有限的专业人士,如今SQL Server 数据挖掘已广泛存在,成为开发者捶手可得的工具,并且已经做好了在更广阔的领域中应用的准备。从电子数据表格到网络游戏,从点到点通讯系统到应用服务器,绝大多数应用都有这样一个共同点:它们不得不进行数据处理。在进行数据处理的时候,它们使用特定的标准API来访问数据。在SQL Server 2005数据挖掘的数据处理系统中,这些API也同样可以被智能的嵌入到应用中。
这篇文章带你思考将SQL Server数据挖掘嵌入到应用中的契机。文章重点关注可编程内容,即通过写代码来使用数据挖掘技术和增强服务器特性。我们将给出一系列可以被数据挖掘引擎执行的常用任务,并针对它们展示微软SQL Server数据挖掘体系结构的解决方案。之后,我们将列举一些客户端产品(Adomd.NET 和 OLE DB)的可编程API。之后的一个章节专注于Analysis Management Objects所管理的API。随后,我们将展示服务器创建新的存储过程以及添加新的算法插件和查看器等扩展功能.
数据挖掘应用也可以结合联机分析处理(OLAP)、Reporting Services或者Integration Services来创建。然而,这篇文章不介绍这些内容,而是严格通过代码来介绍数据挖掘功能和如何增强数据挖掘功能。
数据挖掘和联机分析处理都是微软分析服务的组件。本篇文章中介绍的客户端API同时适用于这两种组件。但是,本文的介绍仅针对数据挖掘。其中的场景、代码实例、元数据对象都是针对数据挖掘的。
与 Microsoft Analysis Services 2005 通讯
让我们从Microsoft Analysis Services 2005(与数据挖掘服务器之间)的通讯协议开始。客户端通过Analysis Services 2005来执行这个通讯协议(比如使用Microsoft OLE DB Provider for Analysis Services 9.0 或者 Adomd.NET),并且这个协议也必须被其它客户端执行。
Microsoft Analysis Services 2005 使用SOAP作为最外层的通讯层。(更多关于SOAP的内容请访问这个网页。)SOAP为应用程序定义了一系列可以通过XML消息来调用的方法。 这些方法由Microsoft Analysis Services 发布,使用XML for Analysis或者 XMLA来定义。
XMLA规范是由一个超过20家研究商业智能的龙头企业(包括微软公司、Hyperion和SAS 学会)组成的组织提出的,它是一个标准的OLAP和数据挖掘技术接口。 更多关于XMLA的信息,请点击这里。
XMLA定义了两种发送给服务器的请求,以及服务器进行响应返回的信息的格式。请求的类型是“发现(Discover)”和“执行(Execute)”。“发现”用来从服务器获取信息和元数据。例如, “发现”可以用来获取服务器上一系列挖掘模型以及它们的属性(列描述、算法等等)。“执行”用来执行对服务器的命令,如创建一个新的目录或者挖掘模型、训练一个模型、或者执行一个查询。
数据定义语言( DDL) 和 数据挖掘扩展语言(DMX)
XMLA的“执行”命令可应用于多种任务。这里有几个例子:
· 创建(Create)命令:这些命令在服务器上创建一个新的元数据对象,它们包含被创建的对象的全部或部分属性,例如名称、数据绑定、挖掘模型和挖掘结构中的列、挖掘模型的数据挖掘算法等等。
· 修改(Alter)命令:这些命令修改已存在的服务器元数据对象的属性。
· 删除(Drop)命令:这些命令用来从服务器上去掉元数据对象。
· 处理(Process)命令:这些命令用来初始化那些基于当前绑定的训练数据集定义的元数据对象上的训练序列。
· 语句 (查询语句)。
当一个XMLA“执行”请求描述一个对象(如创建Create或者修改Alter语句)或者将一个对象定义为一个动作的目标(如处理Process或删除Drop)时,命令的内容由Microsoft Analysis Services 数据定义语言(Data Definition Language —— DDL)组成。DDL是Analysis Services 2005中元数据以及元数据操作的内部表示方法。 服务器上的对象存储在DDL中,商业智能化项目由若干DDL片段组成。关于DDL的更多细节,请查看SQL Server 2005 在线文档中的“分析服务脚本语言(Analysis Services scripting language)”。
另一方面,在数据挖掘任务中,当XMLA请求是一个语句的时候,XMLA “执行”请求使用一种查询语言——DMX(数据挖掘扩展Data Mining eXtensions语言)作为它的请求的内容。DMX语言在针对数据挖掘的OLE DB 规范中定义,在这里可以使用。
Microsoft Analysis Service 2005 也可以使用另一种查询语言来执行语句——MDX。MDX语言是为OLAP组件所设计的。所以,这里我们只关注DMX。
区分DDL和DMX是非常重要的:DDL是一种由Analysis Services 2005使用的类XML语言,用来描述、管理和指定元数据。DDL可以很方便的扩展到XMLA。
而DMX是一种为数据挖掘而设计出的类SQL语言。DMX与SQL非常类似,DMX包含这样的结构,它们允许创建和操作元数据对象(想想SQL中的CREATE TABLE 或者INSERT INTO语句,DMX中有与其等价的CREATE MINING MODEL 和INSERT INTO 语句)。然而,对于管理元数据对象的任务来说,DMX的灵活性比DDL要差。DMX语句无法扩展到XMLA;但是它们可以被固定的XMLA结构所包括。
文章结尾处的附录1提供更多Microsoft Analysis Services 2005协议部署的细节内容。
SOAP相对来说比较容易操作;大多数开发工具都提供针对创建、传输、接收SOAP包的帮助。但是,选择使用DDL请求还是DMX请求,并把它按照适当的格式封装到XMLA语句中就不是一件那么容易的事情了。所以开发者需要比仅仅使用XML流作为通讯方法更好的工具。这也就是为什么如今可编程API存在的原因。这些API将XMLA请求的相关操作作业打包,分析XMLA的响应信息,并且向开发者提供一个更具逻辑性的通讯视图,用来操作内部细节。也有一小部分API可以被Microsoft SQL Server 数据挖掘应用。选择哪个API取决于客户端执行的请求的类型和客户端的开发环境。
下一节将分析典型的数据挖掘在客户端/服务器端通讯(C/S)时的客户端请求。之后的章节将从各种数据挖掘可编程API处理典型请求时的方法以及它们支持的客户端环境的角度,具体展示这些API以及它们之间的差别。
数据挖掘任务
SQL Server数据挖掘服务器支持多种请求。对于每一种请求,我们将给出可用的DDL命令和等价的DMX:
· 元数据的发现:这些请求允许客户端应用根据一些属性,如挖掘模型的列、使用的算法、被训练的数据集,迭代服务器上已存在的元数据对象,并且从中选择一个或多个有用的元数据。XMLA规范为这类请求定义了发现(Discover)命令,没有与其直接对应的DMX或DDL。
· 元数据的定义:这些请求是一系列对服务器上的数据结构的定义。这些数据结构是挖掘结构和挖掘模型,它们由目录(数据库)组合在一起。针对这些请求的XMLA命令是执行(Execute),包括DDL用来创建和修改的Create 或 Alter 语句。也可以使用DMX的 CREATE语句,尽管它的灵活性要比DDL 的Create语句差。
· 模型的训练:这些请求为服务器端的数据挖掘模型执行训练处理。训练可以使用预先绑定的数据(在元数据定义时决定),也可以只描述当前正在处理的操作的数据集。XMLA命令还是 执行(Execute),包含一个DDL的处理(Process)语句。在DMX中,训练可以由插入(INSERT INTO)命令得到。
· 查询模型:这些请求包括(但不局限于)在数据挖掘中我们常说的记分(Scoring)和预测(Predicting)。 我们将查询定义为使用数据挖掘所建立的模型的过程。这些请求由发送到服务器端的DMX语句组成。
· 订阅进度通知:这些请求非常方便地显示一个进度条,这个进度条用来显示在执行一个很长的操作时或者在指定时间检查服务器状态时的实际进展情况。这类请求不能使用DMX创建。它们拥有跟踪的功能,作为带DDL订阅(Subscribe)语句的XMLA执行(Execute)命令来进行传输。
对这些任务有了基本概念后,我们可以正式开始列举可编程API及它们的特性了。上述任务中的最后一项,关于进度的通知,我们将单立一节的内容进行讲解,下面的API章节就不再讨论这个任务了。
通用API
我们将探讨两种常用的API:Adomd.NET和OLE DB。它们的差别在于它们的目标环境不同: OLEDB (OLE for Databases)主要针对非托管应用(尽管它也可以被用于托管应用);而Adomd.NET针对托管应用。下边我们将看到,这些API具有非常相似的结构。它们都基于非常有名的数据库访问范例。
Adomd.NET 作为通用API
Adomd.NET是由Microsoft Analysis Services 2000提供的旧ADOMD库的托管版本。这个库专门为Microsoft Analysis Services 2005的客户端而设计。它执行ADO.NET数据访问范例(包括一系列标准接口,如 IDbConnection、IDbCommand、 IDataReader 等等),并且使用Microsoft Analysis Services 2005提供的许多特性来扩展这些范例。
在.NET框架中, System.Data 命名空间使你可以建立从多个数据源有效管理数据的组件。关于此点的更多内容请参考关于 System.Data 命名空间的MSDN文档。 System.Data 拥有多种特性,它定义一系列可以被.NET数据提供程序执行的用来访问关系型数据库的接口。微软分析服务(Microsoft Analysis Services)是一个多维数据库,它比普通关系型数据库拥有更强大的功能。Adomd.NET是一个.NET数据提供程序,能执行提供给.NET数据提供程序的一系列标准 System.Data 接口,这些接口的功能在Analysis Services 2005中得以增强,也增加了很多在关系型数据库中不使用的新特性。
Adomd.NET作为SQL Server 2005连接组件的一部份被安装,也可以单独下载进行安装。在从应用程序使用它之前,必须在机器上安装Adomd.NET数据提供程序。
这一节的代码示例使用Visual Studio 2005的C# 2.0实现。经过一个简单的“翻译”过程,它们也可以被Visual Studio 套件的任意托管语言(如Visual Basic .NET或Visual C++ .NET)运转。
在应用程序中使用 Adomd.NET时,必须先添加一个 Microsoft.AnalysisServices.AdomdClient. dll程序集,使用类似如下的代码进行添加:
using Microsoft.AnalysisServices.AdomdClient;
下一步,连接Microsoft Analysis Services 2005 服务器:
AdomdConnectionconn = new AdomdConnection();
conn.ConnectionString = "Data Source=localhost; " +
"Initial Catalog=MyCatalog";
conn.Open();
在数据挖掘任务列表中,第一个是元数据对象的发现。就像我们前边所说的一样,元数据的发现由XMLA发现(Discover)命令实现。Adomd.NET提供两种简单的方法来发现元数据。第一种与AMO非常相似:
foreach (MiningModel model in conn.MiningModels)
{
Console.WriteLine(model.Name);
}
微软分析服务开发团队尽了很大的努力来确认常用的计划都已包含于Adomd.NET Connection类所发布的程序集中。你可以使用之前的这些代码来访问数据库中的挖掘结构集、一个结构中或者整个数据库中的挖掘模型列表、以及模型和结构中的列。Adomd.NET 拥有远超过AMO 的功能,它允许代码这样构成分级模型:
foreach (MiningContentNode node in model.Content)
{
foreach( MiningContentNode in node.Children )
{
// 使用节点的属性
}
}
对Microsoft Analysis Services 2005中的OLAP计划来说,Adomd.NET Connection 对象所发布的程序集比数据挖掘所提供的程序集更加适用。所以在Adomd.NET中你可以使用相同的方法来浏览立方体和维度。
发现服务器元数据的第二种方法与OLE DB的方法非常相似,也就是执行一个发现(Discovery)命令来传输一个GUID计划和一系列约束,然后返回一个可以被遍历的表型结果。 有些计划返回的是分级表型结果(嵌套表)。这也就是为什么在Adomd.NET 中,一个发现操作的返回值是一个 数据集 (DataSet ) ;对比ADO.NET ,它返回的是一个数据表。数据集可以描述表之间的关系,所以数据集可以包含一些发现操作的嵌套表型结果。下边的一段代码片段发现了一个挖掘模型的内容,并且使用数据集得到了响应NODE_DISTRIBUTION嵌套表计划的嵌套行:
Guid modelContent = new Guid("{3ADD8A76-D8B9-11D2-8D2A-00E029154FDE}");
object[] arRestrictions = new object[3];
// 约束发现(Discovery)MyCatalog目录中DecisionTree1模型的内容。
// 第二个约束(MODEL_SCHEMA) 在这里忽略。
arRestrictions[0] = "MyCatalog";
arRestrictions[1] = null;
arRestrictions[2] = "DecisionTree1";
DataSet dsContent = conn.GetSchemaDataSet(
modelContent, arRestrictions);
// 一致性检查:确认关系值为1
Debug.Assert( dsContent.Relations.Count == 1);
DataRelation relation = dsContent.Relations[0];
DataTable topTable = relation.ParentTable;
foreach (DataRow row in topTable.Rows)
{
// 使用最上层表中的列
Console.WriteLine("NODE_CAPTION=" + row["NODE_CAPTION"]);
Console.WriteLine("NODE_UNIQUE_NAME" + row["NODE_UNIQUE_NAME"]);
// 根据关系描述,取得嵌套行
DataRow[]distRows = row.GetChildRows(relation);
foreach (DataRow distRow in distRows)
{
// 使用嵌套表中的列
Console.WriteLine(distRow["ATTRIBUTE_VALUE"]);
}
}
与OLE DB非常相似,Adomd.NET提供发送请求到服务器的命令。这些请求可以是DDL或者DMX的;所以它们可以创建或者修改已经存在的、用来训练挖掘结构和挖掘模型的元数据对象(DDL和DMX),也可以查询已存在的模型(只支持DMX)。我们也就可以通过此点来区分元数据的创建、处理,和DMX的查询。它们的区别在于:DMX查询返回一个表型结果(分层的或者单层的),而元数据创建和处理语句只返回一个成功或者失败。Adomd.NET公开了一些执行(Execute)方法,其中两种对于返回成功/失败的请求和返回表格型数据的请求非常有用。
第一种:我们使用一个DDL处理语句作为示例,任何其它的DDL语句(如Alter、Create或者Drop)也可以使用相同的代码。
AdomdCommand cmd = new AdomdCommand();
cmd.Connection = conn;
cmd.CommandText = "
"xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">"+"<Type>ProcessDefault</Type>" +
" <Object>" +
" <DatabaseID>MyCatalog</DatabaseID>" +
" <MiningStructureID>Structure1</MiningStructureID>" +
" </Object>" +
"</Process>";
cmd.ExecuteNonQuery();
同样, ExecuteNonQuery 也可以执行一个DMX语句来产生相同的结果:
"INSERT INTO MINING STRUCTURE Structure1"
当 ExecuteNonQuery 被调用的时候,如果请求执行成功了,语句将返回;如果执行失败将报一个异常。在之后的例子中,将给出异常的具体信息,如服务器返回的错误信息。
第二种执行方法是 ExecuteReader 。这种方法应该在语句的返回值肯定是表型的时候被调用。就像我们前边所提到的一样,Microsoft Analysis Services 2005返回的结果有时会是分层表型结果。例如,让我们考虑这样的一个模型, Model1,它根据消费者的年龄、他/她汽车的颜色来预测消费者的性别和购买商品的清单。当然,这样的模型可能并没有现实意义,但是,它却是一个很容易使DMX语句返回分层表结构结果的例子。
下面的代码使用 AdomdCommand 来传输一个预测查询给服务器,并读取最上层返回值(预测的性别)和嵌套返回值(预测的商品列表):
cmd.CommandText = "SELECT Gender, Products FROM Model2 " +
"NATURAL PREDICTION JOIN "+
"( SELECT 30 AS Age, 'Black' as CarColor) AS T";
AdomdDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
// 使用上层结果,预测性别
Console.WriteLine( rdr.GetString(0) );
// 为第一列的嵌套内容获得一个nested reader
AdomdDataReader nestedReader = rdr.GetDataReader(1);
// 读嵌套内容并使用嵌套数据
while (nestedReader.Read())
{
Console.WriteLine(nestedReader.GetString(0));
}
nestedReader.Close();
}
调用 GetDataReader 将返回一个新的实例 AdomdDatareader 类,它被初始化后用来访问对列编号了的嵌套表。如果指定的列并不是一个被嵌套的表,“执行”方法将返回一个异常。我们可以使用类似如下代码的语言来判断Datareader中的列是不是一个嵌套表:
if (rdr.GetFieldType(1) == typeof(AdomdDataReader) )
{
// 如果进入If循环,rdr的第一列是一个嵌套表
}
在现实生活中,最有可能根据用户的实际输入来进行预测。一个常见的Web应用场景是这样的,用户给出年龄和汽车的颜色,应用程序代码产生一个DMX请求来预测该客户购买商品的清单。当开发者对DMX和相关的数据类型有一个很好的理解的时候,查询可以使用将客户录入的所有字符串连接起来的方式进行创建。 然而,这样的方法具有潜在的威胁,它可能引起DMX嵌入错误或研发错误。一种更好的方式是使用参数来建立查询,将用户输入的内容作为参数的值。Adomd.NET对DMX的参数化查询提供了大量的支持,就像下面的例子一样。这段代码不包括读取返回值的内容,因为它与之前的代码片段是一样的。
cmd.CommandText = "SELECT Gender, Products FROM Model2 " +
"NATURAL PREDICTION JOIN "+
"( SELECT @Age AS Age, @Color as CarColor) AS T";
AdomdParameter paramAge, paramColor;
paramAge = cmd.CreateParameter();
paramAge.Direction = ParameterDirection.Input;
paramAge.ParameterName = "Age";
cmd.Parameters.Add(paramAge);
paramColor = cmd.CreateParameter();
paramColor.Direction = ParameterDirection.Input;
paramColor.ParameterName = "Color";
cmd.Parameters.Add(paramColor);
cmd.Parameters["Age"].Value = 30; // 用户在这里输入
cmd.Parameters["Color"].Value = "Black"; // 用户在这里输入
AdomdDataReader rdr = cmd.ExecuteReader();
请注意,参数不一定非是数值。请考虑这样的DMX语句:
INSERT INTO MyModel(Col1, Col2)
OPENQUERY(DataSource, "SELECT ColA, ColB FROM Table") AS T
或者是:
SELECT PREDICT(Products, 5) FROM MyModel NATURAL PREDICTION JOIN
OPENQUERY(DataSource, "SELECT ColA, ColB FROM Table") AS T
这两个语句都用了一个OPENQUERY 函数来描述执行时被服务器使用的表型内容(训练挖据模型,分别进行预测)。使用Adomd.NET,我们可以使用一个参数来取代OPENQUERY函数,并且向服务器传输一些表型内容。查询可能是这样的:
INSERT INTO MyModel(Col1, Col2)
@MyTabularContent AS T
或者是:
SELECT PREDICT(Products, 5) FROM MyModel NATURAL PREDICTION JOIN
@MyTabularContent AS T
在这些例子中, 参数 MyTabularContent 可以是一个 数据表(DataTable ) 或者执行一个 IDataReader .NET接口。相比来说,数据表更容易使用, IDataReader 接口具有不需要将所有数据保存在内存中的优势。 IDataReader 执行的一个例子是客户端应用执行的SQL查询所返回的 SqlDatareader 。当然,一个SQL查询请求也可以在OPENQUERY 功能中被提交,但是这种请求的前提是服务器已经访问到了SQL数据库。表型参数为两种情况所设计:
· 数据库中的数据是客户端可见但是服务器端不可见的(这种情况应该使用 IDataReader )
· 数据在客户端应用程序所占用的内存中( DataTable 可以在这种情况时使用)
Adomd.NET 一个独有的特点是可以使用XML返回选定的列。Microsoft Analysis Services 2005为指定的查询返回这样的列。例如:
SELECT * FROM MyModel.PMML
这个语句将返回PMML 2.1格式下MyModel 模型的内容(即被支持PMML的MyModel使用的数据挖掘算法)。除了例如模型名称、PMML缓冲区大小这类元信息外,这个语句的返回值还包括指定的列和包含PMML的MODEL_PMML(一种被数据挖掘团队设计出来的XML格式,用来描述挖掘模型的内容)。
这个XML的内容可以以字符串方式被访问,但是Adomd.NET拥有分析XML列的能力(基于服务器端发来的指定的列类型来判断) 并且将它们发布为一个 System.Xml.XmlReader 对象。这些列也可以作为字符串被读取。以下的示例代码使用这一特性来访问带XML目录的列,同时使用字符串和 XmlReader 两种方法。
cmd.CommandText = "SELECT * from [MyModel].PMML";
AdomdDataReader rdr = cmd.ExecuteReader();
// 遍历响应结果,读取第5列,MODEL_PMML
while (rdr.Read())
{
// 取得列值
object objXMLValue = rdr.GetValue(5);
if (objXMLValue is System.Xml.XmlReader)
{
//使用一个XML reader
System.Xml.XmlReader pmmlReader =
(System.Xml.XmlReader)objXMLValue;
//在这里读PMML
}
// 使用字符串来获取这列
string strPMMLAsString = rdr.GetString(5);
}
Adomd.NET 的另一个特性是连续访问服务器响应,将在 进度通知:使用跟踪对象 一节中具体阐述。
Adomd.NET是Microsoft Analysis Services 2005中最具灵活性,最容易使用的客户端API。在编写以微软分析服务为目标的.NET应用操作时也同样推荐使用它。它提供了类AMO访问服务器元数据的大量特性,它允许执行DDL和DMX语句,并且它对DMX语句的参数也有很好的支持。
OLE DB作为通用API
在微软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定义了一个可以被对话执行的 IDBSchemaRowset 接口。这里我们需要注意的是,ADO和ADO.NET有一个封装了数据源和OLE DB对话的连接对象(Connection)。这两种标准的OLE DE对象(数据源和OLE DB对话)公开的功能在ADO和ADO.NET的连接对象中可用。
所有的OLE DB对象(数据源、对话、命令和响应)经常在COM组件中执行来调用OLE提供程序。
下面的图1给出了一个OLE DB解决方案的框架:
图 1. OLE DB解决方案框架图
如图中所示,首先,各个客户端上安装的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连接字符串的例子:
"Provider=MSOLAP; Data Source=localhost; "
第一个属性 Provider 描述示例中指定的提供程序。
"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版本上进行测试的:
1 Dim Conn As ADODB.Connection
2
3 Set Conn = New ADODB.Connection
4 Conn.Open ("Provider=MSOLAP.3; Data Source=localhost;" _
5 & "Initial Catalog=MyCatalog")
在第一行和第三行创建并初始化了一个ADODB连接对象。在第四行,就像我们前边所说的,ADO连接对象封装了两种OLE DB对象:数据源和对话。在连接字符串中,你将看到一个之前没有讨论过的属性:“Initial Catalog”。它定义服务器上将被这个连接使用的数据库。让我们使用这个连接对象来完成我们之前列举的数据挖掘任务。
对于元数据发现(Discovery),ADO连接提供了一个 OpenSchema 函数(在OLE DB对话中打包了 IDBSchemaRowset 接口)。
OpenSchema 包含3个参数:
· 枚举,用来描述将要被发现的计划。
· 约束集,将被应用于发现操作的一系列约束。
· 全局唯一标识符(GUID),描述提供程序指定的计划。
我们尝试在MyCatalog 数据库上发现服务器端的挖掘模型。这不是数据挖掘模型计划(指定的提供程序计划)中预先计划好的枚举,所以第一个参数就是 adSchemaProviderSpecific 。第二个参数,约束集,包含用来查找模型(“MyCatalog”)的目录名。第三个参数包含Analysis Services OLE DB提供程序中,能识别挖掘模型计划的GUID的字符表。
6 Const DMSCHEMA_MINING_MODELS="{3add8a77-d8b9-11d2-8d2a-00e029154fde}"
7 Dim Restrictions()
8 Restrictions = Array("MyCatalog")
9 Dim rsSchema As ADODB.Recordset
10 Set rsSchema = Conn.OpenSchema(
adSchemaProviderSpecific,
Restrictions,
DMSCHEMA_MINING_MODELS)
数据挖掘的OLE DB规范包含分析服务的OLE DB提供程序支持的计划的完整定义,包括发现(Discovery)语句返回的列和约束。
OpenSchema 返回一个 ADODB.Recordset 对象。 Recordset 对象封装了一个表型服务器响应。下面我们将看到如何遍历这个对象以及如何从中提取信息。这段代码的目的是枚举挖掘模型的名字。 像我们所知道的一样,在数据挖掘OLE DB里,挖掘模型计划中的每一行对应一种挖掘模型,并且包含一个“MODEL_NAME”列,列中存储挖掘模型的名字。
下面一段代码显示如何从 Recordset 对象中查找指定的列,以及如何从这些列中提取信息。
11 ' 从(MODEL_NAME)中查找列
12 Dim iModelNameColumn As Integer
13 For iModelNameColumn = 0 To rsSchema.Fields.Count - 1
14 If rsSchema.Fields(iModelNameColumn).Name = "MODEL_NAME" Then
15 GoTo Found
16 End If
17 Next
18 Error (1)
19 Found:
20 ' 读取Recordset的返回值
21 rsSchema.MoveFirst
22 While Not rsSchema.EOF
23 Debug.Print rsSchema.Fields(iModelNameColumn).Value
24 rsSchema.MoveNext
25 Wend
如你所看到的一样,这段代码先遍历了 Recordset 对象的所有字段。每个字段表示响应的一列。我们根据这些字段的索引MODEL_NAME进行查找。如果找到了这样的一列,就开始遍历它的行内容,否则就报错。
为了遍历行, Recordset 指针先移到数据的开始位置。之后一行一行的读取行数据。对于每一行都读取和使用MODEL_NAME字段的值。
一些数据挖掘任务(如创建新元数据对象或训练已存在的对象)可以通过发送DDL语句到服务器来执行。让我们看看DDL语句是如何被OLE DB通过ADO来传输的。我们将使用与之前一样的连接对象,并介绍一个新的OLE DB对象的ADO包, ADODB.Command 对象:
26 Dim Cmd As ADODB.Command
27 Set Cmd = New ADODB.Command
28 Cmd.ActiveConnection = Conn
29
30 Dim strProcessDDLStmt As String
31 strProcessDDLStmt = "" _
32 & "</Process
xmlns=""http://schemas.microsoft.com/analysisservices/2003/engine"">" _
33 & " <Type>ProcessStructure</Type>" _
34 & " <Object>" _
35 & " <DatabaseID>CheckInTestDB</DatabaseID>" _
36 & " </Object>Structure1" _
37 & " </Process>" _
38 & ""
39
40 Cmd.CommandText = strProcessDDLStmt
41 Cmd.Execute
42
命令在一个活跃连接中执行。这个活跃的连接就是第28行中的内容。一般来说,这个命令包含着执行语句。这在 CommandText 属性(第40行)中设置。当ADO为Analysis Services 2005打包OLE DB提供程序时, CommandText 属性支持DMX语句和DDL语句(就像之前所展示的一样)。命令的执行被“执行(Execute)”方法初始化(第41行)。执行经常返回一个 ADODB.Recordset 对象(可用于之前的发现(Discovery)代码段的表型服务器响应)。但是,处理操作是没有服务器响应的,它不返回成功或失败。如果出现了一个错误,ADO将报一个异常并停止正在运行的代码。因此,如果执行到了第42行,就说明执行成功了。
在之前的代码中,可以将 CommandText 属性改为一个DDL语句,比如 Alter 、 Create 或者 Dro p ;或改为一个DMX语句,如CREATE MINING MODEL或者INSERT INTO,它可以实现绝大多数挖掘任务。唯一一个需要附加补充的是查询挖掘模型。DMX查询与一般的无响应信息语句不同,因为:
· 它返回一个表型结果。
· 表型结果可能包含多级的表(嵌套表)。
· DMX 支持参数。
我们可以从返回单级表的DMX查询开始看起,使用我们最开始使用的对象来对比(命令和连接):
43 Cmd.ActiveConnection = Conn
44 Cmd.CommandText = "SELECT NODE_CAPTION FROM DecisionTree1.CONTENT" _
45 &"where NODE_TYPE=2"
46
47 Dim rs As ADODB.Recordset
48 Set rs = Cmd.Execute()
49 rs.MoveFirst
50 While Not rs.EOF
51 Debug.Print rs.Fields(0).Value
52 Wend
53 rs.Close
如我们之前所提到的一样,DMX语句由 CommandText 属性来传输。与发现(Discovery)使用相同的方式来遍历 Recordset 。第44行用到的查询只返回一列,这里并不真正需要从recordset 字段来查找列;相反的,它应该由它的索引得到(第51行)第0字段的内容。也请注意第53行中对 Recordset 的配置。当 Recordset 是活跃的时候,命令对象不能执行之后的语句。
OLE DB规范也允许返回更加复杂的结果集,如表型列或者嵌套表。下面给出一个服务器响应是嵌套表的例子,我们将使用DMX语句来添加查询更复杂的第二列NODE_DISTRIBUTION。所以新的查询如下所示:
"SELECT NODE_CAPTION, NODE_DISTRIBUTION FROM DecisionTree1.CONTENT WHERE NODE_TYPE=2"
NODE_DISTRIBUTION 是一个典型的嵌套表例子。根据数据挖掘的OLE DB规范,模型中的NODE_DISTRIBUTION列包含当前行所在节点的属性值的分布。例如,在一棵预测头发颜色的决策树中,对每一个树节点,这一列都描述有多少实例是黑发,多少实例是金发,多少实例是灰发。
执行命令在新的一列中并不改变。实际上唯一需要改变的就是 Recordset 的遍历代码,需要进行适合表的新列的改变。在代码中可以很容易的从 Recordset 作为字段值的属性返回一列的值。如果实例中的列是一个嵌套表,列值将产生一个新的 Recordset ,再遍历整个嵌套表。
所以,在51行以下应该执行如下的代码:
52 Debug.Assert( rs.Fields(1).Type = adChapter)
53 Dim nestedRS As ADODB.Recordset
54 Set nestedRS = rs.Fields(1)
55 nestedRS.MoveFirst
56 While Not nestedRS.EOF
57 Debug.Print nestedRS.Fields(0).Value
58 Wend
59 nestedRS.Close
第52行语句用来在将值写入嵌套 Recordset 前,确认列的类型是正确的。这行语句也可以用来判断制定的列是不是一个嵌套表。
应为拥有遍历嵌套表的能力,此时数据挖掘查询产生的任何返回值都可以在你的应用中被使用了。
DMX也支持查询中的参数。参数可以取代DMX查询中的任何值。例如,可以使用一个参数来代替上述查询语句中 where 子句里的NODE_TYPE 的值“2”。在数据挖掘应用中,也有少数参数非常有用的场景,比如生成一个单独的查询(关于单独查询的详细内容,请看“Adomd.NET”一节)。
想在DMX查询中将一个值变为一个参数,我们使用参数指示标志 @ 来开始替换,使用“ @ 唯一的参数名”。这样VBA代码片段中的第45行就可以变成:
45 &"where NODE_TYPE=@typeParam"
然后,在执行命令之前,我们应该插入这样的一段代码来确保能正确的使用新的参数。请注意,尽管实际数据可能与参数的值很不同,但是使用参数并不会改变服务器响应的格式。所以上述遍历 Recordset 的代码可以并不改变。
46 Cmd.NamedParameters = True
47
48 Dim typeParameter As ADODB.Parameter
49 Set typeParameter = Cmd.CreateParameter()
50 typeParameter.Direction = adParamInput
51 typeParameter.Name = "typeParam"
52 typeParameter.Value = 2
53 typeParameter.Type = adInteger
54 typeParameter.Size = 4
55
56 Cmd.Parameters.Append typeParameter
在分析服务的OLE DB提供程序中使用参数时,如下的几步非常重要:
· 命令必须使NamedParameters可用(第46行)。分析服务的OLE DB提供程序只支持命名了的参数。
· 参数的名字必须符合查询中的相应参数,但是在这里不使用 @ 前缀(第51行)。
· 可以只传输参数(第50行)。
· 参数的类型和大小必须声明(第53和54行)。
想对数据挖掘的OLE DB规则进行很好的理解,需要充分使用Microsoft Analysis Services 2005数据挖掘的特性。一旦设计好了数据挖掘查询,OLE DB就成为了一个可以执行它们、可以管理数据挖掘服务器的完整且具有通用性的API。关于在非托管C++或ADO.NET中C#使用OLEDB 的代码,请看本文附录2中的代码片段。
Analysis Management Objects – AMO
如同名字所显示的一样,AMO是一个用来管理任务的API。它非常适用于描述元数据属性的细节信息。AMO是一种非常符合微软分析服务的数据定义语言(DDL)的对象模型,在AMO中描述元数据对象。它允许迭代元数据对象、创建新对象、修改已存在对象。在AMO对象模型中,用DDL描述的每个属性都可以被检查和修改。AMO也可以用来检查和修改服务器属性,包括注册/非注册型插件算法,或者可注册/不可注册数据挖掘算法。AMO在元数据的定义和发现,以及服务器对象的训练上都非常有用。但是,它并不支持执行查询语句。
在讨论细节信息之前,我们应该先来说明一下AMO是一个托管库。所以,它可以在由通用执行时间组件(CLR——Common Language Runtime)兼容的编程语言开发的应用程序中使用,如C#、托管执行的C++、或者Visual Basic .NET。要想使用AMO, 我们需要在客户机上安装SQL Server 2005连接组件。
在使用AMO的时候,我们首先应该在应用程序的开始处引用 Microsoft.AnalysisServices.dll 库。之后,AMO对象模型就可以使用了。先来连接服务器:
Microsoft.AnalysisServices.Server server = new Server();
Server.Connect("localhost");
一旦连接成功,服务器端的元数据对象就可以被分级检查到:
Databases dbCollection = server.Databases;
foreach( Database db in dbCollection )
{
MiningStructures structCollection = db.MiningStructures;
foreach( MiningStructure struct in structCollection)
{
Console.WriteLine( struct.Name );
}
}
如果想修改已存在的元数据对象,我们只需要修改它的属性。使用如下代码:
model.Algorithm="Microsoft_Decision_Trees".
then call "Update".
model.Update();
当Update被调用时,你所做的修改就将被提交到服务器,同时刷新本地的信息集。
在服务器上添加一个新的元数据、在各自的集合上创建新成员这两个方法,与修改功能也是非常相似的:
MiningStructure myStructure;
MiningModel myModel = myStructure.Models.Add();
之后填充对象的内容:
myModel.Name = "New Model"
myModel.Algorithm = "Microsoft_Clustering"
然后通过调用 Update() 来提交对服务器端所作的修改:
myModel.Update();
当操作未能成功执行完毕时,更新操作(Update)将返回一个异常。通常产生异常的情况是:
· 被更新的属性不完整或者不一致。
· 由于当前用户未能拥有足够的权限而引起的服务器不能更新对象。
当出现异常的时候,我们可以找到问题的所在并修复它。
AMO在处理Analysis Services 2005服务器端元数据上具有很强的功能,但是它并不支持之前所提到的数据挖掘任务中的部分任务。它不提供进度通知的功能,也不提供查询挖掘模型的功能(一般情况下,它不支持DMX语句的执行)。如果你的应用需要浏览和检查Analysis Services 2005服务器,使用AMO是最好的选择。但是,如果除此以外你还需要执行语句或者显示进度通知,AMO的功能就不够了。下一章将为大家介绍两种通用API,它们支持分析服务所公开的所有特性。
进度通知:使用跟踪对象
当在服务器端同时执行多个事件时,微软分析服务就会发送一系列通知。这些事件包括用户的登入登出、 执行请求的开始位置和结束位置、不同服务器对象正在执行的进度情况。在接收到通知以后,管理员就可以检查服务器在每一刻的状态。正在处理服务器对象的用户也可以从中了解正在执行的操作是什么,以及还需要执行多长时间。
这一节中,我们将讨论应用程序是如何从Microsoft Analysis Services 2005服务器来接收进度通知的。我们从如何发现服务器发出的通知看起。 之后,我们简短的介绍应用程序如何订阅它所感兴趣的服务器通知。最后,我们给出一个需要处理进度通知的应用程序的编程模型。
在进行深入的讨论之前,我们先来明确一下,SQL Server 2005使用一个客户端分析器(Profiler)来处理这些通知。使用这个分析器,用户可以真正根据自己的需要进行通知的选择,然后检查这些通知的具体内容。分析器应用程序也允许记录服务器通知,可以为了以后检查通知内容而先将它们保存下来。它也可以使用性能计数器(Performance Counter)将正在执行的不同的性能指示器的相关服务器通知整合起来。大多数应用程序并不需要在代码中执行服务器通知,这一节针对那些需要使用数据挖掘客户端高级用户接口的开发者来进行讲解。
服务器发出的每种通知都是一个表型行。这一行包含一些基本信息,例如通知的种类、时间戳、服务器进程ID、以及服务器的名称。其它列分别对应特定的事件,例如处理通知的Progress Total、起始时间、结束时间、在服务器上已经执行的时间。服务器发出的所有通知被存放在一张虚拟表中,它为每个事件保留一行,以及被任何服务器事件支持的所有列的集合。这意味着:如果列A只被一个指定事件支持,它将在这张虚拟表中所有的事件行中出现,但是不支持A的事件的列A字段是空值。说这张表是一张虚拟表,是因为它并不存放在内存中,也不能被直接访问到。当没有人去看服务器事件进展情况的时候,它被存放在一个只有管理员可以访问到的“flight-recorder”文件中,用来提供过去出现错误的原因相关的有价值的信息。
这张虚拟表中的列集可以用常规XMLA发现语句(Discovery)来发现。这个计划的XMLA名称是DISCOVER_TRACE_COLUMNS,它的GUID是{a07ccd18-8148-11d0-87bb-00c04fc33942}。这个计划中的每一行描述事件表中的一列,计划至少有一列,使用事件的XML格式进行描述。XML格式的描述如下所示:
<COLUMN>
<ID>0</ID>
<TYPE>1</TYPE>
<NAME>EventClass</NAME>
<DESCRIPTION>Event Class is used to categorize events.</DESCRIPTION>
<FILTERABLE>false</FILTERABLE>
<REPEATABLE>false</REPEATABLE>
<REPEATEDBASE>false</REPEATEDBASE>
</COLUMN>
就这本白皮书来说,我们所感兴趣的属性有 ID 、 名字( Name )和描述( Description )。
ID 是列的数值型标志符。像我们关于事件的讨论一样,一个事件通过定义ID来指定列。列的名字和描述对于客户端来说非常重要。基于这些属性,客户端应用程序可以判断哪些列是自己所感兴趣的列,哪些列是可以忽略的。 ID 为 0 的列是“服务器通知”这张虚拟表中最重要的列,因为它是用来定义事件类型的。Microsoft Analysis Services 2005发布的所有通知都包含此列。
发现服务器发布的事件是一个与发现列很相似的任务。使用的XMLA计划是 DISCOVER_TRACE_EVENT_CATEGORIES,它的GUID是 {a07ccd19-8148-11d0-87bb-00c04fc33942}。这个任务中的每一行描述一个服务器发布的事件类别,任务记录事件类别中的全部事件。当使用XML形式定义事件类别时,任务中的代码如下所示:
<EVENTCATEGORY>
<NAME>Queries Events</NAME>
<TYPE>0</TYPE>
<DESCRITION>Collection of events for queries.</DESCRITION>
<EVENTLIST>
<EVENT>
<ID>9</ID>
<NAME>Query Begin</NAME>
<DESCRIPTION>Query begin.</DESCRIPTION>
<EVENTCOLUMNLIST>
<EVENTCOLUMN>
<ID>0</ID>
</EVENTCOLUMN>
<EVENTCOLUMN>
<ID>2<ID>
</EVENTCOLUMN>
...
</EVENTCOLUMNLIST>
</EVENT>
<EVENT>
<ID>10</ID>
<NAME>Query End</NAME>
<DESCRIPTION>Query end.</DESCRIPTION>
<EVENTCOLUMNLIST>
<EVENTCOLUMN>
<ID>0</ID>
</EVENTCOLUMN>
<EVENTCOLUMN>
<ID>2</ID>
</EVENTCOLUMN>
...
</EVENTCOLUMNLIST>
</EVENT>
....
</EVENTLIST>
</EVENTCATEGORY>
所以,一个事件类别可以包含多个带不同ID的事件。如之前所说的一样,每个事件拥有它们自己的列,并且它们都包含提供事件类信息的列0。
另一个特殊的列是列1,事件子类(event subclass)。它被多个事件共享。事件子类这一列允许跟踪用户,例如,我们可以用它来区一个 ProgressStart 事件到底是来自于数据挖掘,还是OLAP维度处理。如果一个事件中出现了列1,这一列要比其它列的定义复杂一些。如下文所示:
<EVENTCOLUMN>
<ID>1</ID>
<EVENTCOLUMNSUBCLASSLIST>
<EVENTCOLUMNSUBCLASS>
<ID>1</ID>
<NAME>Process</NAME>
</EVENTCOLUMNSUBCLASS>
<EVENTCOLUMNSUBCLASS>
<ID>2</ID>
<NAME>Merge</NAME>
</EVENTCOLUMNSUBCLASS>
...
</EVENTCOLUMNSUBCLASSLIST>
</EVENTCOLUMN>
这个更加复杂的定义描述了当前事件中列1可能出现的所有值的含义。
当一个应用程序决定了它感兴趣的事件或者事件列是哪些的时候,它可以订阅这些信息作为服务器通知。这个订阅功能在服务器创建跟踪对象的时候被创建。跟踪对象的功能与包含服务器通知的虚拟表的视图的功能相似。除此功能以外,跟踪对象存有服务器对象的所有属性。它可以被创建、修改、删除以及根据许可情况进行约束。一个跟踪声明会指定它感兴趣的事件(类似于关系型视图中的WHERE子句)以及事件将返回哪些列。定义跟踪的DDL可以包含更多的过滤条件,如“只返回那些列C是特定值的返回值”,但是这些过滤条件并不是本文要讨论的内容。这些高级选项可以从SQL Server 2005 在线文档中进行了解,在文档中有专门一节“跟踪要素(分析服务脚本语言)”。
让我们来考虑这样的一个应用程序,它用来训练挖掘模型,而且只订阅了如下进度报告事件:
· Progress Report Begin (事件ID是5)
· Progress Report Current (事件ID是7)
· Progress Report End (事件ID是6)
· Progress Report Error(事件ID是8)
对每一个事件来说,感兴趣的列是:
· 列 0, EventClass 。
· 列9, ProgressTotal ,完成当前任务所需要执行的步骤数(此列仅在Progress Report Current事件可用)。
· 列10, IntegerData ,数据挖掘进度通知中的属性,存储正在执行的任务的当前步骤(此列仅在Progress Report Current事件可用)。
· 列42, TextData ,包含当前步骤的详细描述。
我们使用下面的DDL语句创建这个跟踪:
<Create
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">
<ObjectDefinition>
<Trace>
<ID>DemoTrace</ID>
<Name>DemoTrace</Name>
<Events>
<Event>
<EventID>5</EventID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<Event ID>6</Event ID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<EventID>7</EventID>
<Columns>
<ColumnID>0</ColumnID>
<ColumnID>9</ColumnID>
<ColumnID>10</ColumnID>
<ColumnID>42</ColumnID>
</Columns>
</Event>
<Event>
<EventID>8</EventID>
<Columns>
<Columns>0</Columns>
<Columns>42</Columns>
</Columns>
</Event>
</Events>
</Trace>
</ObjectDefinition>
</Create>
一旦跟踪被创建,客户端应用程序就将订阅这个跟踪。订阅跟踪的功能与执行返回表型