大家都知道"巧婦難為無米之炊",同樣對于搜索引擎而言,沒有了輸入內容這個“米”,“炊”自然也是無從談起。不過首先我們來看看搜索引擎作為一個系統(tǒng),它大概長什么樣子。

這個圖展示了搜索引擎的框架,其實大部分的檢索系統(tǒng)都采用類似的邏輯架構,所以我們可以把搜索引擎看作是一個超大型圖書文獻檢索系統(tǒng)。(插播一個八卦:百度的李彥宏在大學時候的專業(yè)是圖書館系古典文學編目。)如圖,系統(tǒng)通過“數(shù)據(jù)獲取”模塊從互聯(lián)網上汲取網頁信息,然后發(fā)送給后臺“數(shù)據(jù)加工”模塊進行索引再存入數(shù)據(jù)庫。在右邊面向用戶端,系統(tǒng)通過搜索框入口獲取用戶需要檢索的信息,并轉發(fā)給檢索服務器,檢索服務器按照一定規(guī)則再從數(shù)據(jù)庫中抽取匹配信息返還給用戶。從頂層設計上來看,搜索引擎不是很復雜,而我們要做的就是實現(xiàn)其中每一個模塊的技術細節(jié)。
本篇的重點我將談談圖中的“數(shù)據(jù)獲取”模塊,即如何處理搜索引擎的輸入源數(shù)據(jù),也就是解決“米”的問題。對于站內搜索引擎而言,這個的問題是比較容易解決的。原因是網站可以直接索引站點自身的內容或者是用戶提交的內容,這些對于網站的設計者而言都是可控的。比如網站設計者可以在每提交一個頁面到服務器前,先把頁面輸入到站內搜索引擎,等搜索引擎索引完頁面后再進行發(fā)布。又比如當用戶提交的內容需要被檢索的時候,網站首先將這些內容提交給站內搜索引擎,等搜索引擎索引完后再提交用戶的內容到數(shù)據(jù)庫中。對于如何恰當?shù)仄胶庥脩趔w驗與系統(tǒng)索引耗時之間的關系是一門有趣的藝術,不同的網站設計者可能有不同的看法。
從技術上來說,獲取一個網頁是相當容易的,無論你使用哪種語言作為開發(fā)工具,它們一般都會提供類似http.get()這樣的方法。讀者甚至也可以直接使用socket套接字。http協(xié)議從本質上來說,只是使用socket套接字發(fā)送的一串文本而已??梢匀芜x如下2種方式來驗證這一點:
方法1:
手工使用socket套接字在本地搭建一個server,監(jiān)聽在3000端口,偽代碼:
main()
{
???????? socket_handle=socket('0.0.0.0','3000').bind();
???????? listen(socket_handle);
???????? new_socket = accept(socket_handle, data);
???????? printf(data);
???????? return();
}
使用你的編程工具完成上述的編碼后,運行一下。打開瀏覽器,在地址欄里輸入"http://127.0.0.1:3000",回車,看一下server程序在屏幕上的輸出。
方法2:
如果你有l(wèi)inux操作系統(tǒng),你可以使用netcat這個神奇的命令行工具。netcat也提供windows的版本,但是需要額外下載。筆者使用suse的linux,不同的linux在參數(shù)上可能略有差別。
在linux桌面模式下調出控制臺并輸入:
??? netcat -l -p 3000
然后打開瀏覽器,在地址欄里輸入"http://127.0.0.1:3000",回車,看一下server程序在屏幕上的輸出。
如果你嘗試了上面任何一種方式,會在控制臺上看到一個http的請求頭,一般它會是這樣的:
我不在這里過多地討論http協(xié)議的細節(jié),讀者可以直接使用firefox或者chrome自帶的web開發(fā)者工具來看看瀏覽器發(fā)送到其他網站的實際報文頭。由于大部分現(xiàn)代的編程語言都會提供http協(xié)議的庫或者方法,我們就直接忽略它的具體實現(xiàn),而把更多的精力放到更重要的內容上,比如下載前系統(tǒng)要做些什么準備工作或者下載完成后系統(tǒng)接著該干些什么,諸如此類的。
通常我們需要提供一些url種子鏈接作為搜索引擎的初始下載目標,之后要做的就是從下載到的網頁中解析出有價值的鏈接繼續(xù)新的下載,同時對有價值的文本并做進一步的索引處理。這里主要涉及到如下幾個需要解決的問題:
1:互聯(lián)網上的網站數(shù)以千萬計,搜索引擎在搜索網站時,是應該以深度優(yōu)先呢,還是以廣度優(yōu)先?換句話說,是應該把一個網站的內容全部檢索完后再進入下一個網站,還是應該盡量檢索不同的網站,在這個基礎上再考慮檢索深度的問題。
2:網站上的網頁,特別是中文網站上的網頁,除了包含自身的主題信息外,常常還含有大量的廣告信息,這些廣告對于用戶來說是毫無意義的。比如一個關于兒童皮膚問題的網頁上可能含有女性服裝的廣告,如果系統(tǒng)不能區(qū)分這個網頁是關于討論兒童皮膚的問題,在用戶檢索女性服飾時,就會出現(xiàn)不相關的兒童皮膚問題的網頁鏈接。如何剔除網頁垃圾信息,獲取有用的主題信息,是一個好的搜索引擎必須考慮的事情。
3:當我們打算提供中文搜索服務時,需要額外面對一個英語世界中不存在的問題,或者說英語的世界里這個問題是可以被忽略的,它就是“中文分詞”。英語中語義是按單個字來表示的,一個字表示一個意思,那么很自然地可以在系統(tǒng)中按單個字進行拆分索引。而中文常常是使用多個字的組合來表示一個意思,單個字本身并不能代表這個詞組的意思。比如“中文”這個詞組指的是中國人使用的文字或者語言。單個字“中”和“文”,分別對應地理方位的正中間和文章,他們與“中文”的含義相去甚遠。所以我們在做搜索引擎的時候,需要考慮如何來實現(xiàn)按詞組來構建語義的中文分詞系統(tǒng)。
4:我們從網頁中獲取url鏈接時,難免會遇到已經獲取過的鏈接,如果系統(tǒng)不能辨識這些冗余鏈接地址,就會造成重復勞動,不僅浪費計算資源,最差情況下,系統(tǒng)會陷入無限循環(huán)處理同一個資源集合的深淵中。當鏈接地址上億級的時候,發(fā)現(xiàn)重復鏈接就變成了一個挑戰(zhàn)。
這幾個問題我會在后面專門的專題中進行講述,現(xiàn)在假設這些問題都已經解決了。我們來看看“數(shù)據(jù)獲取”模塊的實際實現(xiàn)。

“HTTP進程調度”占據(jù)整個模塊的心臟地位,它負責從“URL池管理器”處獲取有效URL鏈接,然后調度起一個“http通信”進程去互聯(lián)網上拿URL對應的網頁,之后再把下載到的網頁發(fā)送給“網頁解析器”?!熬W頁解析器”的主要工作是抽取網頁中的有效文字信息和有效URL鏈接地址,并分別發(fā)送給下一級的“數(shù)據(jù)加工”模塊和“URL池管理器”?!癠RL池管理器”解決我們前面提到的問題1和問題4。“網頁解析器”則是解決問題2。問題3則是留給下一級的“數(shù)據(jù)加工”去處理了。