搜索引擎告訴你如何大海撈針
?如果問你這個問題:
像搜索引擎這樣的全文搜索底層原理到底是什么?
對于有經驗的人來說,很輕松的就能回答這個問題。因為現代的搜索引擎基本都是采用倒排索引來實現的。那什么是倒排索引呢?
建立倒排索引
有的同學看到「倒排」兩個字可能有點慌。
我知道你很急,但你先別急(bushi)
這個不是「倒排需求」的倒排,而是「倒排索引」的倒排。假設我們現在有 3 個網頁,包含了如下很簡單的內容:
三個文檔
現在假設我們要對網頁中的內容進行搜索,第一步需要做什么呢?當然是建立索引,沒有索引你還想大海撈針?想 peach,相信大家對索引應該不陌生,大家平時看書時看到的目錄,是一種索引,MySQL 當中的聚簇索引和非聚簇索引也是一種索引。
廢話不多說,直接看人肉手動分詞 + 建立道倒排索引之后的結果:
對三個文檔簡歷好索引之后的效果
假設現在要搜索 jump 這個詞,那么最終就會把網頁 1、2 展示給你,因為 jump 在兩個網頁中都出現過。這就是很簡單的一個倒排索引的例子。
搜索連續的詞怎么辦?
可能大家還沒有意識到這個問題在哪里,我們舉個例子來看看。在搜索引擎里搜索的時候,我們輸入 i jump? 和 "i jump"? 是不同的概念。前者代表包含了 i? 和 jump? 兩個詞的網頁,后者代表了單詞 i? 后緊跟 jump? 的網頁。例如,搜索 i jump? 預期會把上面 3 個網頁全部搜索出來,而搜索 "i jump" 則只會搜索出網頁 3.
此時我們思考一個問題,搜索引擎是如何實現上面功能的呢?在上面的索引表中,只有哪些詞出現在了哪些網頁當中,卻并沒有詞語位置的相關信息。
所以,只記錄詞語出現在哪些網頁中是遠遠不夠的。為了滿足上面精確到詞語位置的查詢需求,讓我們把詞語的位置也一起寫入到索引中,如下所示:
將詞語的位置加入到倒排索引當中
這樣以來,當我們搜索 "i jump" 時,我們就能夠通過索引中記錄的位置來搜索相鄰的詞語,如下圖所示:
根據有位置記錄的索引來搜索相鄰的詞語
詞語 I? 在 3-3? 的位置,而 jump? 在 3-4,由此就可以推斷,這兩個詞在同一個網頁的相鄰的位置了。
只搜索標題的內容怎么辦?
現在 Google 是支持這種搜索的,查詢的格式如下:intitle:${search_content},大家可以去嘗試一下。
那這個到底是怎么實現的呢?
很顯然上面的索引是無法滿足只搜標題這個需求的,因為它無法判斷當前這個詞是標題還是正文,那這個到底是怎么實現的?
首先,我們得知道如何標識「標題」。如果我們在現在的網友上右鍵,選擇查看源代碼,你就會看到 HTML,這才是網頁的“真面目。網頁的標題會用 <title></title>? 標簽給包裹起來,而正文會用 <body></body> 標簽給包裹起來,那比如我們現在給上面的 3 個網頁加上 title 標簽,那么網頁就會變成這樣:
帶 title body 標簽的 HTML 網頁
既然網頁的內容發生了“變更”(實際上沒有,因為它本來就應該長這樣,只不過為了滿足循序漸進的講解才這么說),那么索引也自然需要更新一下。因為本質上我們需要知道哪些詞是標題,那么新增了這部分信息的索引就如下所示:
添加了標題信息的倒排索引
可以看到,標題的文本、以及標識標題的標簽都被寫入了索引,通過這些信息我們就能夠判斷當前的詞是否是標題。比如舉個例子,我們搜索 intitle:Caesar?,這個時候首先會通過索引找到詞語 Caesar?,發現它只出現在網頁 2 的位置 2,那么我們再對比 <title>? 和 </title>? 出現的位置我們會發現,2-2 剛好在標題的范圍內:
通過標題位置的索引來只搜索標題
這樣以來,我們就能夠將搜索的范圍限制在標題內了。
當然,這個只是搜索的操作,搜索引擎還有另一個重要的組成部分 —— 排序,對于搜索出的結果如何將用戶最需要的、最相關的排在最前面也是技術含量很高的操作,后續有機會繼續分享一下。