1. 程式人生 > >搜尋引擎設計一(百度為例)

搜尋引擎設計一(百度為例)

隨著搜尋經濟的崛起,人們開始越加關注全球各大搜索引擎的效能、技術和日流量。作為企業,會根據搜尋引擎的知名度以及日流量來選擇是否要投放廣告等;作為普通網民,會根據搜尋引擎的效能和技術來選擇自己喜歡的引擎查詢資料;作為技術人員,會把有代表性的搜尋引擎作為研究物件.搜尋引擎經濟的崛起,又一次向人們證明了網路所蘊藏的巨大商機。網路離開了搜尋將只剩下空洞雜亂的資料,以及大量等待去費力挖掘的金礦。

但是,如何設計一個高效的搜尋引擎?我們可以以百度所採取的技術手段來探討如何設計一個實用的搜尋引擎.搜尋引擎涉及到許多技術點,比如查詢處理,排序演算法,頁面抓取演算法,CACHE機制,ANTI-SPAM等等.這些技術細節,作為商業公司的搜尋引擎服務提供商比如百度,GOOGLE等是不會公之於眾的.我們可以將現有的搜尋引擎看作一個黑盒,通過向黑盒提交輸入,判斷黑盒返回的輸出大致判斷黑盒裡面不為人知的技術細節.

查詢處理與分詞是一箇中文搜尋引擎必不可少的工作,而百度作為一個典型的中文搜尋引擎一直強調其”中文處理”方面具有其它搜尋引擎所不具有的關鍵技術和優勢.那麼我們就來看看百度到底採用了哪些所謂的核心技術.

我們分兩個部分來講述:查詢處理/中文分詞.

一. 查詢處理

使用者向搜尋引擎提交查詢,搜尋引擎一般在接受到使用者查詢後要做一些處理,然後在索引資料庫裡面提取相關的資訊.那麼百度在接受到使用者查詢後做了些什麼工作呢?

  1. 假設使用者提交了不只一個查詢串,比如”資訊檢索理論工具”.那麼搜尋引擎首先做的是根據分隔符比如空格,標點符號,將查詢串分割成若干子查詢串,比如上面的查詢就會被解析為:<資訊檢索,理論,工具>三個子字串;這個道理簡單,我們接著往下看.

  2. 假設提交的查詢有重複的內容,搜尋引擎怎麼處理呢?比如查詢”理論工具理論”,百度是將重複的字串當作只出現過一次,也就是處理成等價的”理論工具”,而GOOGLE顯然是沒有進行歸併,而是將重複查詢子串的權重增大進行處理.那麼是如何得出這個結論的呢?我們可以將”理論工具”提交給百度,返回341,000篇文件,大致看看第一頁的返回內容.OK.繼續,我們提交查詢”理論工具理論”,在看看返回結果,仍然是那麼多返回文件,當然這個不能說明太多問題,那看看第一頁返回結果的排序,看出來了嗎?順序完全沒有變化,而GOOGLE則排序有些變動,這說明百度是將重複的查詢歸併成一個處理的,而且字串之間的先後出現順序基本不予考慮(GOOGLE是考慮了這個順序關係的).

  3. 假設提交的中文查詢包含英文單詞,搜尋引擎是怎麼處理的?比如查詢”電影BT下載”,百度的方法是將中文字串中的英文當作一個整體保留,並以此為斷點將中文切分開,這樣上述的查詢就切為<電影,BT,下載>,不論中間的英文是否一個字典裡能查到的單詞也好,還是隨機的字元也好,都會當作一個整體來對待.至於為什麼,你用查詢”電影dfdfdf下載”看看結果就知道了.當然如果查詢中包含數字,也是如此辦理.

到目前為止,一切很簡單,也很清楚,百度怎麼處理使用者查詢的呢?歸納如下:首先根據分割符號將查詢分開,然後看看是否有重複的字串,如果有,就拋棄多餘的,只保留一個,接著判斷是否有英文或者數字,如果有的話,把英文或者數字當作一個整體保留並把前後的中文切開.

接著該幹什麼呢?該考慮分詞的問題了.

二. 中文分詞

首先,講講百度的分詞時機或者條件問題,是否是個中文字串百度就拿來切一下呢?非也,要想被百度的分詞程式榮幸的切割一下也是要講條件的,哪能是個字串就切割啊?你當百度是賣鋸條的麼?

那麼什麼樣的字串才滿足被切割的條件呢?簡單說來,如果字串只包含小於等於3箇中文字元的話,那就保留不動,當字串長度大於4箇中文字元的時候,百度的分詞程式才出馬大幹快上,把這個字串肢解掉.

