DotNetNuke(DNN)的搜索,索引(index) indexing provider, Search Input, Search Results, ModuleIndexer
由 admin 在 周六, 2006-07-22 17:08 提交

又基于SearchInput模块做了一个自己的SearchInput模块,它可以指定搜索范围,及搜索一些额外字段,如按书号或作者进行搜索.



DotNetNuke中自己新建的模块(Module)虽然在Controller上实现了Isearchable接口,但其中的内容可能还是无法被DNN的搜索模块搜索到,经跟踪调查发现要将此模块在数据库中的DesktopModules表中的记录的SupportFeatures字段值改为2或3,然后再re-index一下,然后你新建的模块中的内容(数据)就可以被DNN搜索到了。

 

DNN中的每一个Search Input模块都要指定一个Search Result模块以显示搜索结果。如果你新建了自己的SearchInput或SearchResults模块,想要改变默认的对应关系或使你的新建的SearchInput模块对应到你自己的SearchResult模块上,就需要:
1. 新建一个页面(Tab),在其中放一个你所要的SearchResult模块。
2. 然后到SearchInput模块的Settings中指定使用此页面(Tab)来呈现搜索结果,即可。



后来我又要给DNN的SearchInput增加模式,即一个简单搜索模式(2个搜索条件框),一个高级模式(8个搜索条件框),还要在Settings页中加一个控制选项,用来控制是显示简单模式还是高级模式.

 

在简单模式下,有一个链接可以跳转到高级模式.如果网站(PORTAL)中有多个页面都包含有高级模式的搜索输入模块(SearchInput Module),则Settings(设置)页中可以设定是要跳转到哪一个页面.



后客户又要把两个搜索结果并成一个,即一个是DNN默认的SearchResults,另一个是通过搜索客户的专有产品数据库产生的产品搜索结果,这个工作也花费了我不少时间。因为要把两个分页机制合并到一起,即默认两个Search Results List是各有一个分页导航按钮(Link)的,且两个List的返回的结果数目是不一样的,故需取两者的最大集合来合并成一个分页导航按钮(Link)。


2006-07-17:
一个为客户新建的模块中的一些字段(如产品编号,关键字等)也要能被DNN的默认搜索功能搜索到,就对Public Function GetSearchItems(ByVal ModInfo As Entities.Modules.ModuleInfo) As Services.Search.SearchItemInfoCollection Implements Entities.Modules.ISearchable.GetSearchItems进行了修改,使客户模块中的产品编号等特殊字段也能被搜索到.后发现默认的DNN搜索是以空格来分隔单词的,所以要把逗号转成空格才行,然后再到Host > Search Admin > Re-index content,若模块的内容没有变过,Re-index content不会起作用,所以必须故意进去对模块的内容进行UPDATE,然后再Re-index content就行了,若产品编号是数字的话,还要记得勾上Include Numbers.若要检查为何自己的的内容无法被搜到,可到SearchWord表中去看.


2006-07-17:
后客户又要对每一个页面上的Meta Keywords进行索引,以便能被DNN的默认搜索功能搜索到。DNN默认的ModuleIndexer是基于模块的,即是将关键词作为某一模块的内容进行索引和存放和搜索的,而一个PAGE上有多个模块,无法简单的在模块上实现ISearchable接口来做到,故只能自己重新做一个IndexProvider,基于ModuleIndexer的代码来做。

 

修改Web.config以使用自己新做的ModuleIndexProvider,如下

<providers>
<clear />
<!--
<add name="ModuleIndexProvider" type="DotNetNuke.Services.Search.ModuleIndexer, DotNetNuke.Search.Index" providerPath="~\Providers\SearchProviders\ModuleIndexer\" />
-->
<add name="XXX_ModuleIndexProvider" type="DotNetNuke.Services.Search.XXX.ModuleIndexer, XXX.Search.Index" providerPath="~\Providers\SearchProviders\XXX_ModuleIndexer\" />
</providers>

主要要修改GetSearchIndexItems这个方法,我修改后的代码如下:

Public Overrides Function GetSearchIndexItems(ByVal PortalID As Integer) As SearchItemInfoCollection
Dim SearchItems As New SearchItemInfoCollection
Dim SearchCollection As SearchContentModuleInfoCollection = GetModuleList(PortalID)
For Each ScModInfo As SearchContentModuleInfo In SearchCollection
Try
Dim myCollection As SearchItemInfoCollection
myCollection = ScModInfo.ModControllerType.GetSearchItems(ScModInfo.ModInfo)
If Not myCollection Is Nothing Then
SearchItems.AddRange(myCollection)
End If
Catch ex As Exception
LogException(ex)
End Try
Next
'*************************************************
'  add page meta keywords to search index result
Dim arrTabs As ArrayList
Dim objTabController As New TabController
arrTabs = objTabController.GetAllTabs
Dim i As Integer
For i = 0 To arrTabs.Count - 1
Dim objTab As TabInfo = CType(arrTabs(i), TabInfo)
Dim aModuleIdOnThisTab As Integer
'get a module id on this tab
Dim objModuleController As New ModuleController
Dim objModule As New ModuleInfo
Dim intIndex As Integer
Dim arrModules As ArrayList = objModuleController.GetPortalTabModules(objTab.PortalID, objTab.TabID)
For intIndex = 0 To arrModules.Count - 1
objModule = CType(arrModules(intIndex), ModuleInfo)
'get a dedicated module on this page
If objModule.AllTabs = False Then
aModuleIdOnThisTab = objModule.ModuleID
Exit For
End If
Next
Dim SearchItem As SearchItemInfo = New SearchItemInfo(objTab.Title, objTab.Description, 9999, Now, aModuleIdOnThisTab, "", objTab.KeyWords.Replace(","c, " "c), "", Null.NullInteger)
SearchItems.Add(SearchItem)
Next
'*************************************************
Return SearchItems
End Function

其实就是借用了某一个TAB(PAGE)上的模块来存储SearchItem,因为DNN默认的方式就是基于模块进行搜索的,如果一个页面上面没有任何模块,那么它的META KEYWORD就无法被搜索到了。

且以上代码还排除了会显示在所有页面上的模块,因为这样的模块会把某一页面上的META KEYWORD也错误的带到其他页面上去,因为这样的模块会显示在所有页面上。我粗略的测试后感觉是这种情况。

2006-07-25:
又进行了修改,排除了选用已被删除的模块来存放SearchItem的可能性. 发现一些问题:因为从某种意义上讲,这已经是在HACKING DNN了,因为这个任务是超出了DNN的固有结构和已有结构的. 如果某一页中有一些看不见的,因乱操作而产生的垃圾结构数据,会有可能导致此页的PAGE META KEYWORDS索引不到和搜索不到. 比如TabModules和Modules表中的数据乱了,如一个模块存在于一个已删除的PANE中,或反正TabModules和Modules表中的数据乱了,我就把TabModules和Modules表全部删除干净,或删除乱掉的模块记录,再重新RE-INDEX一下. 我那个原来有问题的页,就可以正常的索引和搜索到PAGE META KEY WORDS了.

还有一种办法可保证选用的模块绝对没问题:用同一方法中上半部分中原DNN默认的已生成的SearchItems中的TabID相同的模块的ID.

当然还有另一种不同思路来实现,大致思想如实现Banner的Ads的索引和搜索类似,参见下方.



客户需要Banner Module中的Text, Script也要被Index(索引)以可被搜索到。
Banner是用来在网站上放广告的,客户要列在Search Results页中的被搜索到的广告条目的超链URL是指向广告客户的目标URL的,而不是在DNN网站上包含此广告Banner的页面。
最终我在ModuleIndexer.vb中添加如下代码:

 

'##########################################
' index Text, Script Ads
Dim objBannerController As New Services.Vendors.BannerController
'get all searchable banners
Dim bannerAryList As ArrayList = objBannerController.GetBanners(-1)
For Each bi As BannerInfo In bannerAryList
Dim sii As SearchItemInfo = New SearchItemInfo(bi.BannerName, bi.Description, 65535, Now, moduleIdPicked, "", bi.BannerName & " - " & bi.Description)
SearchItems.Add(sii)
Next
'##########################################

执行如下SQL脚本:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER procedure [dbo].[GetBanners]
@VendorId int
as
select BannerId,
BannerName,
URL,
Impressions,
CPM,
Views,
ClickThroughs,
StartDate,
EndDate,
BannerTypeId,
Description,
GroupName,
Criteria,
Width,
Height
from   Banners
where
(VendorId = @VendorId)
OR
((@VendorId = -1) AND ((BannerTypeId = 6)OR(BannerTypeId = 7)))
order  by CreatedDate desc

