OLE DB for DM实践 —— 用数据挖掘实现交叉销售

       我们在访问一些销售网站时,常常会碰上这种情况:浏览某商品信息的同时,网页上会打出促销广告,购买此商品加另一商品可以享受折扣,就像下面图片中的那样。



       实现这种功能关键步骤是找到商品间的关联规则——我们会向购买了童车的客户推荐儿童玩具,而不会推荐汽车这种与童车毫不相干的商品。不过一个超市或网站上通常会销售上千种商品,通过人去识别商品相关性是不可能的,所以要使用计算机进行模式识别,计算机找到的规则有些是可预知的,但未知的规则更有意思,比较经典的是沃尔玛的尿布和啤酒故事(也有人说这个案例是编造的)。


    这里我做了个购物页面,模拟一个交叉销售的过程。

         

       页面上方有两个列表,左边的列出了可供客户选购的商品,客户选中了某个商品后加入到右边的购物篮列表,同时下方的单选列表,询问客户是否愿意再选购一个商品和当前的商品一起打包购买,打包购买可以享受折扣。

       要做的工作很简单,在SQL Server中使用样本数据库AdventureWorksDW建立一个关联规则挖掘模型(这部分在SQL Server 2005联机丛书中有详细的教程),部署模型后,在网页的后台代码中通过ADOMD.NET查询关联模型,预测可能实现交叉销售的商品。查询挖掘模型需要使用Microsoft.AnalysisServices.AdomdClient命名空间,其中包含与Analysis Services对话的客户端对象AdomdConnection用于连接SSAS数据库,AdomdCommand用于执行DMX查询,查询返回AdomdDataReader对象保存查询结果,有了查询结果就知道客户可能会打包购买哪些商品。
  

           使用AdventureWorksDW数据库中的视图vAssocSeqLineItemsvAssocSeqOrders建立挖掘模型。这两个视图,一个是订单数据,一个是订单明细行数据。应

Microsoft_Association_Rules算法,因为只要两个商品打包销售,将算法参数Maximun_Itemset_Size改成2。

模型训练后就可以得到各种关联规则,例如图中第一行规则:购买了Touring Tire Tube同时可能会购买Touring Tire

      


    设计一个页面,很简单,四个Label,两个ListBox,三个Button,一个RadioButtonList,一个SqlDataSource
   
页面代码如下:   

 1 ExpandedBlockStart.gif ContractedBlock.gif <% dot.gif @ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default"  %>
 2 None.gif
 3 None.gif <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
 4 None.gif
 5 None.gif < html  xmlns ="http://www.w3.org/1999/xhtml"   >
 6 None.gif < head  runat ="server" >
 7 None.gif     < title > 无标题页 </ title >
 8 None.gif </ head >
 9 None.gif < body >