怎麼證明呢?我們向百度提交”電影下載”,看看返回結果中標為紅字的地方,不難看出來,查詢已經被切割成<電影,下載>兩個單詞了,說明分詞程式已經開工了,如果是比4箇中文字元更長的字串,那分詞程式就更不客氣了,一定大卸八塊而後快.我們來看看三個字元的情況,提交查詢”當然擇”,看起來這個查詢不倫不類,那是因為我希望看到這個字串被切分為<當然,擇>,返回結果365篇相關頁面,翻到最後一頁,發現標紅的關鍵字都是”當然擇”連續出現的情況,好像沒有切分,但是還不確定,那麼再提交人工分好的查詢”當然擇”看看,返回結果1,090,000篇,基本上可以確定沒有進行分詞了,當然另外一種解釋是:對於三個字元先切分,然後將切分後的結果當作一個短語查詢,這樣看到的效果和沒有切分是相似的.但是我傾向於判斷百度對於少於3個字元的串沒有切分,奧卡姆不是說了麼”如無必要,勿增實體”,幹嗎做無用功呢.那麼如果沒有切分,會有一個隨之而來的問題,怎麼從索引庫裡面提取未切分的字串呢?這牽扯到索引的問題,我覺得百度應該採取了兩套索引機制,一種是按照單詞索引,一種是按照N-GRAM索引,至於索引的具體問題,以後在詳細論述.

下面我們看看百度是採取的何種分詞演算法,現在分詞演算法已經算是比較成熟了,有簡單的有複雜的,比如正向最大匹配,反向最大匹配,雙向最大匹配,語言模型方法,最短路徑演算法等等,有興趣的可以用GOOGLE去搜索一下以增加理解.這裡就不展開說了.但是要記住一點的是:判斷一個分詞系統好不好,關鍵看兩點,一個是消除歧義能力;一個是詞典未登入詞的識別比如人名,地名,機構名等.

那麼百度用的是什麼方法?我的判斷是用雙向最大匹配演算法.至於怎麼推理得出的,讓我們一步步來看.當然,這裡首先有個假設,百度不會採取比較複雜的演算法,因為考慮到速度問題.

我們提交一個查詢”毛澤東北京華煙雲”,又一個不知所云的查詢,儘管不知所云但是自有它的道理,我想看看百度的分詞是如何消歧以及是否有詞典未登入詞的識別的功能,如果是正向最大匹配演算法的話,那麼輸出應該是:”毛澤東/北京/華/煙雲”,如果是反向最大匹配演算法的話,那麼輸出應該是:”毛/澤/東北/京華煙雲”,我們看看百度的分詞結果:”毛澤東/北/京華煙雲”,一個很奇怪的輸出,跟我們的期望相差較多,但是從中我們可以獲得如下資訊:百度分詞可以識別人名,也可以識別”京華煙雲”,這說明有詞典未登入詞的識別的功能,我們可以假設分詞過程分為兩個階段:第一階段,先查詢一個特殊詞典,這個詞典包含一些人名,部分地名以及一些普通詞典沒有的新詞,這樣首先將”毛澤東”解析出來,剩下了字串”北京華煙雲”,而”北/京華煙雲”,可以看作是反向最大匹配的分詞結果.這樣基本說得通.為了證明這一點,我們提交查詢”發毛澤東北”,我們期望兩種分詞結果,一個是正向最大匹配<發毛,澤,東北>,一個是上述假設的結果<發,毛澤東,北>,事實上百度輸出是第二種情況,這樣基本能確定百度分詞采取了至少兩個詞典,一個是普通詞典,一個是專用詞典(人名等).而且是專用詞典先切分,然後將剩餘的片斷交由普通詞典來切分.

繼續測驗,提交查詢”古巴比倫理”,如果是正向最大匹配,那麼結果應該是<古巴比倫,理>,如果是反向最大匹配,那麼結果應該是<古巴,比,倫理>,事實上百度的分詞結果是<古巴比倫,理>,從這個例子看,好像用了正向最大匹配演算法;此外還有一些例子表明好像是使用正向最大匹配的;但是且慢,我們看這個查詢”北京華煙雲”,正向最大匹配期望的結果是<北京,華,煙雲>,而反向最大匹配期望的結果是<北,京華煙雲>,事實上百度輸出的是後者,這說明可能採用的反向最大匹配;從這點我們可以猜測百度採用的是雙向最大匹配分詞演算法,如果正向和反向匹配分詞結果一致當然好辦,直接輸出即可;但是如果兩者不一致,正向匹配一種結果,反向匹配一種結果,此時該如何是好呢?從上面兩個例子看,在這種情況下,百度採取最短路徑方法,也就是切分的片斷越少越好,比如<古巴,比,倫理>和<古巴比倫,理>相比選擇後者,<北京,華,煙雲>和<北,京華煙雲>相比選擇後者.還有類似的一些例子,這樣基本可以解釋這些輸出結果.