并在SearchResults.ascx上做了一些修改,最终成功了。



2006-07-24:
把做好的ModuleIndexer布署到测试服务器上去测试,结果发现无法搜索到任何东西,SearchWord表中没有新单词增加进去,以为是什么地方出错了,调了半天.

 

其实最后发现是我自己犯了两个错误:
1.修改WEB.CONFIG的时候

    <searchIndex defaultProvider="OSV_ModuleIndexProvider">
<providers>
<clear />
<add name="OSV_ModuleIndexProvider" type="DotNetNuke.Services.Search.OSV.ModuleIndexer, OSV.Search.Index" providerPath="~\Providers\SearchProviders\OSV_ModuleIndexer\" />
</providers>
</searchIndex>

下面 add name.... 的地方改了,上面的defaultProvider忘了改了.

2.
Host > Search Admin 中的 Maximum Word Length 和 Minimum Word Length 填反了,当时也没注意,就在上面填了一个小数字,下面填了一个大数字. 结果可想而知,当然什么也索引(搜索)不到了. 只有数字能被索引(搜索)到.



2006-07-24:

 

发现模块的Controller 中的 GetSearchItems 中的
Dim SearchItem As SearchItemInfo = New SearchItemInfo(...
这行代码中的日期(PubDate)很重要,我把它设为Now了,以便保持索引和搜索结果的最新. 若不为Now则需故意去Update一下文本,以使能搜索到最新的在其他额外的客户字段上的改动.


发现ModuleIndexer.vb中的GetSearchIndexItems方法中的try很重要,布置不妥的话会使Re-Index时出错,故重新布置try后,保证了即使某行出错也能输出其他的SearchItems,代码如下:

        Public Overrides Function GetSearchIndexItems(ByVal PortalID As Integer) As SearchItemInfoCollection
Dim moduleIdPicked As Integer
Dim SearchItems As New SearchItemInfoCollection
Dim SearchCollection As SearchContentModuleInfoCollection = GetModuleList(PortalID)
Try
For Each ScModInfo As SearchContentModuleInfo In SearchCollection
Try
Dim myCollection As SearchItemInfoCollection
myCollection = ScModInfo.ModControllerType.GetSearchItems(ScModInfo.ModInfo)
If Not myCollection Is Nothing Then
SearchItems.AddRange(myCollection)
moduleIdPicked = ScModInfo.ModInfo.ModuleID
End If
Catch ex As Exception
LogException(ex)
End Try
Next
'##########################################
' index Text, Script Ads
Dim objBannerController As New Services.Vendors.BannerController
'get all searchable banners
Dim bannerAryList As ArrayList = objBannerController.GetBanners(-1)
For Each bi As BannerInfo In bannerAryList
Try
Dim sii As SearchItemInfo = New SearchItemInfo(bi.BannerName, bi.Description, 65535, Now, moduleIdPicked, bi.URL, bi.BannerName & " - " & bi.Description, "OsvAdsBanner")
SearchItems.Add(sii)
Catch ex As Exception
LogException(ex)
End Try
Next
'##########################################
'*************************************************
'  add page meta keywords to search index result
Dim arrTabs As ArrayList
Dim objTabController As New TabController
arrTabs = objTabController.GetAllTabs
Dim i As Integer
For i = 0 To arrTabs.Count - 1
Dim objTab As TabInfo = CType(arrTabs(i), TabInfo)
Dim aModuleIdOnThisTab As Integer
'get a module id on this tab
Dim objModuleController As New ModuleController
Dim objModule As New ModuleInfo
Dim intIndex As Integer
Dim arrModules As ArrayList = objModuleController.GetPortalTabModules(objTab.PortalID, objTab.TabID)
For intIndex = 0 To arrModules.Count - 1
Try
objModule = CType(arrModules(intIndex), ModuleInfo)
'get a dedicated module on this page
If objModule.AllTabs = False Then
aModuleIdOnThisTab = objModule.ModuleID
Exit For
End If
Catch ex As Exception
LogException(ex)
End Try
Next
Dim SearchItem As SearchItemInfo = New SearchItemInfo(objTab.Title, objTab.Description, 9999, Now, aModuleIdOnThisTab, "", objTab.KeyWords.Replace(","c, " "c), "", Null.NullInteger)
SearchItems.Add(SearchItem)
Next
'*************************************************
Catch ex As Exception
LogException(ex)
End Try
Return SearchItems
End Function