投递文章投递文章 投稿指南投稿指南 RSS订阅RSS订阅

SQL Server 2005数据挖掘开发者指南

来源:Microsoft 发布时间:2008-01-06 收藏 投稿 字体:【

小结

我们希望本文能涉及Microsoft Analysis Services 2005可编程挖掘模型的所有重要的内容。但是MAS2005这个产品目前还没有完全完成,很多特性也将跟随时间的变迁而改变。MSDN的SQL站点包括SQL Server 2005 的常用信息,并且特别包括了数据挖掘的内容。
数据挖掘团队的站点也正在不停的更新着最新的信息、诀窍和技巧、白皮书、以及可下载的代码示例。
数据挖掘新闻组,microsoft.public.sqlserver.datamining 和 microsoft.private.sqlserver2005.analysisservices.datamining,也一直在关注着数据挖掘团队,所以它们也拥有大量有用的信息。

附录 1:Microsoft Analysis Services 2005服务器上的常用操作以及请求的协议格式

发送到Microsoft Analysis Services 2005的消息结构.


下面的例子包含一些常用的分析服务请求,使用SOAP、XMLA、以及DDL或 DMX来标示它们。
例1. 使用纯XMLA来发现服务器上的数据库
SOAP   <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
SOAP    <Body>
XMLA      <Discover xmlns="urn:schemas-miscrosoft-com:xml-analysis">
XMLA        <RequestType>DBSCHEMA_CATALOGS</RequestType>
XMLA        <Restrictions>
XMLA          <RestrictionList/>
XMLA        </Restrictions>
XMLA        <Properties />
XMLA      </Discover>
SOAP     </Body>
SOAP   </Envelope>

例2.在服务器上创建新的挖掘模型。使用XMLA执行(Execute)命令,中间使用DDL语句
SOAP <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
SOAP   <Body>
XMLA    <Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
XMLA      <Command>
DDL        <Alter
DDL        AllowCreate="true"
DDL        ObjectExpansion="ExpandFull"
DDL xmlns="http://schemas.microsoft.com/analysisservices/2003/engine"
DDL    >
DDL           <Object>
DDL             <DatabaseID>TT</DatabaseID>
DDL             <MiningStructureID>TestModel</MiningStructureID>
DDL           </Object>
DDL           <ObjectDefinition>
DDL           <MiningStructure
DDL           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
DDL    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
DDL               <ID>TestModel</ID>
DDL               <Name>TestModel</Name>
DDL               ...
DDL             </MiningStructure>
DDL           </ObjectDefinition>
DDL         </Alter>
XMLA      </Command>
XMLA      <Properties />
XMLA    </Execute>
SOAP  </Body>
SOAP </Envelope>

例 3.在挖掘模型上执行一个DMX查询
SOAP <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
SOAP   <Body>
XMLA    <Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
XMLA       <Command>
XMLA         <Statement>
DMX    SELECT Cluster() FROM CL
XMLA         </Statement>
XMLA       </Command>
XMLA       <Properties />
XMLA     </Execute>
SOAP  </Body>
SOAP </Envelope>


附录 2:在Ado.NET 和 C++中使用 OLE DB

非托管 C++
非托管C++是使用OLE DB提供程序的常见开发环境。使用它需要具有一些COM知识和对OLE DB模型很好的理解。ATL使用者模版将复杂的COM隐藏起来,并提供了一个编写应用程序的简单方法。使用ATL使用者模版并不像使用分析服务的特定API(如ADOMD.NET)那么容易,但是它是一个能获得非托管应用程序的方法。这里,我们假定用户已经拥有了ATL库的知识以及对数据挖掘的OLE DB规范有了很好的理解,所以我们直接给出一些非托管C++代码。
在下面的代码中,我们假设我们已经有了一个预先设置好的宏CHECK_ERROR,它用来管理COM错误。
一个非常简单(虽然不是非常有用)的执行这个宏的方法是:
#define CHECK_ERROR(x)   hr=(x);if(FAILED(hr)) return 1;