但是仍然遺留的問題是:如果正向反向分詞不一致,而且最短路徑也相同,那怎麼辦?輸出正向的還是反向的結果?我們再來看一個例子.提交查詢”遙遠古古巴比倫”,這個查詢被百度切分為<遙遠,古古,巴比倫>,說明詞典裡面有”巴比倫”,但是是否有”古巴比倫”這個詞彙不確定,此時看不出是正向切分還是反向切分得出的結果,換查詢為”遙遠古巴比倫”,此時被切分為”遙遠/古巴比倫”,這說明詞典裡面有”古巴比倫”這個詞彙,這說明了”遙遠古古巴比倫”是正向最大匹配的結果.那為什麼”遙遠古古巴比倫”不會被反向切分為”遙/遠古/古巴比倫”呢,百度的可能選擇是這種情況下選擇單字少的那組切分結果.

當然還可以繼續追問:如果切分後單字也一樣多,那怎麼辦?最後看一個例子,查詢”王強大小:”,百度將其切分為”王/強大/小”,是正向切分的結果,如果是反向的會被切分為”王/強/大小”,這說明有歧義而且單字也相同則選擇正向切分結果.

OK,看到這裡可能頭已經有些暈了,最後總結一下百度的分詞演算法,當然裡面還是有猜測的成分,演算法如下:

首先查詢專用詞典(人名,部分地名等),將專有名稱切出,剩下的部分採取雙向分詞策略,如果兩者切分結果相同,說明沒有歧義,直接輸出分詞結果.如果不一致,則輸出最短路徑的那個結果,如果長度相同,則選擇單字詞少的那一組切分結果.如果單字也相同,則選擇正向分詞結果..

百度一直宣傳自己在中文處理方面的優勢,從上面看,分詞演算法並無特殊之處,消歧效果並不理想,即使百度採取比上述分詞演算法複雜些的演算法也難以說成是優勢,如果說百度有優勢的話,唯一的優勢就是那個很大的專用詞典,這個專用詞典登入了人名(比如大長今),稱謂(比如老太太),部分地名(比如阿聯酋等),估計百度採用學術界公佈的比較新的命名實體識別演算法從語料庫裡面不斷識別出詞典未登入詞,逐漸擴充這個專門詞典.如果這就是優勢的話,那麼這個優勢能夠保持多久就是個很明顯的問題

