直播中
如果您經(jīng)常訪問“內(nèi)幕新聞”站點(diǎn),您就會(huì)知道,Microsoft Web 組在 2000 年 7 月份召開的“專業(yè)開發(fā)人員討論會(huì)”之前推出了其 Search 引擎的新型改進(jìn)版本。您已知道該版本引入了先進(jìn)的同義詞匹配、可返回最為相關(guān)的加按語搜索結(jié)果的擴(kuò)展 Best Bets 邏輯,以及對最常用搜索的智能緩存。
然而,有關(guān)該版本的內(nèi)幕消息遠(yuǎn)比表面上的東西多。
我們當(dāng)然會(huì)興奮不已,因?yàn)樵撍阉靼姹镜呢S富的功能以及經(jīng)改進(jìn)的搜索結(jié)果明顯地能為客戶帶來更佳的搜索體驗(yàn)(參閱 Search 2.5 技術(shù)內(nèi)幕)。但是,大多數(shù)人當(dāng)時(shí)并未意識(shí)到,我們同時(shí)在幕后將傳統(tǒng)的基于 ASP(Active Server Page 活動(dòng)服務(wù)器頁面)的 Search 2.5 版移植到新型的 Microsoft .NET 框架。
對搜索組而言,這是最具前沿性的開發(fā)。因?yàn)槲覀円呀?jīng)深入到 Internet 服務(wù)的未來。而且我們希望如此。下面來談?wù)剛€(gè)中緣由。
為何要移植到 .NET?
顯而易見,我們正在進(jìn)入 Internet 的下一個(gè)階段。我們正在跨越通常意義上的 Web 頁面,并在開發(fā)功能強(qiáng)大的 Web 服務(wù)。在這一階段,使資源和信息有計(jì)劃地得到利用是極為重要的。這樣,我們就可以把這些資源和信息作為服務(wù)來利用,而不是讓其停留在雜亂無章的數(shù)據(jù)倉庫中。
可擴(kuò)展標(biāo)記語言 (XML) 是在超級(jí)分布式系統(tǒng)之間實(shí)現(xiàn)多數(shù)據(jù)集傳輸?shù)囊环N手段。它同時(shí)可以使開發(fā)人員以更具價(jià)值的新型方式聚集和組合各種來源的數(shù)據(jù) – 這樣用戶就可以直接從中受益。
就 Search 而言,我們?yōu)槎喾N自定義和本地化 Search 版本設(shè)計(jì)了在 microsoft.com 上查找信息的核心功能。我們組在如何使數(shù)據(jù)訪問兼?zhèn)潇`活性和可用性方面面臨挑戰(zhàn)。在 .NET 出現(xiàn)之前,我們確實(shí)無法使客戶在不使用安全端口上的 DCOM (分布式組件對象模型)的情況下針對我們的功能設(shè)計(jì)程序,或者客戶只得將我們的多種軟件版本安裝在其服務(wù)器上以便訪問代碼和 COM。
我們組對即將推出的 .NET 技術(shù)進(jìn)行了研究,并認(rèn)識(shí)到可以通過將代碼移植到 .NET 框架來解決所有遠(yuǎn)程性問題。而且,還有一個(gè)意外收獲,我們還可以實(shí)現(xiàn) HTTP 和 SOAP 的無處不在的連接。對絕大多數(shù)人而言,是否有某個(gè)人在 Microsoft 或在世界的某個(gè)地方,使用我們的 Web 服務(wù)在內(nèi)部開發(fā)用于完全不同用途的應(yīng)用程序,無關(guān)緊要。我們對兩種情況均予以支持,同時(shí)我們也可以免費(fèi)獲得技術(shù)方面的好處。
最新的 Search 2.5 版如今運(yùn)行在 Site Server 3.0 上,并仍然使用 COM 從搜索目錄獲得結(jié)果。該應(yīng)用程序的其它各個(gè)方面都基于 XML。XML 作為一種將數(shù)據(jù)(例如,Vocabulary 和 Best Bets)發(fā)布到 Web 服務(wù)器的手段,使我們能夠輕而易舉地?cái)U(kuò)大我們的 Web 空間。
我們同時(shí)執(zhí)行了一項(xiàng)緩存客戶請求的最為常用的查詢和結(jié)果的方案,這是通過將這些查詢和結(jié)果保留在 Web 服務(wù)器上來實(shí)現(xiàn)的,并因此增強(qiáng)了可擴(kuò)展性,進(jìn)一步提高了性能。由于我們的核心體系結(jié)構(gòu)是基于 XML 的,因而,移植到一個(gè)將利用 .NET 框架 Web 服務(wù)的模型確實(shí)非常簡單,而這些 .NET 框架 Web 服務(wù)是建立在新型 ASP+ 技術(shù)基礎(chǔ)之上的(ASP+ 技術(shù)被稱為活動(dòng)服務(wù)器方法 (ASMX) 頁面)。
轉(zhuǎn)換
Search 體系結(jié)構(gòu)由三個(gè)組件組成:
Word Parsing and Vocabulary
Best Bets
Search Results
Search 的 .NET 端口的體系結(jié)構(gòu)與基于 ASP 的版本相同(參見圖 1)。下面讓我們深入了解一下各個(gè)組件。
圖 1.用戶提交查詢后,(1) 將查詢先提交給解析器 (Parser) 進(jìn)行詞條分割和詞匯解析,(2) 將找到的項(xiàng)目的顯示術(shù)語 (Display Term) 傳給 Best Bets,(3) 將找到的項(xiàng)目的首選術(shù)語 (Preferred Term) 和剩余項(xiàng)目傳給 Search Results,(4) 使用 XSL 樣式表編譯生成的 XML 文檔,(5) 給用戶的 Web 瀏覽器提交 HTML。單擊以放大。
Word Parsing and Vocabulary _ 這是一個(gè)包含一個(gè) C++ COM 對象的 Windows 腳本組件,它暴露出 Search 中所支持的所有語言的各種詞條分割程序。這種設(shè)計(jì)之所以必要是因?yàn)樵~條分割程序的接口不容易編寫成腳本,并且通常需要一種 C++ 可編腳本的封裝(盡管這是有辦法做到的:以后將對此進(jìn)行詳細(xì)解釋)。在向 .NET 框架移植的過程中,我們使用了 C++ 對象上的類型列表導(dǎo)出程序 (TLBIMP.EXE),并通過 .NET 中的 Interop 技術(shù)對其進(jìn)行調(diào)用,這樣您就可以調(diào)用現(xiàn)有的 COM 對象了。
Vocabulary Object 運(yùn)行 Xpath(查詢 XML 文檔的語言)查詢,以便將搜索詞條映射到首選術(shù)語。它同時(shí)去除了干擾詞條,并產(chǎn)生一種格式化的數(shù)據(jù)結(jié)構(gòu),適合于 Best Bets 和 Search Results 組件進(jìn)行消耗。一項(xiàng)重要成果是,這個(gè)相當(dāng)復(fù)雜的小腳本得以移植到 C#,我們還可以繼續(xù)從中調(diào)用傳統(tǒng)對象。下面是 Vocabulary Object 中的一個(gè)小代碼示例:
// We return an array of VocabularyObjects after parsing the user's search
// text. This ability to create simple typed structures in C# vastly improves
// our code modularity and self-documentation. Here is the definition of
// VocabularyObject:
public struct VocabularyObject {
public string PREFERREDTERM; // structure members
public string DISPLAYTERM;
public bool FOUND;
public string ORIGPHRASE;
public bool MULTITERM;
public bool MULTIWORD;
// Constructor
public VocabularyObject(string preferredterm,bool found,string origphrase,
bool multiterm,bool multiword,string displayterm) {
PREFERREDTERM = preferredterm;
FOUND = found;
ORIGPHRASE = origphrase;
MULTITERM = multiterm;
MULTIWORD = multiword;
DISPLAYTERM=displayterm;
}
}
// Example usage. Because the parameters to the objects constructor are
// typed, we'll get a compiler error message if we passed an integer
// where a string was expected, for example. This is a very nice feature
// over traditional scripting environments!
VocabularyObject vo("Microsoft DirectX",true,"dx",false,false,"DirectX");
.NET 環(huán)境的其中一個(gè)優(yōu)點(diǎn)就是,您可以創(chuàng)建用于整個(gè)代碼的多數(shù)據(jù)結(jié)構(gòu)。上面最后一行是闡明如何使用這些 Vocabulary Object 的代碼結(jié)構(gòu)的語句實(shí)例。
Best Bets _ 這是一個(gè)小腳本組件,它可提供對本地化 XML 文檔的 XPath 查詢,并可產(chǎn)生加按語的 URL 鏈接。XML 文檔裝載于每個(gè) Search 應(yīng)用程序?qū)嵗膽?yīng)用范圍,并既可單獨(dú)工作,又可與 Vocabulary 對象的方法緊密耦合。移植小腳本是 100% 向 .NET 框架的轉(zhuǎn)換,并可利用 System.IO 和 XML DataNavigator 類 (System.NewXml 命名空間)。
這是最簡單的移植組件。它幾乎是行對行地從 Jscript 向 C# 的轉(zhuǎn)換。我們僅在某些地方對代碼作了一些更改,以便利用新的 XML DataNavigator 類 - 用來查詢并更新 XML 文檔的 .NET 通用語言運(yùn)行時(shí)間部分。
Search Results - 這一復(fù)雜的組件與 Site Server 3.0 相接,從而獲得與客戶的搜索查詢相匹配的實(shí)際頁面描述和鏈接。它還包含一種完善的緩存算法。
構(gòu)建并行解決方案
當(dāng)時(shí)我們遇到的最大挑戰(zhàn)是,我們在開發(fā) Search 2.5 的同時(shí),也在將整個(gè) Search 應(yīng)用程序移植到 .NET 框架的 ASP+ 技術(shù)。由于要在 PDC 日期之前推出此應(yīng)用程序并將其移植到 .NET,周轉(zhuǎn)時(shí)間緊,因此我們當(dāng)時(shí)決定同時(shí)推出這兩種版本,并將它們同時(shí)上市。很明顯,這是一項(xiàng)艱巨的任務(wù),因?yàn)槲覀儽仨毠芾硇碌陌姹荆私庑滦?.NET 框架的所有功能和新的語言隱喻,構(gòu)建具有各種軟件平臺(tái)服務(wù)的服務(wù)器,等等。
關(guān)于我們是如何搞成這個(gè)項(xiàng)目的,還有一段有趣的故事呢。為了確保同時(shí)推出兩種版本(Search 2.5 和 .NET 框架,我們在項(xiàng)目規(guī)劃階段確定了首先把握住哪些組件不變、哪些組件在開發(fā)過程中變化最大以及哪些組件適合于哪種技術(shù)和語言。
我們還及早確定目標(biāo),努力分解此應(yīng)用程序,并按照客戶可能會(huì)采用的方式移植。因?yàn)槲覀?microsoft.com 的人總是認(rèn)真對待客戶在進(jìn)行技術(shù)決策和研究投資回報(bào)時(shí)面臨的各種問題,所以,我們將此應(yīng)用程序移植過程分解成許多部分,每個(gè)部分都盡可能與客戶可能采取的方法接近。我們希望確保做好每項(xiàng)工作,其中包括最簡單的移植(即,小腳本移植到 Jscript 類)直到最大的時(shí)間和技術(shù)利益投入 – 充分利用 C# 編程語言完全移植到 .NET 框架 (100% 可管理的代碼空間)。
下面是我們在應(yīng)對這個(gè)挑戰(zhàn)時(shí)所采取的一些步驟:
首先,我們將主要的 ASP 頁面轉(zhuǎn)換為 ASP+。最初,我們是通過 .NET Reflection 技術(shù)調(diào)用小腳本,這樣我們可以在運(yùn)行時(shí)通過查詢類型庫來調(diào)用典型的 COM 對象。
重要知識(shí):我們從具有 ASP 的編程模型出發(fā)(其中,數(shù)據(jù)、業(yè)務(wù)邏輯以及表示全都被混合在一起),然后采用 ASP+ 的一種完全面向?qū)ο蟮姆椒?,最后是?shù)據(jù)分離、編程以及 UI。
其次,處理最簡單的小腳本并將其移植。BestBets 是最簡單的組件,并且不依賴于 COM 組件。我們決定使用 System.IO、XML Data Navigator 以及 C# 編程語言將這個(gè)組件作為 DLL 移植。我們希望將這個(gè)組件完全移植到受控環(huán)境,并使其充分利用 XML Data Navigator。
重要知識(shí):我們了解了 NewXml 命名空間。同時(shí),我們在移植組件時(shí)去除了 .NET Reflection。這樣我們就可以在本地調(diào)用這些組件。
然后,我們以同樣方式處理 Vocabulary 小腳本。這個(gè)組件在復(fù)雜性和代碼行方面處于此應(yīng)用程序的中間。它由一個(gè)小腳本組成,這個(gè)小腳本包含用于 Search 的業(yè)務(wù)和文本解析規(guī)則,并對 C++ 組件進(jìn)行調(diào)用,我們創(chuàng)建該組件的目的是包裝 COM 對斷字程序的引導(dǎo)調(diào)用。這個(gè)組件在移向受控空間方面具有最大優(yōu)點(diǎn)。這個(gè)復(fù)雜組件被全部移植到 .NET 框架和 C# 編程語言。這需要一些技巧,因?yàn)椋鼮閺?fù)雜的函數(shù)邏輯,并需要利用一個(gè)自定義 COM 對象。但這還不算太難。下一步將拋棄 C++ 包裝并直接調(diào)用這些接口。
重要知識(shí):我們更改了函數(shù)和邏輯以便受益于象類型安全這樣的 C# 的關(guān)鍵優(yōu)勢。在使用 Jscript 時(shí),開發(fā)人員必須銘記每個(gè)變量的類型(整數(shù)、字符串)。C# 會(huì)為您做到這一點(diǎn)。所有變量在聲明時(shí)確定,并且 C# 會(huì)檢查您的工作以便確保沒有越界。這在處理復(fù)雜代碼時(shí)幫助很大。備注: 在 JScript 的下一個(gè)版本中,程序員將可以選擇完全確定變量的類型。
移植最終組件:SearchResults。最初,我們通過 .NET Reflection 調(diào)用這個(gè)組件,而且情況良好。由于這個(gè)代碼太大并相當(dāng)復(fù)雜,同時(shí)由于在我們推出 Search 2.5 版本之前對該版本作了一些根本性的更改,因此移植該代碼的工作一直持續(xù)到現(xiàn)在。在 .NET 測試版中找不到它,但該項(xiàng)工作已取得重大進(jìn)展。10 月份晚些時(shí)候?qū)l(fā)布該版本的更新。
總之,這個(gè)體系結(jié)構(gòu)是一個(gè)杰作。我們擁有一些真正的 C# .NET 組件,我們擁有所有的 ASMX 頁面。而且,我們演示了可以通過 Interop 調(diào)用自定義 COM 對象,以及通過 .NET Reflection 調(diào)用小腳本。傳統(tǒng)的對象(比如,SearchResults)可以消耗由 C# 對象(比如,Vocabulary) 創(chuàng)建的數(shù)據(jù)結(jié)構(gòu),這是非常好的事。
在您審查 .NET Search 測試版之前值得一提的是,這個(gè)體系結(jié)構(gòu)中沒有用戶界面。您所看到的是一項(xiàng) Web 服務(wù)的默認(rèn)情況。我們本來是可以添加一個(gè) UI 的,但是我們之所以保留成現(xiàn)在這樣,是想讓您看到其本來面目。