下面,我们将给出与OLE DB一节中通过ADO来执行的相同的任务的C++代码,因为篇幅的原因不再给出参数部分的代码。
我们这样初始化一个数据源和一个对话:
CoInitialize(NULL);
{
    HRESULT hr;
    CDataSource dataSrc;
    CSession session;

LPOLESTR szConnStr =
L"Provider=MSOLAP.3; Data Source=localhost;"
       L"Initial Catalog=MyCatalog";
       CHECK_ERROR(dataSrc.OpenFromInitializationString(szConnStr));
    CHECK_ERROR(session.Open(dataSrc));

请注意程序开始处必须要调用CoInitialize(NULL)。CoInitialize 初始化COM库,它必须在试图装载OLE DB提供程序前被当前线程所调用。
ATL 使用者模版提供一个常用的访问发现(Discovery)计划的方法:
CRestrictions
    CDynamicAccessor, 1,
    &DMSCHEMA_MINING_MODELS> schemaModels;
schemaModels.SetBlobHandling(DBBLOBHANDLING_NOSTREAMS);
CHECK_ERROR( schemaModels.Open( session, _T("MyCatalog") ));

CHECK_ERROR( schemaModels.MoveFirst() );
do
{
    if( hr == S_OK )
    {
       wchar_t* szModelName =   NULL;
       if( schemaModels.GetValue((DBORDINAL)3, &szModelName) )
       {
           printf("%S\n", szModelName);
       }
    }
    hr  =   schemaModels.MoveNext();
}while(hr == S_OK);

DMSCHEMA_MINING_MODELS 是被分析服务使用的挖掘模型提供程序指定计划的GUID。它在oledbdm.h文件中定义,这个文件是数据挖掘的OLE DB规范。上例中开始处用到的CRestrictions 类使用一个通用访问器(CDynamicAccessor)来自动绑定由发现操作返回的所有的列。
MoveFirst/MoveNext/GetValue操作在功能上与我们在OLE DB一节中所介绍的ADO的相应功能非常相似。
如果一个指定计划在一个应用(或多个应用)中被多次使用,我们需要定义一个专用访问器来简化和优化数据访问。下面的这段代码展示了这样的专用访问器是什么样子的,并且为之前用到的通用CRestrictions定义了一个用来发现挖掘模型的专用版本。挖掘模型计划访问器CMiningModelInfo应该完全填充挖掘模型计划感兴趣的所有的列。
class CMiningModelInfo
{
public:
// 构造函数
    CMiningModelInfo ()
    {
       memset(this, 0, sizeof(*this));
    }

// 属性
    TCHAR   m_szCatalog[129];
    TCHAR   m_szSchema[129];
    TCHAR   m_szName[129];
    TCHAR   m_szType[129];
    GUID    m_guidModel;
    TCHAR   m_szDescription[129];
...
    TCHAR   m_szService[129];
...


// Binding Map
BEGIN_COLUMN_MAP(CMiningModelInfo)
    COLUMN_ENTRY(1, m_szCatalog)
    COLUMN_ENTRY(2, m_szSchema)
    COLUMN_ENTRY(3, m_szName)
    COLUMN_ENTRY(4, m_szType)
    COLUMN_ENTRY(5, m_guidTable)
    COLUMN_ENTRY(6, m_szDescription)
...
    COLUMN_ENTRY(10, m_szService)
...
END_COLUMN_MAP()
};

typedef CRestrictions<CAccessor<CMiningModelInfo>, 7,
&DMSCHEMA_MINING_MODELS >        CMiningModels;

根据数据挖掘OLE DB规范,这里的7是一个挖掘模型计划中的约束值。
下面我们使用上述类,并且使用CMiningModels 来代替通用CRestrictions<CDynamicAccessor>。这个例子中获取模型名称的这段代码:
wchar_t* szModelName =   NULL;
if( schemaModels.GetValue((DBORDINAL)3, &szModelName) )
    printf("%S\n", szModelName);

将改变成这句代码:
   
printf("%S\n", schemaModels.m_szName);

我们可以使用相同的动态访问机制(或者为常用任务设计一个专用的访问器)来执行命令(DDL语句或者DMX语句)。
这样初始化命令:
CStringW   strDMXStmt;
strDMXStmt = L"SELECT NODE_CAPTION FROM DecisionTree1.CONTENT";

CCommand<CDynamicAccessor> cmdDMX;
cmdDMX.SetBlobHandling( DBBLOBHANDLING_NOSTREAMS );
CHECK_ERROR( cmdDMX.Open( session, strDMXStmt.GetBuffer(), NULL) )
CCommand 类的Open 方法传输一个字符串作为第二个参数。当连接到Microsoft Analysis Services 2005时,这个字符串可以是DMX语句也可以是DDL语句。当命令被执行的时候(Open方法),它的响应格式可以被GetColumnInfo 检测到。这就使得之后的pCol 参数指向了一个包含每一列(如名称、大小、类型)的向量。可以通过这个向量来识别得到的列的顺序。
DBORDINAL     ulColumns = 0;
DBCOLUMNINFO* pCol=NULL;
LPOLESTR      ppStrings = NULL;
CHECK_ERROR( cmdDMX.GetColumnInfo(&ulColumns, &pCol, &ppStrings) );

定义了目标列(在上述代码中是字符型的列0)以后,我们就可以遍历服务器响应来获取有用的数据了。
wchar_t*   pszBuffer = NULL;
CHECK_ERROR( cmdDMX.MoveFirst() );

do
{
wchar_t*   szNodeCaption = NULL;
if( cmdDMX.GetValue((DBORDINAL)1, &szNodeCaption) )
{
    printf("%S\n", szNodeCaption);
}
hRet   =   cmdDMX.MoveNext ();
}while(hRet == S_OK );

如果查询返回的是一个嵌套表,每一行将成为一个IRowset 对象。IRowset的子对象可以通过IParentRowset接口由最上层的行集合获得,IParentRowset接口是分层行集合必须提供的接口。
我们假设DMX查询语句是这样的:
"SELECT NODE_CAPTION, NODE_DISTRIBUTION FROM DecisionTree1.CONTENT"
循环读取这个行集合的数据的方法如下所示。例如,我们要读嵌套行集合NODE_DISTRIBUTION的第2列的值,根据数据挖掘OLE DB规范,NODE_DISTRIBUTION行集合必须包含一个挖掘属性值VARIANT。
// 外层循环,读最上层行集合
do
{
    // 获得最上层行集合的IParentRowset接口
    CComPtr<IParentRowset> spParentRowset;
    CHECK_ERROR(cmdDMX.m_spRowset.QueryInterface( &spParentRowset));
          
    // 使用一个动态访问器来读取嵌套行集合
    CAccessorRowset<CDynamicAccessor> nestedRowset;
    nestedRowset.SetBlobHandling( DBBLOBHANDLING_NOSTREAMS );

// 得到指向nestedRowset变量中的子行集合的指针
    CHECK_ERROR( spParentRowset->GetChildRowset(
NULL,
(DBORDINAL)2,
nestedRowset.GetIID(), (IUnknown**)nestedRowset.GetInterfacePtr() ) );
// 将动态访问器绑定到子行集合
    CHECK_ERROR( nestedRowset.Bind() );
    CHECK_ERROR( nestedRowset.MoveFirst() );

    // 内层循环,为了遍历嵌套子集合
    while (hr == S_OK )
    {
       VARIANT varTmp;
       ::VariantInit( &varTmp );
       if( nestedRowset.GetValue((DBORDINAL)2, &varTmp) )
       {
           // 在这里使用 VARIANT
       }
// 继续执行内层循环
       CHECK_ERROR( nestedRowset.MoveNext() );
    }
    // hr不是OK时,在以下两种情况下不是错误:
// DB_S_ENDOFROWSET 或显示了额外的确认代码
          
    // 继续执行外层循环
    hr  =   cmdDMX.MoveNext ();
}while(hr == S_OK );

参数nestedRowset是CAccessorRowset<CDynamicAccessor>类型的,它自动绑定所有的列,并且它可以方便的访问嵌套行集合所有字段的值。它提供了方法MoveFirst、MoveNext和GetValue,这些方法与cmdDMX命令非常相似。这是因为CCommand 类是源自CAccessorRowset 类的。它们将不同的行集合包含在一起: cmdDMX 对象包含命令执行结果的上层行集合,nestedRowset 对象包含子行集合。
设置OLE DB命令参数的详细内容,请到MSDN上查找,MSDN上提供了很多相关的例子和文档。

ADO.NET

ADO.NET被设计来在托管应用中代替ADO。它可以在托管应用中非常方便和容易的使用。ADO.NET是从托管应用连接到Microsoft Analysis Services 2005的首选解决方案,因为它是专为托管应用所设计的。ADO.NET一个非常重要的局限性是它不支持命名参数。也就是说,它只支持通过参数的序号来访问它们;所以ADO.NET不能使用带参数的DMX语句。
使用ADO.NET,需要在托管项目开始位置添加System.Data.dll引用,并在代码中这样使用这个引用:
using System.Data.OleDb;

像我们之前提过的一样,当使用单个连接将OLE DB对象数据源和对话打包在一起的时候, ADO.NET与ADO非常相似。要使用ADO.NET,需要先初始化一个ADO.NET连接,并使用OLE DB连接字符串来配置它:
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = "Provider=MSOLAP.3; Data Source=localhost; " +
"Initial Catalog=MyCatalog";
conn.Open();
一旦初始化连接完毕,就可以使用这个连接来发现服务器上的各种对象了。下面的代码是用来获取分析服务器上的挖掘模型列表的:
Guid miningModels = new Guid("{3ADD8A77-D8B9-11D2-8D2A-00E029154FDE}");
object[] arRestrictions = new object[1];
arRestrictions[0] = "CheckInTestDB";
DataTable tblModels =
conn.GetOleDbSchemaTable(miningModels, arRestrictions);
foreach( DataRow row in tblModels.Rows )
{
string modelName = row["MODEL_NAME"];
// 在这里使用modelName
}

在这段代码中,我们使用一个约束,目录名称,来限制在挖掘模型的目录MyCatalog 中的发现操作。DMX语句和DDL语句可以通过命令来执行,与ADO使用的方法非常相似。然而,ADO.NET命令(Command)对象给出了执行(Execute )方法的多个版本。
其中之一就是ExecuteReader。ExecuteReader返回一个Data  Reader对象(执行.NET IDataReader接口)。数据阅读器可以用来遍历服务器上的表型结果。如果这个表型结果包含嵌套表,可以为每一行获得一个数据阅读器。下面的代码执行一个DMX查询,它将返回上层中的列(NODE_CAPTION)和被嵌套表中的列(NODE_DISTRIBUTION)。然后它遍历上下两层的结果,这段代码体现了它是如何从服务器响应中获取信息的:
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT NODE_CAPTION, NODE_DISTRIBUTION FROM " +
" DecisionTree1.CONTENT WHERE NODE_TYPE=2";

OleDbDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
    // 使用上层字段
    Console.WriteLine(rdr.GetString(0));

    // 控制嵌套阅读器
    // 首先,确认列1种的对象是一个嵌套阅读器
    object objNestedRowset = rdr.GetValue(1);
    Debug.Assert(objNestedRowset is IDataReader);

    OleDbDataReader nestedReader = (OleDbDataReader)objNestedRowset;
    // 现在,遍历嵌套阅读器
    while (nestedReader.Read())
    {
       Console.WriteLine(nestedReader.GetValue(1).ToString() );
    }
}