搜尋引擎設計實用教程(2)-以百度為例
  之二:Spelling Checker拼寫檢查錯誤提示(以及拼音提示功能)
  
  中科院軟體所 張俊林

   2005年11月

  拼寫檢查錯誤提示是搜尋引擎都具備的一個功能,也就是說使用者提交查詢給搜尋引擎,搜尋引擎檢檢視是否使用者輸入的拼寫有錯誤,對於中文使用者來說一般造成的錯誤是輸入法造成的錯誤.那麼我們就來分析看看百度是怎麼實現這一功能的.
  我們分析拼寫檢查系統關注以下幾個問題:
  (1)系統如何判斷使用者的輸入是有可能發生錯誤的查詢呢?
  (2)如果判斷是可能錯誤的查詢輸入,如何提示正確的詞彙呢?
  
  那麼百度是如何做的呢?百度判斷使用者輸入是否錯誤的標準,我覺得應該是查字典,如果發現字典裡面不包含這個詞彙,那麼很有可能是個錯誤的輸入,此時啟動錯誤提示功能,這個很好判斷,因為如果是一個正常詞彙的話,百度一般不會有錯誤提示,而你故意輸入一個詞典不可能包含的所謂詞彙,此時百度一般會提示你正確的檢索詞彙.
  那麼百度是怎麼提示正確詞彙的呢?很明顯是通過拼音的方式,比如我輸入查詢” 制才”,百度提供的提示詞彙為: “:制裁 質材 紙材”,都是同音字.所以百度必然維持著一個同音詞詞典,裡面保留著同音詞資訊,比如可能包含著下面這條詞條: “ zhi cai à制裁,質材,紙材”,另外還有一個標註拼音程式,現在能夠看到的基本流程是: 使用者輸入” 制才”,查詞典,發現沒有這個詞彙,OK,啟動標註拼音程式,將” 制才”標註為拼音”zhi cai”,然後查詢同音詞詞典,發現同音詞” 制裁,質材,紙材”,那麼提示使用者可能的正確拼寫.
  整體流程看起來很簡單,但是還有一些遺留的小問題,比如是否將詞表裡面所有同音詞都作為使用者的提示資訊呢?比如 某個拼音有10個同音詞,是否都輸出呢?百度並沒有將所有同音詞都輸出而是選擇一定篩選標準,選擇其中幾個輸出.怎麼證明這一點?我們看看拼音”liu li”的同音詞,紫光輸入法提示同音詞匯有” 流麗 流離 琉璃 流利”4個,我們看看百度返回幾個,輸入”流厲”作為查詢,這裡是故意輸入一個詞典不包含的詞彙,這樣百度的拼寫檢查才開始工作,百度提示: “琉璃 劉麗 劉莉 “,這說明什麼?說明不是所有同音詞都輸出,而是選擇輸出,那麼選擇的標準是什麼?我能夠猜測到的方法是對於使用者查詢LOG進行統計,提取使用者查詢次數多的那些同音詞輸出,如果是這樣的話,上面的例子說明使用者搜尋”琉璃”次數比其它的都要高些,次之是” 劉麗”,再次是” 劉莉”,看來大家都喜歡查詢自己或者認識的人的名字.
  另外一個小問題:同音詞詞典包含2字詞,3字詞,那麼是否包含4字詞以及更長的詞條?是否包含一字詞? 這裡一字詞好回答,不用測試也能知道肯定不包含,因為你輸入一個字,誰知道是否是錯誤的呢?反正只要是漢字就能在詞表裡面找到,所以沒有判斷依據.二字詞是包含的,上面有例子,三字詞也包含,比如查詢 “中城藥”百度錯誤提示:”中成藥”,修改查詢為”重城藥”,還是提示”中成藥” ,再次修改查詢 “重城要”,百度依然提示”中成藥”. 那麼4字詞彙呢?
  百度還是會給你提示的,下面是個例子:
  輸入:靜華煙雲 提示 京華煙雲
  輸入 靜話煙雲 提示 京華煙雲
  輸入 靜話閻暈 提示 京華煙雲
  那麼更長的詞彙是否提示呢?也提示,比如我輸入: “落花世界有風軍”,這個查詢是什麼意思,估計讀過古詩的都知道,看看百度的提示”落花時節又逢君”,這說明什麼?說明同音詞詞典包含不同長度的同音詞資訊,另外也說明了百度的核心中文處理技術,也就是那個詞典,還真挺大的.
  但是,如果使用者輸入的查詢由兩個或者兩個以上子字串構成,那麼百度的錯誤提示功能就罷工了,比如輸入查詢”哀體”,百度提示”艾提 挨踢”,但是.輸入為 “我 哀體”,則沒有任何錯誤提示.
  還有一個比較重要的問題:如果漢字是多音字那麼怎麼處理?百度呢比較偷懶,它根本就沒有對多音字做處理.我們來看看百度的一個標註拼音的錯誤,在看這個錯誤前先看看對於多音字百度是怎麼提示錯誤的,我們輸入查詢”俱長”,百度提示”劇場 局長”, “俱長”的拼音有兩個:”ju zhang /ju chang” ,可見如果是多音字則幾種情況都提示..現在我們來看看錯誤的情況, 我們輸入查詢”劇常”,百度提示”:劇場 局長”,提示為”劇場”當然好解釋,因為是同音字,但是為什麼 “局長”也會被提示呢?這說明百度的同音字詞典有錯誤,說明在”ju chang”這個詞條裡面包含”局長”這個錯誤的同音詞.讓我們順藤摸瓜,這個錯誤又說明什麼問題呢?說明百度的同音詞典是自動生成的,而且沒有人工校對.還說明在自動生成同音詞典的過程中,百度不是根據對一篇文章標註拼音然後在抽取詞彙和對應的拼音資訊獲得的,而是完全按照某個詞典的詞條來標註音節的,所以對於多音字造成的錯誤無法識別出來,如果是對篇章進行拼音標註,可能就不會出現這種很容易發現的錯誤標註. 當然還有另外一種解釋,就是”局長”是故意被百度提示出來可能的正確提示詞彙,因為考慮到南方人”zh’和 “ch”等前後鼻音分不清麼,那麼是這樣的麼?我們繼續測試到底是何種情況.是百度有錯誤還是這是百度的先進的演算法?
  我們考慮詞彙”長大”,故意錯誤輸入為”贓大”,如果百度考慮到了前後鼻音的問題,那麼應該會提示”長大”,但是百度提示是”藏大”.這說明什麼?說明百度並沒有考慮前後鼻音問題,根本就是系統錯誤. 我們輸入查詢”懸賞”,故意將之錯誤輸入為”懸桑”,沒有錯誤提示,說明確實沒有考慮這種情況.前鼻音沒有考慮,那麼後鼻音考慮了麼,我們輸入”:經常”,故意改為後鼻音 “經纏”,百度提示為”經產 經懺”,還是沒有考慮後鼻音.這基本可以確定是百度系統的錯誤導致.
  根據以上推導,我們可以得出如下結論:百度是將分詞詞典裡面每個詞條利用拼音標註程式標註成拼音,然後形成同音詞詞典,所以兩個詞典是同樣大的,而且這個詞典也隨著分詞詞典的增長而在不斷增長. 至於標註過程中多音字百度沒有考慮,如果是多音字就標註成多個發音組合,通過這種方式形成同音詞詞典.這樣的同音詞詞典顯然包含著很多錯誤.
  最後一個問題:百度對於英文進行拼寫檢查麼?讓我們試試看,輸入查詢”china”,不錯,搜到不少結果,專注中文搜尋的百度還能搜尋到英文,真是意外的驚喜.變換一下查詢”chine”,會更加意外驚喜的給我們提示”china”嗎?百度提示的是: 吃呢 持呢,原來是不小心觸發了百度的拼音搜尋功能了.那麼拼音搜尋和中文檢查錯誤是否採用同一套同音詞詞典呢,讓我們來實驗一下,搜尋”rongji”,百度提示” 榕基 溶劑 容積”,OK,換個中文查詢”容機”,百度提示” 榕基 溶劑 容積”,看來使用的是同一套同音詞詞典.也就是說百度的中文糾錯和拼音檢索使用的機制相同,中文糾錯多了一道拼音註音的過程而已.難道這就是傳說中那個百度的”事實上是一個無比強大的拼音輸入法”的拼音提示功能麼?
  最後讓我們總結歸納一下百度的拼寫檢查系統:
  後臺作業: (1)前面的文章我們說過,百度分詞使用的詞典至少包含兩個詞典一個是普通詞典,另外一個是專用詞典(專名等),百度利用拼音標註程式依次掃描所有詞典中的每個詞條,然後標註拼音,如果是多音字則把多個音都標上,比如”長大”,會被標註為”zhang da/chang da”兩個詞條.
  (2)通過標註完的詞條,建立同音詞詞典,比如上面的”長大”,會有兩個詞條: zhang daà長大” , chang daà長大.
  (3)利用使用者查詢LOG頻率資訊給予每個中文詞條一個權重;
  (4)OK,同音詞詞典建立完成了,當然隨著分詞詞典的逐步擴大,同音詞詞典也跟著同步擴大;
  
  拼寫檢查:
  (1)使用者輸入查詢,如果是多個子字串,不作拼寫檢查;
  (2)對於使用者查詢,先查分詞詞典,如果發現有這個單詞詞條,OK,不作拼寫檢查;
  (3)如果發現詞典裡面不包含使用者查詢,啟動拼寫檢查系統;首先利用拼音標註程式對使用者輸入進行拼音標註;
  (4)對於標註好的拼音在同音詞詞典裡面掃描,如果沒有發現則不作任何提示;
  (5)如果發現有詞條,則按照順序輸出權重比較大的幾個提示結果;
  
  拼音提示:
  (1)對於使用者輸入的拼音在同音詞詞典裡面掃描,如果沒有發現則不作任何提示;
  (2)如果發現有詞條,則按照順序輸出權重比較大的幾個提示結果;

