這個系列的第六個主題,主要談一些搜索引擎相關的常見技術。
1995年是搜索引擎商業公司發展的重要起點,《淺談推薦系統基礎》中也講過,隨著互聯網上的Web站點數量越來越多,分類目錄網站已經不能滿足用戶的需求,用戶也無法依賴手工的方式來獲得自己想要的信息,在這樣的背景下,搜索引擎發展了起來。
有人將搜索引擎分為三個時代:
- 文本檢索:采用經典的信息檢索模型,如布爾模型、向量空間模型或概率模型來計算用戶查詢關鍵詞和網頁文本內容的相關程度。
- 鏈接分析:充分利用了網頁之間的鏈接關系,認為網頁鏈接代表了一種推薦關系,深入挖掘和利用了網頁鏈接所代表的含義。
- 用戶中心:以理解用戶需求為核心,致力于解決如何能夠理解用戶發出的某個很短小的查詢詞背后所包含的真正需求。
搜索引擎的三個目標:
- 更全:索引網頁更全
- 更快:查詢速度更快
- 更準:搜索結果更準
讓搜索結果更準的三個核心問題:
- 用戶真正的需求是什么
- 哪些信息是和用戶需求真正相關的
- 哪些信息是用戶可以信賴的
從架構層面,搜索引擎主要需要解決兩方面的問題:一個是搜索引擎需要獲取、存儲并處理以百億計的海量網頁;另一個是快速響應用戶的查詢,并精確滿足用戶的需求。
搜索引擎通過爬蟲將整個互聯網的信息獲取到本地,通過網頁去重模塊去除其中相當大比例的完全相同或近似重復的內容。
在此之后,搜索引擎對網頁進行解析,抽取出網頁主體內容,以及頁面中包含的指向其他頁面的鏈接。網頁主體內容特別的通過倒排索引結構來保存,保存頁面鏈接關系是為網頁相關性\重要性排序做準備。
由于網頁數量提多,搜索引擎不僅需要保存網頁原始信息,還要存儲一些中間的處理結果,使用單臺或者少量的機器明顯是不現實的,所以需要優秀的云存儲與云計算平臺,使用數以萬計的PC搭建了海量信息的可靠存儲與計算架構。
當搜索引擎接收到用戶的查詢詞后,首先需要對查詢詞進行分析,希望能結合查詢詞和用戶信息來正確推導用戶的真正搜索意圖。在此之后,優先在緩存中查找,搜索引擎的緩存系統存儲了不同的查詢意圖對應的搜索結果。如果緩存信息無法滿足用戶需求,搜索引擎需要調用網頁排序模塊,根據用戶的查詢實時計算哪些網頁是滿足用戶信息需求的,并排序輸出作為搜索結果。
網頁排序重要的兩個參考因素分別是內容相似性和網頁重要性,搜索引擎需要選擇與用戶查詢密切相關的,質量較好或者相對重要的網頁。
除了上述的子功能,搜索引擎的反作弊模塊也是必不可少的,以避免網頁通過各種手段將網頁的搜索排名提高到與其網頁質量不相稱的位置。
網絡爬蟲
通用爬蟲框架
爬蟲首先從互聯網頁面中精心選擇一部分網頁,以這些網頁的鏈接地址作為種子URL,將這些種子URL放入待抓取URL隊列中,爬蟲從待抓取URL隊列依次讀取,并將URL通過DNS解析,把鏈接地址轉換為網站服務器對應的IP地址。然后將其和網頁相對路徑名稱交給網頁下載器,網頁下載器負責頁面內容的下載。
對于下載到的網頁,首先將網頁內容存儲到頁面庫中,等待后續建立索引;之后將該網頁的URL放入已抓取URL隊列中以避免重復抓取;最后核對網頁中所有包含的鏈接信息,與已抓取URL隊列比較,如果鏈接還沒有被抓取過,則將這個URL放入待抓取URL隊列末尾。實際上也就是一種BFS廣度優先搜索。
對于爬蟲而言,互聯網頁面分為五個部分:已下載網頁集合、已過期網頁集合、待下載網頁集合、可知網頁集合和不可知網頁集合。
已下載網頁集合、已過期網頁集合都好說,待下載網頁集合指待抓取URL列表中的網頁,而可知網頁集合指那些通過待抓取網頁的鏈接信息最終會被抓取到的網頁。
爬蟲也大致分為三種,批量型爬蟲、增量型爬蟲和垂直型爬蟲。
批量型爬蟲有比較明確的抓取范圍和目標,達成目標即停止。增量型爬蟲會保持持續不斷的抓取,對于抓取到的網頁,要定期更新。垂直型爬蟲關注特定主題內容或屬于特定行業的網頁。
爬蟲通常需要保護被抓取網站的部分私密性,并減少被抓取網站的網絡負載。比如遵守網頁禁抓標記,并考慮被抓取網站的負載。
爬蟲質量的評價標準主要有三個:抓取網頁覆蓋率、抓取網頁時新性及抓取網頁重要性。盡可能抓取重要的頁面,盡可能及時地更新其內容,在此基礎上,盡可能擴大抓取范圍。
抓取策略
比較有代表性的抓取策略有廣度優先遍歷策略、非完全PageRank策略、OPIC策略以及大站優先策略。
廣度優先遍歷策略
上面說的『將新下載網頁包含的鏈接追加到待抓取URL隊列末尾』就是廣度優先遍歷的思想。
非完全PageRank策略
PageRank是種著名的鏈接分析算法,用來衡量網頁的重要性,我們希望利用PageRank的思想來對URL優先級進行排序,但是PageRank是個全局性算法,如果我們特別的只在已下載的網頁和待下載網頁形成的網頁集合進行PageRank計算,這就是非完全的PageRank策略的思想,當計算完成后,將待下載,也即待抓取URL隊列里的網頁按照PageRank值由高到低排序。
有幾點需要注意,一個是如果每次新抓取到一個網頁,就將所有已經下載的網頁重新計算非完全PageRank值,這樣效率太低。折中的辦法是,每當新下載的網頁攢夠K個,然后重新計算非完全PageRank值。第二個是,既然PageRank計算不是即時的,如果從新下載的網頁中抽取的鏈接重要性非常高,我們通過匯總這個網頁所有入鏈的PageRank值,給它一個臨時PageRank值,如果這個值高于隊列中網頁的PageRank值,那么優先下載這個URL。
OPIC策略(Online Page Importance Computation)
我們可以將OPIC看做一種改進的PageRank算法,我們為每個頁面都給予相同的權重,每當下載了某個頁面P后,P將自己擁有的權重平均分給頁面中所包含的鏈接頁面。對于待抓取URL隊列中的網頁,則根據權重值排序,優先下載最高權重的網頁。
OPIC的思路與PageRank基本一致,區別在于OPIC不需要迭代計算直到收斂,所以計算速度遠遠快于PageRank,適合實時計算使用。OPIC效果略優于廣度優先遍歷。
大站優先策略
以網站為單位來衡量網頁重要性,對于待抓取URL隊列中的網頁,根據所屬網站歸類,如果哪個網站等待下載的頁面最多,則優先下載這些鏈接,也即傾向于優先下載大型網站。
網頁更新策略
爬蟲需要保證本地下載的網頁和原網頁的一致性,網頁更新策略的任務是要決定合適重新抓取之前已經下載過的網頁,以盡可能使本地下載網頁和互聯網原始頁面內容保持一致。
通常采用的方法有:歷史參考策略、用戶體驗策略和聚類抽樣策略。
歷史參考策略
傾向于認為,過去頻繁更新的網頁將來也會頻繁更新,通過參考其歷史,利用泊松過程來對網頁變化進行建模,根據每個網頁過去的變動情況,預測將來核實內容會再次發生變化。
用戶體驗策略
一般來講,對于搜索結果,用戶往往只查看前三頁,所以對于影響越厲害的網頁,我們應該優先調度重新抓取。
聚類抽樣策略
聚類抽樣策略給出了在網頁沒有歷史信息的情況下,網頁更新的策略。聚類抽樣策略認為,網頁具有一些屬性,根據這些屬性可以預測其更新周期,具有相似性的網頁,其更新周期也是類似的。
所以我們對網頁進行聚類,以同一類別內采樣網頁的更新頻率作為類別內所有其他網頁的更新周期。
暗網抓取
所謂暗網,就是目前搜索引擎爬蟲按照常規方式很難抓取到的互聯網頁面,即很難有顯式的鏈接指向。比如數據庫內的記錄,往往是服務器提供查詢頁面,只有用戶按照需求輸入查詢之后,才可能獲得相關數據。
查詢組合問題
比如垂直搜索網站往往會給用戶提供多個查詢輸入框,用于輸入各種屬性來篩選結果。對于暗網爬蟲,一個簡單粗暴的方式就將所有可能的輸入值排列組合。但是很多組合是無效的,也會對被訪問網站造成巨大的流量壓力。
Google提出了富含信息查詢模板(Informative Query Templates)技術,其基本思路是,對于某個固定的查詢模板來說,如果給模板內每個屬性都賦值,形成不同的查詢組合,觀察返回結果,如果相互之間內容差異較大,則這個查詢模板就是富含信息的查詢模板。
這樣做是為了防止多次查詢的返回結果重復內容太多,導致效率低下。
Google的技術方案采用了ISIT算法,ISIT算法與《淺談機器學習基礎》中講過的Apriori算法相似:首先從一維模板開始,對一維查詢模板逐個考察,去掉不富含信息的查詢模板,然后將剩下的一維模板擴展到二維,再依次考察對應的二維模板,如此類推。
這樣就可以找到絕大多數富含信息的查詢模板,同時也盡可能減少了提交的查詢總數。
文本框填寫問題
我們往往需要人工提供一些提示,爬蟲根據初始種子詞表,向垂直搜索引擎提交查詢,并下載返回的結果頁面,然后從返回結果頁面里自動挖掘出相關的關鍵詞,并形成一個新的查詢列表,如此循環往復。
分布式爬蟲
面對海量待抓取網頁,只有采取分布式架構,才有可能在較短時間內完成一輪抓取工作。
大型分布式爬蟲分為三個層級:分布式數據中心,分布式抓取服務器和分布式爬蟲程序。整個爬蟲系統由全球多個分布式數據中心共同構成,每個數據中心又由多臺高速網絡連接的抓取服務器構成,每臺服務器又可以部署多個爬蟲程序。
對于同一數據中心的多臺抓取服務器,又主要存在兩種不同架構,主從式分布爬蟲和對等式分布爬蟲。
主從式分布爬蟲是有一臺專門的服務器提供URL分發服務,其他機器則進行實際的網頁下載。這種架構中,URL服務器容易成為整個系統的瓶頸。
而在對等式分布爬蟲體系中,服務器之間不存在分工差異,每臺服務器承擔相同的功能。我們對網址的主域名進行哈希計算,之后按服務器個數取模,來給對應的服務器分配任務。但是這樣如果部分服務器宕機,或是要添加新的服務器,致使服務器的個數發生了變化,這樣就會導致幾乎所有的任務都需要進行重新分配,導致資源極大的浪費。
為了解決這個問題,我們放棄哈希取模方式,轉而采用一致性哈希方法來確定服務器的分工。
一致性哈希方法將網頁的主域名進行哈希,映射為一個范圍在0到2^23之間的某個數值,并認為0和最大值重合,將其看做有序的環狀序列。每個服務器負責這個環狀序列的一個片段,并且,如果某臺服務器除了問題,那么本該由這臺服務器負責的URL由順時針的下一臺服務器接管,并不會對其它服務器的任務造成影響。
搜索引擎索引
索引是搜素引擎最重要的核心技術之一,搜索引擎的索引其實就是實現單詞-文檔矩陣的具體數據結構表示,可以采用不同的方式來表示單詞與文檔之間的包含關系,比如倒排索引、簽名文件、后綴樹等方式,但倒排索引經實驗證明是最佳的映射關系實現方式。
倒排列表
我們首先利用分詞系統將文檔自動切分成單詞序列,這樣每個文檔就轉換為由單詞序列組成的數據流。然后我們為每個不同的單詞賦予唯一的單詞編號,同時記錄下哪些文檔包含這個單詞,如此處理結束后,我們可以得到最簡單的倒排列表。
這只是最簡單的倒排列表,只是記錄了哪些文檔包含了這個單詞,除此之外,還可以記錄單詞在對應文檔內的詞頻信息、出現位置和文檔頻率。詞頻就是TF-IDF中的TF,而文檔頻率就是TF-IDF中的DF,也即多少個文檔包含某個單詞。
在實際的搜索引擎系統中,也并不存儲倒排索引項中的實際文檔編號,而是代之以文檔編號差值(D-Gap),文檔編號差值是倒排表中相鄰的兩個倒排索引項文檔編號的差值,一般這些編號差值都是大于0的整數。
單詞詞典
單詞詞典是倒排索引中非常重要的組成部分,它用來維護文檔中出現過的所有單詞的相關信息,并記載某個單詞對應的倒排列表在倒排文件中的位置信息。
哈希加鏈表
這種詞典結構主要由哈希表和沖突鏈表組成,沖突鏈表的存在是因為單詞的哈希值可能會有沖突。我們根據函數的哈希值找到單詞在哈希表中的位置,表中會給出沖突表的指針,在沖突表中單詞的對應位置可以讀出其對應的倒排列表。
樹形結構
B+樹是另外一種高效查找結構,它需要詞典項能夠按照大小排序(數字或字符序)。B+樹形成了層級查找結構,中間節點不保存內容,只用于指出一定順序范圍內的詞典項目存儲在哪個子樹中,起到依據詞典項比較大小進行導航的作用。最底層的葉子節點存儲內容信息。
建立索引
兩遍文檔遍歷法
這種方法完全在內存里完成索引的創建過程。
第一遍文檔遍歷的時候,并不立即開始建立索引,而是收集一些全局的統計信息。比如文檔集合中包含的文檔個數,文檔集合所包含的不同單詞個數,每個單詞在多少個文檔中出現過。將所有單詞對應的文檔頻率(DF)值全部相加,就可以知道建立最終索引所需的內存大小是多少,于是在內存中分配足夠大的空間用于存儲倒排索引內容。第一遍文檔遍歷主要做些資源準備工作。
第二遍掃描的時候,開始真正建立每個單詞的倒排表信息,第二遍掃描結束的時候,分配的內存空間正好被填充滿。
兩遍掃描完成后,即可將內存的倒排列表和詞典信息寫入磁盤。因為其需要兩遍掃描,所以速度上不占優勢,而且對內存占用過大,實際系統中這種方法并不常見。
排序法
排序法對兩遍文檔遍歷法的內存占用做了優化,該方法始終在內存中分配固定大小的空間,用來存放詞典信息和索引的中間結果。當分配的空間被耗光的時候,把中間結果寫入磁盤,清空內存里中間結果所占的空間,以便存儲下一輪的中間結果。
所謂的中間結果在這里是(單詞ID、文檔ID、單詞頻率)的三元組,在清空寫入磁盤之前,三元組需要依次按照單詞ID、文檔ID、單詞頻率進行排序,我們將排好序的三元組寫入磁盤。
對于排序法而言,詞典是一直存儲在內存中的,耗光了分配的內存空間,也只是將中間結果寫入磁盤。所以,越往后,可用來存儲三元組的空間是越來越小了。
之所以要對中間結果進行排序,是為了方便最后的合并。合并完成后,就形成了最終的索引文件。
歸并法
排序法中,詞典信息一直在內存中進行維護,就會導致后期中間結果可用的內存越來越少。歸并法對此做了修改,即每次包括詞典在內的所有中間結果信息都被寫入磁盤。
在最終合并的時候,排序法是對同一單詞的三元組依次進行合并,而歸并法的臨時文件則是每個單詞對應的部分倒排列表進行合并,形成這個單詞的最終倒排表,歸并法在合并的過程中形成最終的詞典信息。
動態索引
真實環境中,在索引建立好之后,后續仍不斷有新文檔進入系統,同時原先的文檔集合有些被刪除或者修改。所以我們需要動態索引來將文檔變化在非常短的時間內體現出來。
動態索引往往有三個關鍵的索引結構:倒排索引、臨時索引和已刪除文檔列表。
當有新文檔進入系統時,將其追加在臨時索引結構中,當有文檔被刪除,則由已刪除文檔列表以ID的形式保存,文檔的內容更改可被認為是先刪除后添加。
如果用戶輸入查詢請求,則搜索引擎同時從倒排索引和臨時索引中讀取用戶查詢單詞的倒排列表,找到包含用戶查詢的文檔集合,并對兩個結果進行合并,之后利用已刪除文檔列表進行過濾。
索引更新策略
常用的索引更新策略有4種:完全重建策略、再合并策略、原地更新策略以及混合策略。
完全重建策略是當新增文檔到達一定數目的時候,將新增文檔和老文檔進行合并,然后對所有文檔重新建立索引。這是目前主流搜索引擎采用的方法。
再合并策略是達到一定條件后,將臨時索引和老文檔的倒排索引進行合并,以生成新的索引。
原地更新策略的基本出發點是為了改進再合并策略的缺點,即在索引更新過程中,如果老索引的倒排列表沒有變化,那就可以不需要讀取這些信息,只在其末尾進行追加。
但是這樣會破壞了單詞索引的連續性,因為不可能預留無限大的空間使其可以一直往后追加,所以就必須做數據遷移,這樣導致了進行索引合并時不能順序讀取,反而降低了磁盤讀取速度,而且還需要大量的內存來記錄位置的對應關系。
混合策略是針對不同類別的單詞,對其索引采取不同的索引更新策略。比如,倒排列表較長的單詞用原地更新策略,短倒排列表單詞則采取再合并策略。
查詢處理
為搜索引擎建立索引,其目的是能更快速地提取與用戶查詢相關的文檔信息。目前有兩種常見的查詢處理機制,一種被稱作一次一文檔方式,另外一種被稱為一次一單詞方式。
一次一文檔
搜索引擎接收到用戶的查詢后,首先將兩個單詞的倒排列表從磁盤讀入內存,以倒排表中包含的文檔為單位,每次將其中某個文檔與查詢的最終相似性計算完畢,然后開始計算另外一個文檔的最終得分,知道所有的文檔都計算完畢為止。
在計算過程中始終保留得分最高的K個文檔即可。
一次一單詞
一次一單詞方式首先將某個單詞對應的倒排列表中的每個文檔ID都計算一個部分相似性得分,待計算下個單詞的倒排列表時,對于每個文檔,在原先得分基礎上進行累加。當所有單詞都處理完畢后,每個文檔的最終相似性得分計算結束,之后輸出得分最高的K個文檔作為搜索結果。
跳躍指針
如果用戶輸入的查詢包含多個單詞,那搜索引擎一般是采用與邏輯來判別文檔是否滿足要求,也即需要同時包含所有查詢詞。
對于這種應用場景,一次一文檔的查詢方式是更合適的,因為一次一單詞的查詢方式會浪費大量計算資源在根本不滿足條件的文檔上。
如果倒排列表直接存儲包含查詢詞的文檔的ID,那么計算交集是十分簡單和直觀的,但是前面也說過,我們的文檔ID是以文檔編號差值(D-Gap)形式存儲的,另外這個差值我們還要進行壓縮的。為了求交集,我們得先將若干個倒排表全部解壓縮,然后再將其由D-Gap恢復為文檔ID,再求交集。
跳躍指針的引入可加快列表求交集這一計算過程。
跳躍指針的基本思想是將一個倒排列表數據化整為零,切分成若干個固定大小的數據塊,對于每個數據塊,增加元信息來記錄關于這個塊的一些信息,這樣可以快速找到相應文檔所在的數據塊,也不再需要對整個倒排列表進行解壓。根據元信息,可以確定數據塊所對應的文檔的范圍,找到所需查詢的文檔所對應的數據塊之后,也只需要對該數據塊進行解壓,解壓出來的D-Gap值與元信息結合,就能恢復原本的文檔ID。
多字段索引
在很多實際的搜索應用領域,搜索引擎要處理的文檔是有一定結構的,即文檔包含多種類型的字段,比如郵件的『發件人』、『收件人』、『標題』、『正文』等,我們希望能夠按類型進行搜索。為了滿足這樣的需求,搜索引擎需要能夠對多字段進行索引,常用的的方法有:多索引方式、倒排列表方式和擴展列表方式。
多索引方式也即分別建立多種類別的索引,但是如果用戶沒有指定特定字段,那就要綜合所有字段的索引給出結果,所以效率會較低。
倒排列表方式是在每個文檔索引項信息的末尾追加字段信息(比如標識位),以此來進行過濾。
擴展列表方式是實際中應用得比較多的支持多字段索引的方法。這個方法為每個字段建立一個列表,這個列表記載了每個文檔這個字段對應的出現位置信息。
短語查詢
有些短語,順序顛倒就會產生完全不同的含義,前面講的索引查詢方法只能找到交集,并無法支持特定順序。
位置信息索引
前面我們講的倒排列表往往存儲文檔ID、單詞頻率和單詞位置信息。依照單詞位置信息就可以幫我們完成短語查詢,比如發現根據單詞位置信息發現兩個單詞是相鄰并具有特定順序關系。但是存儲單詞位置信息實際上會對單詞倒排列表的長度產生影響,并且計算代價相當高。
雙詞索引
一般而言,二詞短語在短語中所占比例最大,我們可以建立雙詞索引來滿足二詞短語的查詢需求:
首詞詞典指向下詞詞典的某個位置,下詞詞典存儲了緊跟在首詞后面的第二個詞,下詞的詞典指針用來指向包含這個短語的倒排列表。比如用戶輸入『我的父親』,先將其拆成兩個短語『我的』和『的父親』,分別查找詞典信息,發現『我的』這個短語出現在文檔5和文檔7,而包含『的父親』的文檔中又包含文檔5,看起對應的出現位置,可以發現其滿足需求。
雙詞索引同樣使得索引急劇增大,所以一般只用雙詞索引處理包含『我』、『的』等停用詞的短語。
短語索引
我們也可以直接在索引中加入短語索引,這樣的缺點在于并不可能實現將所有的短語都建好索引,通用的做法是挖掘出熱門短語,為這些短語專門建立索引。
混合索引
分布式索引
當搜索引擎需要處理的文檔集合數量非常龐大時,單機往往難以承擔維護整個索引的任務。所以需要分布式的解決方案。
有兩種經典的劃分方式,一種是按文檔劃分,也即將整個文檔集合切割成若干子集合,每臺機器負責對某個文檔子集建立索引,并相應查詢請求;另一種是按單詞劃分,每個索引服務器負責詞典中部分單詞的倒排索引列表的建立和維護。
按文檔劃分的方式在多種條件下基本都優于按單詞劃分的方式。舉個例子,比如某臺索引服務器宕機,如果采用按文檔劃分的方式,部分單詞的搜索結果中會少掉一部分文檔,這部分文檔還不一定是排在前面的文檔,影響不會很大。但是如果采用的是按單詞劃分的方式,那這些單詞的搜索結果會完全丟失,用戶無法使用這些關鍵詞進行查詢,對用戶體驗的影響要大的多。
索引壓縮
詞典壓縮
如果我們按照上圖的方式存儲倒詞典,那存儲單詞的空間必然要按照最長單詞的長度來分配,這樣就會造成大量的空間浪費。
在詞典壓縮這種技術方案里,可以將單詞連續存儲在某個內存區域,原先存儲單詞內容的部分由指向這個存儲區對應單詞起始位置的指針代替,單詞結尾可以用詞典中下一個單詞的指針所指向的位置來做判斷。如此就可以將原先浪費的存儲空間利用起來。
在上面的基礎上,我們還可以繼續做出改進,我們可以將連續詞典進行分塊,在實際開發時,動態調整分塊大小,而且原先每個詞典項需要保留一個指向連續詞典區的指針,分塊之后,同一塊的詞典項可以共享同一個指針,每節省一個指針,就節省了4字節長的空間,此外,因為同一塊內有多個單詞,所以我們需要標識出單詞的長度以便于區分。
經過上述優化的詞典比不做優化的詞典占用內存數量減少了60%。
倒排列表壓縮
倒排列表往往記載三類信息:文檔編號、詞頻信息及單詞位置序列信息,因為文檔編號及單詞位置序列都是依次遞增的,所以通常的做法是存儲其差值,而非原始數據。這樣文檔編號和單詞位置信息往往會被轉換成大量的小整數,使得數字分布嚴重不均衡。
評價索引壓縮算法的指標通常由三個:壓縮率、壓縮速度和解壓速度。其中解壓速度在3個指標中是最重要的。
一元編碼和二進制編碼是所有倒排列表壓縮算法的基本構成元素,一元編碼是,使用x-1個二進制數字1和末尾一個數字0來表示這個整數。比如5編碼為11110。
二進制編碼方式就是利用二進制進行編碼。
Elias Gamma 算法與 Elias Delta 算法
Elias Gamma采用的分解函數是:x=(2^e)+d
對因子e+1用一元編碼來表示,對于因子d采用比特寬度為e的二進制編碼來表示。比如9編碼為1110:001
Elias Delta是在Elias Gamma基礎上的改進,它對因子e+1利用Elias Gamma再次進行壓縮。比如9編碼110:00:001,從左到右,110是3,110:00是4(22),110:00:000是8(23),110:00:001是9。
Golomb 算法與 Rice 算法
Golomb算法與Rice算法與上述兩個算法相似,只是分解函數不同,就不詳述了。
變長字節算法
實際上就是128進制:
SimpleX 系列算法
SimpleX系列算法最常見的是Simple9,Simple9是一種字對齊算法,字對齊也就是我們通常使用的表示數字的方式,比如128是一百二十八。Simple9最常用的是利用32個比特位,來作為壓縮單位,給定固定大小的壓縮單位后,每個壓縮單位試圖存儲多個待壓縮的數字:
前四位是指示位,用于表明B是多少,即數據存儲區基本構成單元比特寬度是多少。如果數字均為0或1,那用B=1就可以存儲,可以同時存儲28位數字;如果B=2,可以存儲14個范圍在0至3的數字,以此類推。
這個算法可以同時壓縮/解壓多個數字。
PForDelta 算法
PForDelta 算法是目前解壓速度最快的一種倒排文件壓縮算法。
前面講的SimpleX算法,實際上,一次壓縮多個數值面臨困難,因為連續的數值序列有大有小,如果每個數值按照序列中最大的數值來決定比特寬度,很明顯對小數值來說會存在空間浪費的情形。
PForDelta希望能在壓縮率和壓縮解壓速度方面找到一個平衡點,對于待編碼的連續K個數值(一般K取128,即一次性壓縮解壓128個數值),先去除其中10%比例的大數,根據剩下90%的數值決定該采取的比特寬度,而10%的大數當做異常數據單獨存儲:
我們將大數放在異常數據存儲區,但也要記載這些數在原始序列中的位置信息,這樣解壓的時候能夠快速恢復原始數據。
文檔編號重排序
我們前面提到了D-Gap,我們用D-Gap來存儲文檔ID,經過前面的PForDelta,我們也知道,數字越小越容易壓縮,所以我們希望對文檔編號重排序,使得同一個單詞倒排列表中的文檔編號都盡可能盡可能相近,所得到的D-Gap值也就小了。
為了達到這個目的,我們希望內容越相似的網頁,在編排文檔編號時,其文檔編號越相鄰。計算相似性的方法很多,比如TF-IDF。
靜態索引裁剪
前面講的壓縮方法都是無損壓縮,這個方法是有損壓縮,通過主動拋棄一部分不重要的信息來達到更好的數據壓縮效果。
因為對于用戶查詢來說,搜索系統往往只需要返回相關性最高的K個網頁,不需要將相關網頁都呈現給用戶。所以可以將那些不重要的索引項聰哥倒排索引中清除掉,只保留重要的索引項。
大體有兩種不同的思路,一種被稱為以單詞為中心的索引裁剪,一種被稱為以文檔為中心的索引裁剪。
以單詞為中心的裁剪,其裁剪對象是單詞對應倒排列表中的文檔。設定一個閾值α,一個折扣因子,相似度低于閾值與折扣因子乘積的文檔被剪除掉,當然要至少保留K個索引項。
以文檔為中心的裁剪,是在建立索引之前,只建立重要單詞-文檔的倒排列表,可以說是一種建立索引之前的預處理措施。而以單詞為中心的裁剪,是在建好的倒排索引基礎上對索引項進行刪除。
檢索模型與搜索排序
搜索結果排序是搜索引擎最核心的構成部分。
搜索結果排序是說,搜索引擎判斷哪些文檔是和用戶需求相關的,并按照相關程度排序輸出,而檢索模型就是用來計算內容相關度的理論基礎及核心部件。
前面所描述的利用索引的查詢方法講述了如何利用索引找到包含查詢詞的文檔,但并沒有說如何計算文檔與用戶查詢的相似度,畢竟包含查詢詞與相關性是兩個獨立的維度:
其實我們需要的是相關文檔,與是否包含查詢詞并無必然聯系,但是搜索引擎所能做到的只是從包含查詢詞的文檔中找出相關文檔,也即只能處理第一三象限的內容,而對于第二四象限,搜索引擎就無能為力了,需要推薦系統來解決這種用戶無法精確描述自己需求的場景,在《淺談推薦系統基礎》中也提到了,比如LDA,就可以發現兩篇完全沒有重復詞匯的文檔的相似性。
這里我們只考慮通過檢索模型來找到在包含查詢詞的文檔之中,與用戶需求相關的部分。
布爾模型
布爾模型是檢索模型中最簡單的一種,其數學基礎是集合論。布爾模型一般使用邏輯表達式,即『與/或/非』這些邏輯連接詞將用戶的查詢詞串聯。對于布爾模型來說,滿足用戶邏輯表達式的文檔就算是相關的。
布爾模型輸出的結果是二元的,要么相關要么不相關,至于文檔在多大程度上和用戶查詢相關,能否按照相似度排序輸出搜索結果,這些布爾模型都無能為力。
向量空間模型
向量空間模型是目前已經非常成熟和基礎的檢索模型,前面反復提到的余弦相似度、TF-IDF,都與向量空間模型有密切聯系。
不嚴謹的講,向量空間模型就是將文檔看做t維特征組成的向量,每個維度的權重采用TF-IDF計算,然后通過余弦相似度計算不同文檔(或與用戶查詢語句)所對應的特征向量之間的相似度。
在搜索引擎的場景里,向量空間模型這一檢索模型利用用戶查詢語句與文檔之間的相似度代替了查詢語句與文檔之間的相關度。
雖然前面已經多次提過余弦相似度和TF-IDF,這里還是簡單說一下,余弦相似度公式是計算兩個向量之間夾角余弦值的公式,通過余弦值可以得到兩個向量之間的夾角,我們可以近似的認為,兩篇文檔特征向量之間的夾角越小,這兩篇文檔的相似性就越高。
TF-IDF分為兩部分理解,首先是TF(Term Frequency,詞頻),也即認為一篇文檔中常出現的詞要比不常出現的詞更能反映該文檔的主題,然后是IDF(Inverse Document Frequency,逆文檔頻率),也即認為在所有文檔中都出現的詞傾向于不能反映一篇文檔的主題。我們結合這兩條思路計算每個特征維度的TF-IDF權重值,也即TF值*IDF值,也即在一篇文檔中常出現(TF高),卻幾乎不出現在其他文檔中的詞(IDF高),最能反映這篇文檔的主題。
概率檢索模型
概率檢索模型是目前效果最好的模型之一。BM25這一經典概率模型計算公式已經在商業搜索引擎的網頁排序中廣泛使用。
概率檢索模型的思想是:給定一個用戶查詢,如果搜索引擎能夠在搜索結果排序時按照文檔和用戶查詢的相關性由高到低排序,那么這個搜索系統的準確度是最高的。
從表述來看,概率檢索模型直接對用戶查詢與文檔的相關性進行建模,而前面的向量空間模型以用戶查詢與文檔的相似性代替了相關性。
也即我們需要估算給定一個文檔,與用戶查詢相關的概率P(R|D),和不相關的概率P(NR|D)。
這是不是和區分垃圾郵件有點像,區分垃圾郵件用的什么?樸素貝葉斯算法,在《淺談機器學習基礎》中有對樸素貝葉斯算法的詳細講解。
這里的二元獨立模型(BIM)與樸素貝葉斯算法基本相同,BIM的二元假設就是詞集模型,以0/1表示單詞出現與否。BIM的詞匯獨立性假設就是樸素貝葉斯假設,或者說是《淺談自然語言處理基礎》中講過的一元文法模型。
在樸素貝葉斯算法中,根據貝葉斯決策理論,只要計算出P(R|D)和P(NR|D),判斷其大小關系即可,但是在BIM中,因為我們還需要對相關性大小進行歸類,所以我們還要計算出P(R|D)/P(NR|D)。
經過化簡取對數等操作后,我們得到如下公式:
其代表的含義是:對于同時出現在用戶查詢Q和文檔D中的單詞,累加每個單詞的相關性估值,其和就是文檔D和查詢的相關性估值。(這里插一句,樸素貝葉斯那里不是連乘嗎,為什么這里是加?因為P(R|D)/P(NR|D)在化簡的時候取了對數)
還有一點,樸素貝葉斯算法是監督學習算法,通過帶標簽的訓練語料得到先驗概率的估計值,但是這里我們沒有帶標簽的訓練語料怎么辦?我們只能把所有文檔都看做是不相似文檔,這樣我們辛辛苦苦計算出來的P(R|D)/P(NR|D)就等價于所有單詞的IDF之和了。
各種實驗表明,BIM計算的相關性實際效果并不好,但這個模型是非常成功的概率模型方法BM25的基礎。
BIM采用詞集模型,只考慮是否在文檔中出現,而沒有考慮單詞的權值。BM25模型在BIM模型的基礎上,考慮了單詞在查詢中的權值以及單詞在文檔中的權值,擬合出綜合上述考慮因素的公式,并引入一些經驗參數。BM25模型是目前最成功的內容排序模型:
BM25模型計算公式其實融合了4個考慮因素:IDF因子、文檔長度因子、文檔詞頻和查詢詞頻,并利用3個自由調節因子(k1、k2和b)對各種因子的權值進行調整組合。
對于二元獨立模型,我們假設相關文檔個數R和包含查詢詞的相關文檔個數r設定為0,這樣第一個計算因子就化成類似IDF的形式。
N代表文檔總數,n代表出現對應單詞的文檔個數,f指文檔中出現對應單詞的詞頻,qf是查詢語句中對應單詞的詞頻,dl是文檔長度。
BM25F模型是BM25的改進算法,它提出了域的概念,它將一篇文檔劃分為若干域,對于不同的域,在計算中給予不同的權值。
語言模型方法
假如利用樸素貝葉斯算法對相關/不相關文檔進行分類,那是要分別計算文檔由相關文檔集生成的概率P(R|D)和由不相關文檔集生成的概率P(NR|D),然后比較其大小。
BIM是因為沒有相關/不相關的標簽,所以將所有訓練文檔都認為是不相關文檔,對于一個測試文檔計算P(R|D)/P(NR|D)。
語言模型方法和上述兩種看起來很相似,但實際上思路不同,語言模型方法嘗試去計算查詢語句由測試文檔生成的概率,概率越大則認為相關性越高。所采用的,就是樸素貝葉斯中計算測試文檔由相關/不相關訓練文檔集生成的概率。(就是假如樸素貝葉斯算法判別時不用貝葉斯決策理論,就只按照測試文檔由相關訓練文檔集生成的概率作為相似度的標準,那么把這種思路的樸素貝葉斯算法中的測試文檔換成查詢語句,相關訓練文檔集換成測試文檔,那就得到了語言模型方法)
既然是語言模型方法,自然要考慮到是以一元、二元還是多元的文法模型為基礎來計算生成概率。除此之外,還必然要考慮到數據平滑問題,這在《淺談自然語言處理基礎》中詳細講過,比如Good-Turing估計法、Katz、Kneser-Ney。
機器學習排序
機器學習排序方法我們簡單介紹一下,過程主要分為四步:人工標注訓練數據、文檔特征抽取、學習分類函數、采用模型進行分類。
通過人工標注大量訓練數據顯然不現實,不過我們可以利用用戶的點擊數據。
機器學習排序方法最大的好處在于,前面的普通檢索模型方法主要考慮了詞頻、逆文檔頻率和文檔長度這幾個因子來擬合排序公式,因為考慮的因素不多,所以人工擬合的方式可行,但是隨著搜索引擎的發展,對于某個網頁進行排序所考慮的因素越來越多,比如網頁的PageRank值、查詢和文檔匹配的單詞個數、網頁URL鏈接地址長度都會對網頁排名產生影響,那使用人工擬合的方法就很難行得通了。
先簡述一下機器學習排序的思路,我們先將一篇篇文檔轉換成特征向量,比較常用的特征包括:
- 查詢詞在文檔中的詞頻信息
- 查詢詞的IDF信息
- 文檔長度
- 網頁的入鏈數量
- 網頁的出鏈數量
- 網頁的PageRank值
- 查詢詞的Proximity值,即在文檔中多大的窗口內可以出現所有的查詢詞
有了文檔的特征向量之后,接下來的處理方式可以分為三種思路:單文檔方法、文檔對方法和文檔列表方法。
單文檔方法
單文檔方法就是最先想到的機器學習方法,我們有了文檔的特征向量,我們也有了文檔的標注結果:相關/不相關。那我們就可以訓練出一個模型出來判斷文檔的相關性,比如用SVM或者LR都可以。如果可以給出得分,那么得分大于某個閾值為相關,小于則為不相關。LR給出得分很簡單,SVM其實也應該可以根據函數距離的大小來給出相應的可信度得分。
文檔對方法
文檔對方法的核心思想是,給定一個查詢和文檔對<Doc1,Doc2>,我們需要判斷這種順序關系是否合理,也即Doc1排在Doc2前面合不合理。
文檔列表方法
單文檔方法將訓練集里每一個文檔當做一個訓練實例,文檔對方法將同一個查詢的搜索結果里任意兩個文檔作為一個訓練實例,而文檔列表方法是將每一個查詢結果對應的所有搜索結果列表整體作為一個訓練實例。
文檔列表方法的目的是盡量使得機器學習模型對搜索結果的打分順序和人工打分順序盡可能相同,也即模型預測的搜索結果的排列順序與人工標注的排列順序盡可能相同。
結果表明,基于文檔列表方法的機器學習排序效果要好于前述兩種方法。
檢索質量評價標準
準確率和召回率,這兩個就不說了,除此之外還有P@10和MAP。
P@10就是看前10個文檔當中,有多少個文檔是相關文檔,有多少個相關文檔,P@10就是十分之幾。
MAP指標稍微復雜一點,MAP是衡量多個查詢的平均檢索質量的,而AP是衡量單個查詢的檢索質量的。假設用戶搜索結果中有3個文檔是相關的,它們應該排在第1、2、3位,那(Σ(理論位置/實際位置))/相關文檔個數,就是這次查詢的AP值。
對多次查詢的AP值取平均,就得到了MAP值。