与ADO命令非常相似, ADO.NET的 OleDbCommand 对象必须使用活跃连接(Connection)。它的CommandText属性可以被DDL语句或者DMX语句赋值。在ADO.NET阅读器对象(OleDbDataReader)中,根据列的序号来访问列。在列值类型已知的情况下,可以根据类型重新获得列值,就像上述程序中“使用上层字段”部分的代码。列值也可以作为普通对象而重新获得。在这个例子中,对象的类型可以在重新获得后被赋值,如上述代码段中“控制嵌套阅读器”中的代码所示。
另一种执行(Execute)方式是ExecuteNonQuery。这个方式在执行DDL语句或DMX语句后,不希望有返回值的时候特别适用(而不是返回成功或失败),例如CREATE MINING MODEL 或者 INSERT INTO。在下面的代码中,使用 ExecuteNonQuery 来执行DDL 处理(Process)语句。
cmd.CommandText = "  <Process " +
"xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">"+
"    <Type>ProcessStructure</Type>"+
"    <Object>"+
"      <DatabaseID>CheckInTestDB</DatabaseID>"+
"      <MiningStructureID>Structure1</MiningStructureID>"+
"    </Object>"+
"  </Process>";

cmd.ExecuteNonQuery();

与ADO非常相似,如果语句执行失败,将报一个异常。C# 异常处理允许开发者获得这个异常并研究产生错误的原因。

最新5条评论 查看所有评论
评论内容:请自觉遵守互联网相关政策法规。
用户名: 密码: 匿名 注册
热门文章
随机推荐
About iTtang - 联系方法  - 专题列表 - 友情链接  -  高级搜索   -  帮助中心  -