搜尋引擎設計實用教程(3)-以百度為例

                       之三:對百度分詞演算法的進一步分析



                                 中科院軟體所 malefactor

                           2005年11月

上面說過,經過分析得出百度的分詞系統採用雙向最大匹配分詞,但是後來發現推理過程中存在一個漏洞,而且推匯出來的百度分詞演算法步驟還是過於繁瑣,所以進一步進行分析,看看是否前面的推導有錯誤.

那麼以前的分析有什麼漏洞呢?我們推導百度分詞有反向最大匹配的依據是百度將”北京華煙雲”分詞為<北,京華煙雲>,從這裡看好像採用了反向最大匹配,因為正向最大匹配的結果應該是<北京,華,煙雲>,但是由此就推論說百度採用了雙向最大匹配還是太倉促了,前面文章我們也講過,百度有兩個詞典,一個普通詞典,一個專有詞典,而且是專有詞典的詞彙先切分,然後將剩餘片斷交給普通詞典去切分.所以上面的”北京華煙雲”之所以被切分成<北,京華煙雲>,另外一個可能是:京華煙雲這個詞彙是在專有詞典裡面儲存的,所以先分析,這樣得出”京華煙雲”,剩下”北”,沒什麼好切分的,所以輸出<北,京華煙雲>.