10 None.gif     < form  id ="form1"  runat ="server" >
11 None.gif     < div >
12 None.gif         < asp:Label  ID ="Label1"  runat ="server"  Height ="1px"  Text ="选择您想要的商品"
13 None.gif            Width ="200px"  style ="z-index: 108; left: 10px; position: absolute; top: 15px" ></ asp:Label >
14 None.gif         < asp:Label  ID ="Label2"  runat ="server"  Height ="1px"  Style ="left: 270px;
15 None.gif            position: absolute; top: 15px; z-index: 101;"  Text ="您已选购的商品"  Width ="270px" ></ asp:Label >< br  />
16 None.gif         < br  />
17 None.gif         < asp:ListBox  ID ="ListBox1"  runat ="server"  DataSourceID ="AdventureWorksDW"
18 None.gif            DataTextField ="Model"  DataValueField ="Model"  Height ="353px"  Width ="200px"  style ="z-index: 102; left: 10px; position: absolute; top: 53px" ></ asp:ListBox > &nbsp;
19 None.gif         < asp:ListBox  ID ="ListBox2"  runat ="server"  Height ="353px"  Style ="z-index: 103; left: 270px;
20 None.gif            position: absolute; top: 53px"  Width ="270px"  AutoPostBack ="True" ></ asp:ListBox >
21 None.gif         < asp:Button  ID ="Button1"  runat ="server"  Font-Bold ="True"  Font-Size ="16pt"  Style ="left: 218px;
22 None.gif            position: absolute; top: 160px; z-index: 104;"  Text =">"  Width ="41px"  Height ="41px"   />
23 None.gif         < asp:Button  ID ="Button2"  runat ="server"  Font-Bold ="True"  Font-Size ="16pt"  Style ="left: 218px;
24 None.gif            position: absolute; top: 221px; z-index: 105;"  Text ="<"  Width ="41px"  Height ="41px"   />
25 None.gif         < asp:SqlDataSource  ID ="AdventureWorksDW"  runat ="server"  ConnectionString ="Data Source=127.0.0.1;Initial Catalog=AdventureWorksDW;Integrated Security=True"
26 None.gif            ProviderName ="System.Data.SqlClient"
27 None.gif            SelectCommand ="SELECT DISTINCT Model FROM vAssocSeqLineItems" ></ asp:SqlDataSource >
28 None.gif    
29 None.gif     </ div >
30 None.gif         &nbsp;   &nbsp;
31 None.gif         < asp:Panel  ID ="Panel1"  runat ="server"  BorderStyle ="None"  BorderWidth ="1px"  Enabled ="False"
32 None.gif            Height ="182px"  Style ="z-index: 106; left: 10px; position: absolute; top: 420px"
33 None.gif            Width ="380px" >
34 None.gif             < asp:Label  ID ="Label3"  runat ="server"  Height ="62px"  Style ="z-index: 100; left: 6px;
35 None.gif                position: absolute; top: 3px"  Text ="您可以捆绑购买下面的一种商品,捆绑购买将享受9折优惠"  Width ="370px" ></ asp:Label >
36 None.gif             < asp:RadioButtonList  ID ="RadioButtonList1"  runat ="server"  Height ="71px"  RepeatLayout ="Flow"
37 None.gif                Style ="z-index: 101; left: 6px; position: absolute; top: 72px"  Width ="370px" >
38 None.gif             </ asp:RadioButtonList >
39 None.gif             < asp:Button  ID ="Button3"  runat ="server"  Style ="z-index: 103; left: 6px; position: absolute;
40 None.gif                top: 151px"  Text ="确定"  Width ="370px"   />
41 None.gif         </ asp:Panel >
42 None.gif         < asp:Label  ID ="Label4"  runat ="server"  Height ="50px"  Style ="z-index: 107; left: 10px;
43 None.gif            position: absolute; top: 610px"  Width ="380px"  Font-Size ="12pt" ></ asp:Label >
44 None.gif     </ form >
45 None.gif </ body >
46 None.gif </ html >
47 None.gif

   向项目中添加Microsoft.AnalysisServices.AdomdClient引用,然后写后台代码:
  1 None.gif Imports  Microsoft.AnalysisServices.AdomdClient
  2 ExpandedBlockStart.gifContractedBlock.gifPartial  Class _Default Class _Default
  3InBlock.gif    Inherits System.Web.UI.Page
  4InBlock.gif
  5InBlock.gif    '客户向订单中加入一种商品
  6ExpandedSubBlockStart.gifContractedSubBlock.gif    Protected Sub Button1_Click()Sub Button1_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button1.Click
  7InBlock.gif        Me.line += 1 '增加订单中行数
  8InBlock.gif        Dim newPackage As Package = New Package(Me.ListBox1.SelectedItem.Text)
  9InBlock.gif        Me.order.Add(newPackage, line.ToString, , ) '单据中加入一商品包
 10InBlock.gif        Me.selectedLine = Me.line '指定当前加入的行作为挖掘模型查询行
 11InBlock.gif        Me.ListBox2.Items.Add(New ListItem(newPackage.name, line.ToString)) '加入已购商品列表
 12InBlock.gif        Me.generateSelectionList() '查询挖掘模型,产生供客户选购的打包商品
 13ExpandedSubBlockEnd.gif    End Sub

 14InBlock.gif
 15InBlock.gif    '客户从已购商品列表中删除一行
 16ExpandedSubBlockStart.gifContractedSubBlock.gif    Protected Sub Button2_Click()Sub Button2_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button2.Click
 17InBlock.gif        Me.selectedLine = 0
 18InBlock.gif        Me.Panel1.Enabled = False
 19InBlock.gif        Dim removedLine As String = Me.ListBox2.SelectedValue
 20InBlock.gif        Me.ListBox2.Items.Remove(Me.ListBox2.SelectedItem)
 21InBlock.gif        Me.order(removedLine).removed = True
 22ExpandedSubBlockEnd.gif    End Sub

 23InBlock.gif
 24InBlock.gif    '客户在已购列表中选择一行,如果此行的包只有一件商品,产生供客户选购的打包商品
 25ExpandedSubBlockStart.gifContractedSubBlock.gif    Protected Sub ListBox2_SelectedIndexChanged()Sub ListBox2_SelectedIndexChanged(ByVal sender As ObjectByVal e As System.EventArgs) Handles ListBox2.SelectedIndexChanged
 26InBlock.gif        If Me.order(Me.ListBox2.SelectedValue).models.count = 1 Then
 27InBlock.gif            Me.Panel1.Enabled = True
 28InBlock.gif            Me.selectedLine = CType(Me.ListBox2.SelectedValue, Integer)
 29InBlock.gif            Me.generateSelectionList()
 30InBlock.gif        Else
 31InBlock.gif            Me.Panel1.Enabled = False
 32InBlock.gif        End If
 33ExpandedSubBlockEnd.gif    End Sub

 34InBlock.gif
 35InBlock.gif    '客户从单选列表中选中一个商品,将选中商品加入包中
 36ExpandedSubBlockStart.gifContractedSubBlock.gif    Protected Sub Button3_Click()Sub Button3_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button3.Click
 37InBlock.gif        If Me.RadioButtonList1.SelectedIndex <> -1 AndAlso Me.order(Me.selectedLine.ToString).models.count = 1 Then
 38InBlock.gif            Me.Panel1.Enabled = False
 39InBlock.gif            CType(Me.order(Me.selectedLine), Package).models.Add(Me.RadioButtonList1.SelectedItem.Text)
 40InBlock.gif            CType(Me.order(Me.selectedLine), Package).discount = 9
 41InBlock.gif            Me.ListBox2.Items.FindByValue(Me.selectedLine.ToString).Text = CType(Me.order(Me.selectedLine), Package).name
 42InBlock.gif        End If
 43ExpandedSubBlockEnd.gif    End Sub

 44InBlock.gif
 45InBlock.gif    '查询挖掘模型,在单选列表控件产生供客户选择的商品
 46ExpandedSubBlockStart.gifContractedSubBlock.gif    Private Sub generateSelectionList()Sub generateSelectionList()
 47InBlock.gif        If Me.selectedLine <> 0 Then
 48InBlock.gif            Dim cnDataSource As String = ""
 49InBlock.gif            Dim cnPassword As String = "xxxxxx"
 50InBlock.gif            Dim cnUserId As String = "cheney"
 51InBlock.gif            Dim cnInitialCatalog As String = "test"
 52InBlock.gif            Dim cnLocation As String = "127.0.0.1"
 53InBlock.gif            Dim cnMiningModel As String = "v Assoc Seq Orders"
 54InBlock.gif            Dim cnNestedTable As String = "v Assoc Seq Line Items"
 55InBlock.gif
 56InBlock.gif            Dim cnString As String = Me.getCnString(cnDataSource, cnPassword, cnUserId, cnInitialCatalog, cnLocation)
 57InBlock.gif            Dim cmdText As String = Me.getCmdText(cnMiningModel, cnNestedTable)
 58InBlock.gif            Dim cn As AdomdConnection = New AdomdConnection(cnString)
 59InBlock.gif            Dim cmd As AdomdCommand = cn.CreateCommand
 60InBlock.gif            cmd.CommandText = cmdText
 61InBlock.gif            cmd.Parameters.Add("ProductModel"Me.order(Me.selectedLine.ToString).models(1).ToString)
 62InBlock.gif            Dim Reader As AdomdDataReader
 63InBlock.gif            cn.Open()
 64InBlock.gif            Try
 65InBlock.gif                Reader = cmd.ExecuteReader()
 66InBlock.gif            Catch ex As Exception
 67InBlock.gif                Me.Panel1.Enabled = False
 68InBlock.gif                Me.Label4.Text = ex.Message
 69InBlock.gif                Exit Sub
 70InBlock.gif            End Try
 71InBlock.gif            Reader.Read()
 72InBlock.gif            Dim nestedReader As AdomdDataReader = Reader.GetDataReader(0)
 73InBlock.gif            Me.RadioButtonList1.Items.Clear()
 74InBlock.gif            While nestedReader.Read
 75InBlock.gif                Me.RadioButtonList1.Items.Add(nestedReader(0))
 76InBlock.gif            End While
 77InBlock.gif            cn.Close()
 78InBlock.gif            Me.Label3.Text = "您已经购买了" + Me.order(Me.selectedLine.ToString).models(1+ ",您可以捆绑购买下面一种商品,且享受9折优惠"
 79InBlock.gif            Me.Panel1.Enabled = True
 80InBlock.gif        End If
 81ExpandedSubBlockEnd.gif    End Sub

 82InBlock.gif
 83InBlock.gif    '获取数据挖掘连接字符串
 84ExpandedSubBlockStart.gifContractedSubBlock.gif    Private Function getCnString()Function getCnString(ByVal dataSource As StringByVal password As StringByVal userId As StringByVal initialCatalog As StringByVal location As StringAs String
 85InBlock.gif        Dim conxtString As String = ""
 86InBlock.gif        If dataSource = "" OrElse IsNothing(dataSource) Then
 87InBlock.gif            conxtString += ""
 88InBlock.gif        Else
 89InBlock.gif            conxtString += "Data Source=" + dataSource + ";"
 90InBlock.gif        End If
 91InBlock.gif        If password = "" OrElse IsNothing(password) Then
 92InBlock.gif            conxtString += ""
 93InBlock.gif        Else
 94InBlock.gif            conxtString += "Password=" + password + ";"
 95InBlock.gif        End If
 96InBlock.gif        If userId = "" OrElse IsNothing(userId) Then
 97InBlock.gif            conxtString += ""
 98InBlock.gif        Else
 99InBlock.gif            conxtString += "User ID=" + userId + ";"
100InBlock.gif        End If
101InBlock.gif        If initialCatalog = "" OrElse IsNothing(initialCatalog) Then
102InBlock.gif            conxtString += ""
103InBlock.gif        Else
104InBlock.gif            conxtString += "Initial Catalog=" + initialCatalog + ";"
105InBlock.gif        End If
106InBlock.gif        If location = "" OrElse IsNothing(location) Then
107InBlock.gif            conxtString += ""
108InBlock.gif        Else
109InBlock.gif            conxtString += "Location=" + location
110InBlock.gif        End If
111InBlock.gif        Return conxtString
112ExpandedSubBlockEnd.gif    End Function

113InBlock.gif
114InBlock.gif    '获取DMX查询语句
115ExpandedSubBlockStart.gifContractedSubBlock.gif    Private Function getCmdText()Function getCmdText(ByVal miningModel As StringByVal nestedTable As StringAs String
116InBlock.gif        Return "select  predictassociation([" + miningModel + "].[" + nestedTable + "],exclusive,3,$adjustedprobability) from [" + miningModel + "] prediction Join (select (select @ProductModel as [Model]) as Product) as t on t.product.[Model]=[" + miningModel + "].[" + nestedTable + "].[Model]"
117ExpandedSubBlockEnd.gif    End Function

118InBlock.gif
119ExpandedSubBlockStart.gifContractedSubBlock.gif    Public Sub on_load()Sub on_load(ByVal sender As ObjectByVal e As EventArgs) Handles Me.Load
120InBlock.gif        If Me.IsPostBack = False Then
121InBlock.gif            Me.order = New Collection
122InBlock.gif            Me.line = 0
123InBlock.gif            Me.selectedLine = 0
124InBlock.gif        End If
125ExpandedSubBlockEnd.gif    End Sub

126InBlock.gif
127InBlock.gif    '订单中的行数,一行代表一个商品销售包
128ExpandedSubBlockStart.gifContractedSubBlock.gif    Property line()Property line() As Integer
129InBlock.gif        Get
130InBlock.gif            Return Me.ViewState("line")
131InBlock.gif        End Get
132InBlock.gif        Set(ByVal value As Integer)
133InBlock.gif            If IsNothing(Me.ViewState("line")) Then
134InBlock.gif                Me.ViewState.Add("line", value)
135InBlock.gif            Else
136InBlock.gif                Me.ViewState("line"= value
137InBlock.gif            End If
138InBlock.gif        End Set
139ExpandedSubBlockEnd.gif    End Property

140InBlock.gif
141InBlock.gif    '用于查询挖掘模型的订单中的行。将查询数据挖掘模型中,在购买了此行的包中商品后,客户还可能购买哪些商品
142ExpandedSubBlockStart.gifContractedSubBlock.gif    Property selectedLine()Property selectedLine() As Integer
143InBlock.gif        Get
144InBlock.gif            Return Me.ViewState("selectedLine")
145InBlock.gif        End Get
146InBlock.gif        Set(ByVal value As Integer)
147InBlock.gif            If IsNothing(Me.ViewState("selectedLine")) Then
148InBlock.gif                Me.ViewState.Add("selectedLine", value)
149InBlock.gif            Else
150InBlock.gif                Me.ViewState("selectedLine"= value
151InBlock.gif            End If
152InBlock.gif        End Set
153ExpandedSubBlockEnd.gif    End Property

154InBlock.gif
155InBlock.gif    '订单中包括多行,每一行代表一个销售包,包中含有多个商品。多个商品可以打包销售,也可以单独销售,如果单独销售,包中只有一个商品
156ExpandedSubBlockStart.gifContractedSubBlock.gif    Property order()Property order() As Collection
157InBlock.gif        Get
158InBlock.gif            Return Me.ViewState("order")
159InBlock.gif        End Get
160InBlock.gif        Set(ByVal value As Collection)
161InBlock.gif            If IsNothing(Me.ViewState("order")) Then
162InBlock.gif                Me.ViewState.Add("order", value)
163InBlock.gif            Else
164InBlock.gif                Me.ViewState("order"= value
165InBlock.gif            End If
166InBlock.gif        End Set
167ExpandedSubBlockEnd.gif    End Property

168ExpandedBlockEnd.gifEnd Class

169 None.gif
170 None.gif ' 商品可以打包销售,包中有多个商品
171 None.gif < Serializable() >  _
172 ExpandedBlockStart.gifContractedBlock.gif Class Package Class Package
173ExpandedSubBlockStart.gifContractedSubBlock.gif    Public ReadOnly Property name()Property name() As String '包的名称,格式是:“商品型号名 + 商品型号名,折扣”
174InBlock.gif        Get
175InBlock.gif            Dim v As String = ""
176InBlock.gif            For i As Integer = 1 To Me.models.Count
177InBlock.gif                If i = 1 Then
178InBlock.gif                    v += models(i)
179InBlock.gif                Else
180InBlock.gif                    v += " + " + models(i)
181InBlock.gif                End If
182InBlock.gif            Next
183InBlock.gif            If Me.discount <> 10 Then
184InBlock.gif                v += " , " + Me.discount.ToString + ""
185InBlock.gif            End If
186InBlock.gif            Return v
187InBlock.gif        End Get
188ExpandedSubBlockEnd.gif    End Property

189InBlock.gif    Public discount As Integer '折扣
190InBlock.gif    Public removed As Boolean '包从已选商品列表中删除标识
191InBlock.gif    Public models As Collection '商品型号集合
192ExpandedSubBlockStart.gifContractedSubBlock.gif    Public Sub New()Sub New(ByVal firstModel As String)
193InBlock.gif        Me.models = New Collection
194InBlock.gif        Me.models.Add(firstModel)
195InBlock.gif        Me.discount = 10
196InBlock.gif        Me.removed = False
197ExpandedSubBlockEnd.gif    End Sub

198ExpandedBlockEnd.gifEnd Class
   

总结:从代码中可以看出Adomd与Ado在查询方面的使用方法区别不大,关键是对于OLE DB for DM中嵌套表及DMX的理解。我这里仅仅是简单的实践而已,实际环境中的就不可能这么简单,商务网站一般不会是在客户选择了一件商品后就打折促销,而是等客户选购完他需要的商品后,再将其他商品打折推销给客户;另外对复杂的挖掘模型查询是非常费时的,代码中还需要考虑线程异步的问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值