簡介
使用 Microsoft SQL Server 2000 的全文檢索搜尋功能,可以對在非結構化文本資料上產生的索引執行快速、靈活的查詢。常用的全文檢索搜尋工具是網站的搜尋引擎。為了協助讀者理解全文檢索搜尋功能的最佳使用方法,本文介紹了大量抽象概念;並對最佳化全文索引和查詢以實現最大吞吐率和最佳效能,提供了幾點提示和技巧。
全文檢索搜尋功能簡介
全文檢索搜尋功能在 SQL Server 7.0 中引入。全文檢索搜尋的核心引擎建立在 Microsoft Search (MSSearch) 技術上,Microsoft Exchange 和 Microsoft SharePoint Portal Server 等產品中也採用了此項技術。
SQL Server 7.0 全文檢索搜尋中公開的功能可提供基本的文本搜尋功能,並使用早期版本的 MSSearch;而 SQL Server 2000 的全文檢索搜尋實現則包含一組可靠的索引和查詢功能,並在 SQL Server 7.0 的基礎之上添加了幾項增強功能。這些增強功能包括:通過 Microsoft 叢集服務完全支援群集操作,能夠過濾和索引 IMAGE 列中儲存的文檔,提供改進的語言支援,以及在效能、可縮放性和可靠性方面進行了改進。
MSSearch 產生、維護和查詢檔案系統中(而不是 SQL Server 中)儲存的全文索引。MSSearch 進行全文索引時使用的邏輯和實體儲存體單元是目錄。全文檢索目錄在每個資料庫中包含一個或多個全文索引 - 可以為 SQL Server 中的每個表建立一個全文索引,且索引中可以包含該表中的一列或多列。每個表只能屬於一個目錄,且每個表只能建立一個索引。我們將簡單介紹有關組織全文檢索目錄和索引的最佳方案 - 但首先,讓我們來簡單瞭解一下全文檢索搜尋的工作原理。
配置全文檢索搜尋功能
要為 SQL Server 中儲存的文本資料建立全文索引,應該先完成以下幾步準備工作。第一步是以全文方式啟用包含要產生索引的文本資料的資料庫(如果您尚未執行此操作)。
注意:
執行以下語句將丟棄並重新建立屬於要啟用全文檢索搜尋的資料庫的所有全文檢索目錄。除非要重新建立全文檢索目錄,否則請確保在要啟用的特定資料庫中未建立任何全文檢索目錄。
如果您是 sysadmin 角色的成員或此資料庫的 db_owner,可以繼續進行並發出以下語句:
use Northwind exec sp_fulltext_database 'enable'
接下來,您需要建立全文檢索目錄,以儲存全文索引。正如前面所提到的,此目錄中的資料存放區在檔案系統中(而不是 SQL Server 中),因此,在考慮全文檢索目錄的儲存位置時應該仔細選擇。除非指定其他位置,否則全文檢索目錄將儲存在 FTDATA 目錄(位於 Microsoft SQL Server/MSSQL 儲存位置中)的子目錄中。以下是在非預設位置建立全文檢索目錄的方法:
exec sp_fulltext_catalog 'Cat_Desc', 'create', 'f:/ft'
在本例中,全文檢索目錄將建立為“f:/ft”的子目錄,如果您查看檔案系統的該部分,將看到它有了自己的目錄。MSSearch 使用的全文檢索目錄的命名規則是:
SQL+dbid+catalogID
目錄 ID 從 00005 開始,並且每建立一個目錄就遞增 1。
如果可能的話,最好在其所在的物理磁碟機上建立全文檢索目錄。如果產生全文索引的進程需要進行大量的 I/O 操作(具體而言,就是從 SQL Server 中讀取資料,然後向檔案系統寫入索引),則應避免使 I/O 子系統成為瓶頸。
那麼,全文檢索目錄有多大呢?通常情況下,全文檢索目錄的系統開銷比 SQL Server 中儲存的資料(對其進行全文索引)量高出大約 30%;但是,此規則取決於資料中唯一單詞(或主鍵)的分布,以及被您視為是非搜尋字的單詞的分布。非搜尋字(或終止詞)是指要排除在全文索引和查詢以外的詞語(因為它們不是您感興趣的搜尋字詞,而且出現頻率很高,所以只會使索引變得很大,而不會有實際效果)。稍後,我們將介紹有關非搜尋字選擇方面的注意事項,以及如何最佳化非搜尋字以改善查詢效能。
如果您尚未執行此操作,請在每個要產生全文索引的表上建立一個唯一的單列非空索引。這個唯一索引用於將表中的每一行映射到 MSSearch 內部使用的一個唯一可壓縮主鍵。接下來,您需要讓 MSSearch 知道您要為表建立全文索引。對錶發出以下語句可將該表添加到所選的全文檢索目錄中(在本例中,它是我們在前面建立的“Cat_Desc”):
exec sp_fulltext_table 'Categories', 'create', 'Cat_Desc', 'PK_Categories'
下一步是向此全文索引添加列。您可以為每一列選擇一種語言,如果該列的類型為 IMAGE,則必須再指定一列,以指示 IMAGE 列的每一行中儲存的文件類型。
在列語言選擇方面,有一些重要但尚未成文的注意事項。這些注意事項與文本的標記方式以及 MSSearch 對文本的索引方式有關。被索引的文本是通過一個稱作單詞分隔字元(用作單詞邊界標記)的組件提供的。在英文中,單詞分隔字元通常是空格或某種形式的標點符號;而在其他語言中(例如德語),單詞或字元可以組合在一起;因此,所選的列語言應表示要儲存在該列的行中的語言。如果不確定,最好的方法通常是使用中性單詞分隔字元(只使用空格和標點符號執行標記功能)。選擇列語言的另一個好處是“尋根溯源”。全文檢索查詢中的尋根溯源是指在特定語言中搜尋某一單詞的所有變化形式的過程。
選擇語言的另一個考慮因素與資料的表示方法有關。對於非 IMAGE 列資料來說,不需要執行特殊的過濾操作;而文本通常需要將單詞分隔組件按原樣傳遞。單詞分隔字元主要用於處理書面文本。因此,如果文本中有任何類型的標記(例如 HTML),則在索引和搜尋過程中,語言精確性將不會很高。這種情況下,您有兩種選擇 - 首選方法是只將文本資料存放區在 IMAGE 列中,並指明其文件類型,以便對其進行過濾。如果不選擇此方法,則可以考慮使用中性單詞分隔字元,並且可能的話,在非搜尋字列表中委任標記資料(例如 HTML 中的“br”)。在指定了非語言相關的列中不能進行任何基於語言的尋根溯源,但有些環境可能會要求您選擇此方法。
在知道列選項後,通過發出以下語句在全文索引中添加一列或兩列:
exec sp_fulltext_column 'Categories', 'Description', 'add'
您可能注意到,此處未指定任何語言 - 這種情況下,將使用預設的全文語言。可以通過系統預存程序“sp_configure”為伺服器設定預設全文語言。
將所有列添加到全文索引後,即可執行填充操作。填充方法之多實在是不勝枚舉,此處不作詳細介紹。在本例中,只需對錶啟動完全填充,並等待它執行完畢:
exec sp_fulltext_table 'Categories', 'start_full'
您可能希望使用 FULLTEXTCATALOGPROPERTY 或 OBJECTPROPERTY 函數來監視填充狀態。要擷取目錄填充狀態,可以執行:
select FULLTEXTCATALOGPROPERTY('Cat_Desc', 'Populatestatus')
通常情況下,如果完全填充進行中,則返回的結果是“1”。有關如何使用 FULLTEXTCATALOGPROPERTY 和 OBJECTPROPERTY 的詳細資料,請參閱 SQL Server Books Online。
全文檢索查詢
查詢全文索引與執行 SQL Server 中的標準關係型查詢略有不同。由於索引是在 SQL Server 外部進行儲存和管理的,因此全文檢索查詢處理大部分由 MSSearch 完成(因此,那些一部分是關係型、一部分基於全文的查詢將被單獨處理),這樣做有時會損害效能。
從本質上說,執行全文檢索查詢時,查詢詞傳遞給 MSSearch,後者遍曆其內部資料結構(索引),並向 SQL Server 返回主鍵和排位值。如果執行 CONTAINS 或 FREETEXT 查詢,則通常看不到主鍵或排位值,但如果執行 CONTAINSTABLE 或 FREETEXTTABLE 查詢,則將獲得這些值,然後這些值通常會與基表合并在一起。與基表合并主鍵的進程需要很高的系統開銷 - 稍後,我們將向您介紹一些巧妙的方法以盡量減少或完全避免這種合并。
如果您通過不斷思考,對全文檢索查詢如何返回資料有了一個初步瞭解,就可以推測出 CONTAINS/FREETEXT 查詢僅執行 CONTAINSTABLE/FREETEXTTABLE 查詢並與基表進行合并。有了這樣的瞭解,您應該避免使用這些類型的查詢,除非不這樣做的開銷更高。在 Web 搜尋應用程式中,使用 CONTAINSTABLE 與 FREETEXTTABLE 比使用不帶 TABLE 的同類函數好得多。
到現在為止,您已經知道全文檢索查詢是用來從 SQL Server 之外儲存的 MSSearch 索引中訪問資料的特殊方法,還知道如果盲目地與基表進行合并,就會遇到麻煩。應該瞭解的另外一個重要內容是 CONTAINS 樣式查詢與 FREETEXT 樣式查詢之間的本質差別。
CONTAINS 查詢用於對所查詢的所有詞語執行完全符合查詢。無論您只尋找單個單詞,還是尋找以“orange”開頭的所有單詞,系統只返回包含所有搜尋字詞的結果。因此,CONTAINS 查詢速度很快,因為它們通常返回很少的結果,並且不需要執行過多的附加處理。CONTAINS 查詢的缺點包括令人生厭的非搜尋字過濾問題。經驗豐富的開發人員以及過去使用過全文檢索搜尋的資料庫管理員,在試圖匹配只包含單個非搜尋字的單詞或片語時,曾遇到過“您的查詢只包含非搜尋字”這樣令人吃驚的錯誤。要避免收到此錯誤,方法之一是在執行全文檢索查詢之前過濾出非搜尋字。向包含非搜尋字的 CONTAINS 查詢返回結果是不可能的,因為此類查詢只返回與整個查詢字串完全符合的結果。由於非搜尋字不是全文索引項目,因此包含非搜尋字的 CONTAINS 查詢不會返回任何行。
FREETEXT 查詢消除了 CONTAINS 查詢中偶爾出現的所有警告說明。當發出 FREETEXT 查詢時,實際上發出的是詞根查詢。因此,當您搜尋“root beer”時,“root”和“beer”包含其所有形式(尋根溯源與語言相關;所用的語言由產生索引時指定的全文列語言確定,並且在所有查詢的列中必須相同),並且系統將返回至少與這些詞語之一匹配的所有行。
FREETEXT 查詢的負面影響是它們通常比 CONTAINS 查詢耗用更多的 CPU - 因為要尋根溯源以及返回更多的結果,就需要包含更複雜的排位計算。不過,基於 FREETEXT 的查詢非常靈活,而且速度非常快,是基於 Web 的搜尋應用程式中通常使用的最佳選擇。
排位和最佳化
我經常遇到使用全文檢索搜尋的使用者,他們問我排位編號是什麼意思,以及如何將排位編號轉換成某種使用者可以理解的值。對這個問題,回答可長可短,在這裡我將進行簡要回答。簡單而言,這些排位編號不如結果返回的順序那樣重要。也就是說,當您按照排位對結果進行排序時,總是首先返回關聯程度最高的結果。排位值本身常常變化 - 全文檢索搜尋使用機率排位演算法,即返回的每個文檔的關聯性受全文索引中的任何或所有其他文檔的直接影響。
有些人認為,一種有助於增加某些行排位的技巧是在這些行的全文索引列中重複常用的搜尋索引鍵。儘管在某種程度上,這種方法可能會提高這些行因某些關鍵字而首先返回的幾率,但在其他情況下,可能會適得其反 - 而且還存在使詞語查詢效能降低的風險。較好的解決方案是為搜尋應用程式實現“最佳選擇”系統(請參閱以下樣本),這樣就可以確保首先返回某些文檔。多次重複使用關鍵字會使這些特定關鍵字的全文索引擴大,並使得 MSSearch 在尋找正確行和計算排位時浪費時間。如果全文索引資料量很大,並嘗試使用了此方法,您可能會發現某些全文檢索查詢很耗時。如果能夠實現更細緻(也可能更精確)的“最佳選擇”系統,您會發現它明顯改善了查詢效能。
多次重複資料的另一個問題與用於組合關係型查詢和全文檢索查詢的常用技巧有關。許多使用全文檢索搜尋的使用者都深受此問題的困擾,每當他們試圖將某種過濾器應用於全文檢索查詢返回的結果時,便會遇到這樣的問題。正如前面所說的,全文檢索查詢為每個匹配行返回一個主鍵和一個排位 - 要收集有關這些行的任何詳細資料,必須與它的基表進行合并。由於從無限制的全文檢索查詢中可能會返回任意數量的結果,因此合并可能需要大量系統開銷。人們發現避免合并的一個有效方法是只在全文索引中添加要過濾的資料(如果可能)。換句話說,如果使用者要從報紙上所有文章的本文中搜尋索引鍵“Ichiro”,並且只希望返回該報上體育專欄中的文章,則查詢語句通常如下所示:
-- [方法 1:]-- 開銷最高:先全部選擇,然後再合并和過濾SELECT ARTICLES_TBL.Author, ARTICLES_TBL.Body, ARTICLES_TBL.Dateline, FT_TBL.[rank] FROM FREETEXTTABLE(Articles, Body, 'Ichiro') AS FT_TBLINNER JOIN Articles AS ARTICLES_TBLON FT_TBL.[key] = ARTICLES_TBL.ArticleIDWHERE ARTICLES_TBL.Category = 'Sports'-- [方法 2:]-- 可以使用,但會導致意外結果並變慢,或者會返回不準確的結果: -- 執行全文過濾,並且只提取主鍵和排位-- (處理在 Web 服務器上完成)SELECT [key], [rank] FROM CONTAINSTABLE(Articles, *, 'FORMSOF(INFLECTIONAL('Ichiro') AND "sports"')
這兩個查詢要麼不必要地佔用大量系統開銷,要麼存在返回錯誤結果的可能性(在第二個查詢中,“sports”很可能出現在所有類型的文章中)。這兩項技術還存在其他變體,但這是兩種非常簡單的模型。如果可行,我通常建議您對資料進行水平劃分。即,“類別”列的每個可能值都自成一列(或表),並且與該文章相關的可搜尋索引鍵僅儲存在此列中。採用此方法,而不是使用一個“本文”列和一個“類別”列,可以去掉“類別”列,而使用儲存可搜尋索引鍵的“Body_<category>”列。如以下樣本所示:
-- 如果您可以調整架構,這非常有效 – 每個類別-- 都成為自己的列(或表格),並且需要命中的-- 全文索引也較少。這明顯需要作一些解釋……SELECT [key], [rank] FROM FREETEXTTABLE(Articles, Body_Sports, 'Ichiro')
對於包含大量資料,且這些資料可適應此架構(或許是主架構)更改的系統,其效能會得到顯著的提高。但在何時應用多個過濾器或不應用過濾器方面卻有著明顯的限制。當然,還有其他的方法可以解決這些問題。通過以上樣本,您會瞭解一種將某些搜尋條件抽象到架構的方法 - 實際上是“欺騙”最佳化程式(更確切的說是“成為”最佳化程式),因為在 SQL Server 本身的全文檢索查詢中當前不存在本地最佳化。
其他效能技巧
人們在聊天時常常問我的另一個問題是如何才能分頁顯示全文檢索查詢結果。換句話說,如果我要發出“root beer”查詢,一次在某一 Web 頁上顯示 40 個結果,並且只希望返回該頁面上的 40 個結果(例如,如果我在第三頁,我希望僅返回第 81 至第 120 條結果)。
對於分頁顯示結果,我曾見過多種方法,但沒有一種方法能夠做到百分之百有效。我所推薦的方法可以最大程度地減少全文檢索查詢執行的次數(實際上,對於要分頁顯示的每個結果集只需執行一次),並將 Web 服務器用作一個簡單的緩衝。從更高的層面來講,您只需在全文檢索查詢中檢索一個完整的主鍵和排位值行集合(如果需要,可以在架構中使用最佳選擇並提取常用過濾器),並將其儲存在 Web 服務器的記憶體中(這取決於您的應用程式和負載,想象將 <32 位元組的典型主鍵大小與 <4 位元組的排位大小相加 [等於 <36 位元組],然後乘以通常返回的結果集 <1000 行,最後等於 <35K。假定一個在任何給定時間返回 <1000 個活動查詢結果集中的一個主動式快取集,您將發現此主動式快取集在 Web 服務器上佔用的記憶體少於 35MB - 這還可以接受)。
為了分頁顯示結果,該進程只遍曆 Web 服務器的記憶體中儲存的數組,並對 SQL Server 發出 SELECT 以便只顯示需要顯示的行和列。這又回到了全文檢索查詢僅返回主鍵和排位的概念中 - SELECT(甚至許多這樣的查詢語句)比全文檢索查詢的速度快許多倍。使用 SELECT 而不是與基表合并多個行,並結合多個其他策略,您可以保留 SQL Server 電腦上更多的 CPU 週期,並且更有效、更划算地利用 Web 領域。
另一種可以替代 Web 服務器端緩衝的方法是在 SQL Server 自身中緩衝結果集,並定義多種用於瀏覽這些結果的方法。雖然本文著重說明 Web 服務器 (ASP) 層級的應用程式設計,但 SQL Server 的可程式化功能還為產生高效能的 Web 搜尋應用程式提供了強大的架構。
小結
Microsoft SQL Server 2000 的全文檢索搜尋功能為索引和查詢資料庫中儲存的非結構化文本資料提供了可靠、快速而靈活的方法。如果要廣泛地將這種快速、準確的搜尋功能應用於各種應用程式,那麼很有必要充分利用其速度和精確性,來實現全文檢索搜尋解決方案。通過分布計算負載並通過某些巧妙的方式對資料進行組織,可以省下錢來購買其他硬體和軟體,以擺脫因不必要的緩慢查詢帶來的困擾。在開發優秀的搜尋應用程式時,通常要考慮到許多因素和注意事項,希望本文提供的資訊和樣本對您學習使用 SQL Server 2000 產生出色的 Web 搜尋應用程式會有所協助。
附錄 A:實現全文檢索搜尋功能的最佳選擇
改進全文檢索查詢效能和有效性的一種可行方法是實現“最佳選擇”系統。此系統是一種很簡單的方法,可確保某些與特定查詢運算式匹配的行先於其他行返回。最佳選擇沒有複雜的預編程邏輯(例如,SharePoint Portal Server 就包含這樣的邏輯),因此,通常是首選辦法。
在本樣本中挑選出最佳選擇,並將唯一的主鍵和一些關鍵字儲存在單獨的表中。FREETEXTTABLE 查詢對(非常小的)最佳選擇表執行,並且從該查詢中返回的任何結果都與對基表的 FREETEXTTABLE 查詢結果一同返回。在給定這些搜尋條件下,最先返回的將是所有“最佳選擇”行,隨後是被 MSSearch 視為關聯程度最高的行(以遞減順序返回)。
下面是一個非常簡單的用於建立最佳選擇系統的樣本指令碼。
use myDbcreate table documentTable(ftkey int not null, document ntext)create unique index DTftkey_idx on documentTable(ftKey)/* 在此插入文檔 (要產生全文索引的所有文檔)*/-- 為所有文檔表建立全文檢索目錄和索引exec sp_fulltext_catalog 'documents_cat', 'create', 'f:/ftCats'exec sp_fulltext_table 'documentTable', 'create', 'documents_cat', 'DTftkey_idx'exec sp_fulltext_column 'documentTable', 'document', 'add'exec sp_fulltext_table 'documentTable', 'start_change_tracking'exec sp_fulltext_table 'documentTable', 'start_background_updateindex'/* 現在建立最佳選擇表和索引 (添加應該始終最先返回的文檔)*/create table bestBets(ftKey int not null, keywords ntext)create unique index BBftkey_idx on bestBets(ftKey)/* 在此插入最佳選擇*/-- 為最佳選擇表建立全文檢索目錄和索引exec sp_fulltext_catalog 'bestBets_cat', 'create', 'f:/ftCats'exec sp_fulltext_table 'bestBets', 'create', 'bestBets_cat', 'BBftkey_idx'exec sp_fulltext_column 'bestBets', 'keywords', 'add'exec sp_fulltext_table 'bestBets', 'start_change_tracking'exec sp_fulltext_table 'bestBets', 'start_background_updateindex'
首先建立了一個通用的“所有文檔”表,用於儲存所有要全文索引的文檔。通常情況下,文檔表中包含其他列,但在本文中,只包含兩列 - 主鍵索引和文檔本身。全文檢索目錄和索引是為文檔表而建立的。
接著建立了“最佳選擇”表,用於儲存所有全文檢索查詢中首先返回的特殊文檔。此表只需具有全文主鍵列和文檔本身(對將某些文檔作為查詢目標的策略進行最佳化,包括在該文檔本身不包含的文檔中添加其他關鍵字)。全文檢索目錄和索引是為最佳選擇表而建立的。
最佳選擇表和文檔表可以共用文檔(最佳選擇文檔還儲存在常規文檔表中,它們共用同一個主索引值),也可以相互排斥(最佳選擇文檔只儲存在最佳選擇表中)。為便於檢索,使最佳選擇表與文檔表互斥更為容易 - 這樣做就無需從最佳選擇和返回的普通搜尋結果行集合中刪除共用操作。另一方面,使用此方法維護文檔可能很難實現,因為在此方法中,要在查詢中添加邏輯來刪除返回的行集合之間的共用文檔。
如果給定上面的表,則可以建立兩個預存程序,以便對最佳選擇表和文檔表進行搜尋。可使用 Web 服務器層級的邏輯或其他預存程序來緩衝和顯示所需結果(與最佳選擇一起使用時,請參閱下面有關緩衝、顯示和分頁的一個完整、有效樣本)。
首先,建立一個用於檢索最佳選擇行(如果有)的預存程序:
create procedure BBSearch @searchTerm varchar(1024) asselect [key], [rank] from freetexttable(bestBets, keywords, @searchTerm) order by [rank] desc
確保已對傳入搜尋字串進行清理,以避免在伺服器上隨意執行 T-SQL,並確保用單引號將該字串括起。這種情況下,使用 FREETEXTTABLE 比使用 CONTAINSTABLE 要好,因為 FREETEXTTABLE 將採用尋根溯源功能,並找到與任何搜尋字詞相匹配的最佳選擇。
接下來,第二個預存程序檢索與常規搜尋標準匹配的文檔(如果有):
create procedure FTSearch @searchTerm varchar(1024) asselect [key], [rank] from freetexttable(documentTable, keywords, @searchTerm) order by [rank] desc
此外,請確保已清理傳入搜尋字串,並用單引號將該字串括起。
執行這些預存程序時,應該在兩個預存程序中傳入相同的搜尋字詞,首先執行最佳選擇搜尋,然後執行普通全文檢索搜尋。下一節更全面地介紹了在構建 Web 搜尋應用程式時,如何與其他全文檢索搜尋技術一起使用最佳選擇。
附錄 B:使用最佳選擇、結果分頁和有效全文檢索查詢邏輯的應用程式範例
在本例中,我們實現了一個幾乎利用了本文介紹的所有最佳化方案的 Web 搜尋應用程式。我們對聯機零售商目錄使用簡單的搜尋引擎方案,並假定在通訊量很高的情況下,所有使用者都期待在很短的回應時間內獲得結果。本樣本使用了前一節中的最佳選擇表和預存程序。
此應用程式只是一些可用於實現最佳全文檢索搜尋效能的進階策略的簡單樣本。本樣本使用了 ASP,也可使用 ISAPI、ASP.NET 或其他平台來實現具有各自優缺點的類似解決方案。會話對象並不一定對所有應用程式都適用,如果使用不當,可能帶來一定程度的危險。在本例中,我們使用會話對象來實現快速有效緩衝機制 - 當然還有許多其他方法可以在不同程度上實現該功能。
下面是 ASP 頁的通用代碼:
<% @Language = "VBScript" %><% Response.buffer = true %><html> <head> <title>FT 測試</title></head> <body><pre>----------------- 開始測試 ------------------<%Dim firstRow ' 分頁顯示行時的第一行Dim lastRow ' 分頁顯示行時的最後一行Dim pageSize ' 頁面大小(每次的行數)Dim cn ' 連線物件Dim rs ' FT 主鍵/排位返回的結果集(重複使用)Dim useCache ' 使用緩衝或命中 FT(0:不使用;1:使用)Dim alldata ' 要緩衝的結果行集合Dim bbdata ' 要緩衝的最佳選擇行集合Dim connectionString ' SQL 連接字串' 確定是否要從緩衝擷取資料' 預設為否,否則接受傳入的資料if (request.Form("useCache") <> "") then useCache = request.Form("useCache")elseif (request.QueryString("useCache") <> "") then useCache = request.QueryString("useCache")else useCache = 0end if' 設定常量pageSize = 24firstRow = 0lastRow = 23connectionString = <在此輸入您的連接字串>'----------------------------------------------------------------'' 顯示與最佳選擇/搜尋字詞匹配的簡單主鍵/排位 ''----------------------------------------------------------------'Private Sub SearchNPage() Dim p ' 迴圈通過行時的計數器 Dim numRows ' 緩衝/結果集中的總行數 if (useCache <> "1") then ' 擷取最佳選擇/結果並將其緩衝 Dim queryArg ' 傳入的查詢詞 if (request.Form("searchTerm") <> "") then queryArg = request.Form("searchTerm") elseif (request.QueryString("searchTerm") <> "") then queryArg = request.QueryString("searchTerm") else response.Write("未提供搜尋字詞" & VbCrLF) exit sub end if ' 理想情況下,應該在此清理查詢詞... ' 添加自訂的清理邏輯,以防止 ' 隨意執行 SQL ' 調用 CleanString(queryArg) ' 建立與 SQL 的串連 Set cn = Server.CreateObject("ADODB.Connection") cn.Open connectionString ' 從傳入的乾淨字串中擷取最佳選擇匹配項 set rs = cn.Execute("exec BBSearch '" & queryArg & "'") ' 如果有最佳選擇,則擷取最佳選擇 if not(rs.EOF) then bbData = rs.GetRows end if ' 現在從傳入的乾淨字串中擷取普通匹配項 set rs = cn.Execute("exec FTSearch '" & queryArg & "'") ' 如果未返回任何結果,則結束 if (rs.EOF and IsEmpty(bbdata)) then response.Write("沒有匹配的行" & VbCrLF) call ConnClose exit sub end if ' 否則,擷取行 if not(rs.EOF) then alldata = rs.GetRows Session("results") = alldata end if call ConnClose else ' 從緩衝載入 (usecache=1) alldata = Session("results") ' 在此擷取要使用的行範圍 if (request.Form("firstRow") <> "") then firstRow = request.Form("firstRow") lastRow = firstRow+pageSize elseif (request.QueryString("firstRow") <> "") then firstRow = request.QueryString("firstRow") lastRow = firstRow+pageSize end if end if ' useCache<>TRUE ' 對於本應用程式,只是列印出所有最佳選擇 ' (可能比頁面大小大),然後分頁顯示普通結果 ' 此處假設:在使用緩衝時,如果沒有新的最佳選擇,' 則使用以前顯示的最佳選擇 if not(IsEmpty(bbdata)) then response.Write("最佳選擇:" & VbCrLf) for p = 0 to ubound(bbdata, 2)response.Write(bbData(0,p) & " " & bbData(1,p) & VbCrLf) next response.Write(VbCrLf) end if ' 返回搜尋結果(可能只有最佳選擇) if not(IsEmpty(alldata)) then if uBound(alldata, 2) < lastRow then lastRow = uBound(allData, 2) end if response.Write("搜尋結果:" & VbCrLf) for p = firstRow to lastRowresponse.Write(allData(0,p) & " " & allData(1,p) & VbCrLf) next end if ' not(IsEmpty(alldata))End Sub'----------------------------------------------------------------'' 關閉並清除連線物件 ''----------------------------------------------------------------'Private Sub ConnClose rs.Close Set rs = Nothing cn.Close Set cn = NothingEnd Subcall SearchNPage%>---------------- 測試結束 ----------------<form action="<本頁>" method="post"><input type=submit value="next <%=pageSize%> rows" NAME="Submit1"><input type=hidden name="useCache" value="1"><input type=hidden name="firstRow" value=<%=lastrow+1%>></form></pre> </body></html>一個簡單的 HTML 表單頁面即可像下面一樣利用上面的指令碼:<html><head><title>輸入搜尋字詞</title></head><body><form action="<搜尋 ASP 頁面>" method="post">搜尋字詞:<input name="searchTerm"><p><input type="submit" value="Search"></form></body></html>
正如以上兩個程式碼範例所示,建立可執行有效全文檢索查詢(用最佳選擇完成)並緩衝和分頁顯示結果的 Web 應用程式,並不需要花費太多的工夫。只需使用最低的系統開銷,即可添加用於提供其他資料、增強最佳選擇的外觀以及在搜尋結果中導航的邏輯(此外,強烈建議您實現其他用於錯誤處理、安全設定和清理傳入資料的嚴密邏輯)。
通過上面的進階建議和樣本,使用 SQL Server 2000 全文檢索搜尋設計和實現快速可縮放的 Web 搜尋應用程式就是輕而易舉事情了。
附錄 C:資源
Full-Text Search Deployment(英文)
是那些初次接觸全文檢索搜尋的使用者的最佳參考。介紹了填充方法及硬體和軟體需求,並為使用 SQL Server 2000 全文檢索搜尋提供了提示、技巧和其他文檔。
全文檢索搜尋公用新聞群組 (microsoft.public.sqlserver.fulltext)
尋找有關全文檢索搜尋問題的答案以及有用提示和技巧的理想場所。全文檢索搜尋新聞群組是 SQL Server 開發小組和博學的 Microsoft MVP 成員經常光顧的場所。