這裡只是假設,那麼是否確實”京華煙雲”在專有詞典呢?我們再看一個例子”山東北京華煙雲”,百度切分的結果是<山東,北,京華煙雲>,如果”京華煙雲”在普通詞典,如果是反向切分,那麼結果應該是<山,東北,京華煙雲>,如果是正向切分應該是<山東,北京,華,煙雲>,無論如何都分不出<山東,北,京華煙雲>.這說明什麼?說明”京華煙雲”是在那個專有詞典,所以先切分出”京華煙雲”,然後剩下的”山東北”交由普通詞典切分,明顯是正向最大匹配的結果輸出<山東,北>.當然按照我們在第一篇文章的演算法推導”山東北”的切分也會得出<山東,北>的結論,但是明顯比正向最大匹配多幾個判斷步驟,既然效果一樣,另外一個更加簡潔的方法也能說得通,那當然選擇簡便的方法了.所以初步判斷百度採取的是正向最大匹配.

我們繼續測試採用何種分詞演算法,為了減少專有詞典首先分詞造成的影響,那麼查詢裡面不能出現相對特殊的詞彙,構築查詢”天才能量級”,這裡應該沒有專有詞典出現過的詞彙,百度切分為<天才,能量,級>,看來是正向最大匹配的結果.另外,如果所有查詢詞彙都出現在專有詞典,那麼採取的是何種方法?這樣首先就得保證詞彙都出現在專有詞典,這麼保證這一點呢?我們構造查詢”鋪陳曉東方”,百度切分為<鋪,陳曉東,方>,可以看出”陳曉東”是在專有詞典的所以先切分出來.另外一個例子 “山東京城”,百度切分為<山東,京城>,說明”東京”是在普通詞典的.OK,構造查詢”陳曉東京華煙雲”,通過前面分析可以看出兩個詞彙都在專有詞典裡面,百度切分為<陳曉東,京華煙雲>,說明對於專有詞典詞彙也是採取正向最大匹配或者雙向最大匹配.那麼使用反向最大匹配了嗎?構造查詢例子”陳曉東方不敗”,首先我們肯定”陳曉東”和”東方不敗”都是在專有詞典出現的,如果是正向切分,那麼應該是<陳曉東,方,不敗>或者<陳曉東,方,不,敗>如果是反向切分則是<陳,曉,東方不敗>,可以看出百度的切分是<陳曉東,方,不敗>或者<陳曉東,方,不,敗>,說明採用的是正向最大匹配.通過分析,百度的詞典不包含”不敗”這個單詞,所以實際上百度的切分結果是<陳曉東,方,不,敗>,很明顯這和我們以前推導的演算法是有矛盾的,所以以前的分析演算法確實有問題,所以結論是百度採取的是正向最大匹配演算法.

重新歸納一下百度的分詞系統:首先用專有詞典採用最大正向匹配分詞,切分出部分結果,剩餘沒有切分交給普通詞典,同樣採取正向最大匹配分詞,最後輸出結果.

另外,GOOGLE也是採用正向最大匹配分詞演算法,不過好像沒有那個專用詞典,所以很多專名都被切碎了.

從這點講,GOOGLE在中文詞典構建上比百度差些,還需要加把子力氣才行,不過這也不是什麼多難的事.

搜尋引擎設計實用教程(4)-以百度為例

                      之四:相關提示功能



                      中科院軟體所 malefactor

2005年11月

相關提示也是幾乎所有搜尋引擎提供的一個附加功能,所謂相關提示,就是對於使用者提交的查詢進行分析,然後根據其它使用者相似的查詢給予使用者提示,比如我輸入查詢”大長今”,檢索系統會提示其它象”大長今主題曲”,”大長今下載”等等相關的一些其它使用者查詢.

那麼搜尋引擎是根據什麼原則對於其它使用者的查詢進行選擇來提示使用者相關查詢呢?我們還是以百度為例子來看看怎麼實現這個功能.要實現這個功能主要解決如下三個問題:

問題一.從哪裡獲得其它使用者的查詢資訊?這個問題對於搜尋引擎來說不是難事,因為搜尋引擎都有使用者查詢LOG的功能,在一段時間內每一個使用者提交給搜尋引擎的查詢都被記錄在LOG檔案裡面,所以從這個檔案裡面可以獲得其它使用者的查詢資訊.這個LOG還可以用作其它功能的基本素材,比如搜尋排行榜或者搜尋風雲榜,就是根據這個LOG檔案,對使用者查詢歸類,相同的歸為一類,然後統計一段時間內這個類別的出現次數,按照降序排列,選擇前列K個作為輸出即可.

問題二.搜尋引擎拿到使用者的查詢比如”大長今”,使用者查詢LOG裡面有成千上萬的不同查詢,那麼選擇哪些作為提示呢?這裡面牽涉到一個字串相似性計算的過程.

問題三.假設已經從查詢LOG裡面選擇了一批使用者相關查詢資訊,按照什麼順序輸出呢?為什麼”大長今主題曲”排列在”大長今下載”前面呢?這裡面牽涉到排序原則的問題.

我們一步步分析看看百度是如何解決上面的第二和第三個問題的.

首先,百度在計算字串相似性的計算過程是首先對於使用者查詢進行分詞,然後對於分詞後的結果來進行相似性計算的.怎麼證明這一點?第一個證明:首先用”新聞”作為查詢,看看百度提示的相關詞彙是什麼,然後將查詢修改為”新聞新聞新聞”,再看看提示的相關詞彙是什麼,提示是完全一樣的,基本說明是分詞後進行計算的.第二個證明: 首先用”娛樂新聞報道”作為查詢,看看百度提示的相關查詢是什麼,然後人工分好詞”娛樂新聞報道”,再看看提示的相關查詢是什麼.,提示仍然是完全一樣的,我們再顛倒一下詞彙順序,用”新聞娛樂報道”作為查詢,再看看相關查詢是什麼,完全沒有變化.所以得出結論:百度在計算字串相似性之前首先要對使用者查詢進行分詞,當然查詢LOG裡面的查詢也要首先進行分詞.

第二步,怎麼計算相似性並排序輸出呢?如果使用者輸入查詢只有一個單詞,那麼處理起來好像比較簡單,只要使用者查詢LOG裡面包含這個單詞的字串都被糾出來,然後根據使用者總共查詢這個字串的次數進行排序,選擇前列K個作為相關提示就可以了.好像很簡單,但是問題真的這麼簡單就被解決了麼?並非如此.

如果使用者輸入的查詢比較長,問題就出來了,比如我們用“清脆的鳥叫聲”作為查詢,百度返回的相關提示中,前列1-35個相關查詢包含“鳥”和“叫聲”,這幾個查詢排序原則是按照使用者查詢次數多少排列的,在36-40的相關查詢僅僅包含“清脆”一個單詞,排列順序和用“清脆”查詢時候順序相同,說明也是按照使用者查詢次數多少排列的;41-100的相關查詢僅僅包含“叫聲”,第41個查詢”動物的叫聲”是所有100個查詢使用者查詢次數最多的一個.為什麼包含”清脆”的查詢排列在包含”叫聲”的查詢前面而不是反過來呢?

在給個例子,用“咆哮小老鼠”作為查詢,排在最前面的是匹配了“咆哮,小,老鼠”三個詞彙的相關查詢,次之是匹配了“咆哮,老鼠”的相關查詢,再次是匹配“咆哮,小”的相關查詢,最次是匹配“小,老鼠”的相關查詢,總共輸出92個相關查詢,對於只有一個匹配的查詢沒有輸出。那麼為什麼是“咆哮,老鼠”》“咆哮,小”》“小,老鼠”呢?原則是什麼呢?

多次實驗後,發現裡面其實有一個匹配單詞的權重設定問題,拿”咆哮小老鼠”做例子,切分後是<咆哮,小,老鼠>,假設使用者查詢LOG裡面有兩個查詢,一個是”咆哮老鼠論壇”,切分後是<咆哮,老鼠,論壇>.匹配的有兩個單詞(咆哮,老鼠),另一個查詢是”咆哮小”,切分後是<咆哮,小>,匹配的也有兩個單詞(咆哮,小),怎麼給這兩個查詢排序呢?假設每個單詞都有一個權重設定,比如 Weight(咆哮)=a Weight(小)=b Weight(老鼠)=c . 我們計算”咆哮小老鼠”和”咆哮老鼠論壇”的相似性等於重複單詞權重之和,也就是等於a+c,而另外一個查詢的相似性等於a+b,然後按照順序輸出就行了.所以這裡面關鍵是如何設定單詞的權重.

那麼單詞權重怎麼衡量呢,作為搜尋引擎很容易獲得的一個單詞權重評價因素是IDF,所謂IDF,就是說如果一個單詞如果在很多文件中都出現,那麼這個單詞重要性就很低,比如說”的”,幾乎在每個中文網頁都出現,那麼這個單詞的IDF值就非常低.具體計算IDF的公式是

IDF(word)=log(N/DF(word)),

這裡,DF(word)指的是包含單詞word的文件數目個數,N指的是文件集合的總的檔案個數,我們假設百度索引了6億個網頁,那麼這裡N=600000000.

我們用IDF來解釋百度的相關查詢排序因子.首先來解釋“清脆的鳥叫聲”這個查詢的相關查詢排序,我們分別用“清脆”“鳥”“叫聲”來作為查詢,看看有多少網頁包含這些詞,百度返回結果是:

清脆:找到相關網頁約2,390,000篇      

鳥:找到相關網頁約14,000,000篇

叫聲:到相關網頁約3,370,000篇

把這些數值帶入上面的公式計算得出IDF權重 IDF(清脆)=2.39975335》IDF(叫聲)=2.25052135》IDF(鳥)=1.63202321.所以前列匹配了“鳥”和“叫聲”的權重最大,都包含這兩個查詢按照使用者查詢數目多少輸出,其他的按照包含”清脆”或者”叫聲”的順序輸出.

對於查詢“咆哮小老鼠”來說,我們看看是否成立:

百度返回結果:

 咆哮:找到相關網頁約2,090,000篇

 小:找到相關網頁約29,600,000篇

 老鼠:找到相關網頁約11,900,000篇



 IDF(咆哮)=2.45800496

 IDF(小)=1.30685954

 IDF(老鼠)=1.70260429

所以權重是咆哮>老鼠>小

我們看到前面分析輸出順序是: <咆哮,老鼠> > <咆哮,小> > <小,老鼠>

我們根據上面單詞的權重可以看出:<咆哮,老鼠>=IDF(咆哮)+IDF(老鼠)=4.15

                               <咆哮,小>=IDF(咆哮)+IDF(小)=3.75

                               <小,老鼠>=IDF(小)+IDF(老鼠)=3.01

所以百度的順序按照這個順序輸出。

再看個例子:查詢“娛樂新聞報道”百度返回結果:

 娛樂:找到相關網頁約31,600,000篇

 新聞:找到相關網頁約93,500,000篇

 報道:找到相關網頁約17,000,000篇



 IDF(娛樂)=1.27846417 

 IDF(新聞)= 0.80733964 

 IDF(報道)=1.54770233

我們可以預測:

 包含《娛樂,新聞,報道》的相關查詢排名最高,次之是《娛樂,報道>,再次是《新聞,報道》,可以看出百度的排序果然是如此。所以我們的推理基本上是正確的.

最後歸納一下相關查詢的演算法流程:

(1) 使用者輸入查詢,分詞;

(2) 計算使用者查詢和歷史使用者查詢的相似性,相似性計算是通過計算兩者重複單詞的權重之和來計算的

(3) 每個單詞的權重用單詞的IDF來計算,大的排序原則根據這個權重進行排序輸出,如果兩個歷史查詢包含相同的重複詞彙集合,那麼查詢權重相同,則按照使用者查詢次數有高到低排序輸出。

後臺作業:為了加快查詢反映速度,搜尋引擎不會每次使用者查詢都重新計算相關查詢,可以在後臺算好以後儲存在資料庫裡面,使用者查詢的時候直接查詢資料庫輸出,那麼後臺如何處理呢?

(1)對於最近一段時間(比如一個月或者一個星期)使用者查詢LOG進行統計分析,選擇列在前列比如1千萬條最頻繁的使用者查詢,

(2)然後對於每個查詢分詞,按照倒排文件進行儲存,比如“新聞報道 10000”,則在索引裡面登入  “新聞--》新聞報道  10000”“報道-->新聞報道 10000”,其他查詢都是如此處理進入索引。

(3)對於使用者查詢,在索引裡面查詢最相似的歷史查詢,並按照上面介紹的方法計算權重,按照權重輸出;

 (4)當然,為了更加加快查詢速度,第三步驟的工作也可以預先算好,儲存在資料庫裡面,使用者查詢直接在資料庫裡面存取。這個資料庫可以每隔一段時間更新一次以反映最新的情況