這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
從零開始,寫一個搜尋引擎 (0x01)
第零部分我們已經列了一個提綱了,這一篇文章開始要詳細說說了。
搜尋引擎基本概念
在說搜尋引擎架構分層之前,我們先確定幾個搜尋引擎的概念。
文檔,搜尋引擎的基本資料單元,比如一張網頁,一個商品,多個文檔合在一起就是一個搜尋引擎的完整資料
倒排索引,正排索引,儲存在搜尋引擎內部的資料結構,也是搜尋引擎最底層的資料結構。
索引器,將文檔資料產生可供搜尋的倒排索引和正排索引的程式就是索引器。
檢索器,通過對倒排索引和正排索引進行尋找,從而尋找到文檔的程式。
欄位,每個文檔可能有多個欄位,比如一篇文章有標題,作者,摘要,詳情,發布時間的,這些東西雖然在一個文檔中,但是搜尋的時候需要區別對待。
索引,多個文檔通過索引器產生了一堆倒排正排索引,我們把這些倒排正排索引的集合叫索引,如果後面提到索引就是指正排和倒排索引的集合,索引也可以理解為資料庫中的表。
好了,上面就是搜尋引擎的最基本的概念,搜尋引擎簡單的說分成兩部分,一部分就是索引器把文檔變成倒排和正排檔案,第二部分就是檢索器通過倒排和正排檔案還原文檔的過程。
搜尋引擎設計分層
資料庫其實也是一個搜尋引擎,只是資料庫和搜尋引擎的側重點不太一樣,搜尋引擎追求的是簡單,速度快,而資料庫追求的是穩定和複雜邏輯對資料的處理,所以應用情境不太一樣。
既然知道了一個搜尋引擎的基本概念,應該怎麼來設計這個搜尋引擎呢?
按照一般的軟體設計邏輯,如果不是非常複雜的系統,要設計一個系統,首先要設計資料結構,然後把資料結構封裝到各個演算法和類中,然後將各個類組合起來就完成了,所以,我設計這個引擎,是基於以下幾個層次來的。
首先需要一個底層的資料層,用來儲存倒排索引和正排索引,每個欄位都會建立相應的倒排和正排索引,這一部分應該有一系列相關的模組來實現;
所有欄位的倒排索引和正排索引合起來就是整個資料檔案,然後需要一些模組來對這些東西進行管理;
然後由於在第一篇文章中我們說了希望索引器和檢索器都在這裡,類似Elasticsearch的實現,所以也使用了分段的方式管理文檔的索引,每到一定的條件下將索引重新整理到磁碟或者將索引合并起來。
我們還需要一個引擎的東西來管理多個索引,引擎負責複雜的查詢策略和排序策略,這個引擎是可以更換和修改了,只需要實現標準介面就行,也可以自己實現來替換預設的引擎達到更多的功能,甚至你能自己寫一個引擎,實現SQL查詢。
最後還需要一個和外界互動的層,我實現的是一個http伺服器來和外部互動,互動的資料通過json來進行,這一層也可以重寫成任何你需要的樣子。
按照上面這些個模組,一個搜尋引擎,在整體架構上大約分成以下幾個層次
首先,最底層的是資料模組層,負責引擎內所有的資料描述,對於搜尋引擎來說,資料分為倒排索引和正排索引,也叫逆向索引和正向索引,為了方便,我們這統一叫倒排索引和正排索引。
在這一層之上是欄位層,每一個欄位對應了一個正排索引和一個倒排索引(可選),因為有些欄位只需要展示出來而不需要進行搜尋是不需要倒排的。
在欄位層之前有個段的層來對這些欄位進行管理,段有的在記憶體中,有的重新整理到磁碟上了。
段層之上就是索引模組層了,這一層對上提供一些基本的增加,刪除,修改,尋找的介面。
索引模組層之上是引擎層,這一層實現具體的業務尋找邏輯。
最上面是一個網路層,負責和外界進行互動。
在實現的時候,為了盡量簡單,每個模組基本上都是一個檔案來實現的,用了Golang以後,代碼寫起來也自由起來了,只要清晰就行,所以整個引擎下來,代碼量其實不是很大。
下面這個圖就是整個代碼的大架構圖,後面我們會一個一個的來講這些東西。
通過這一篇文章,希望能對搜尋引擎有個初步的瞭解了,後面我會一個一個模組一個一個技術點的來拆分一下這個搜尋引擎。
接下來的文章會開始介紹搜尋引擎的底層技術了,倒排索引【會花比較多精力來說倒排索引,畢竟這是核心的核心】,正排索引【這個簡單,就是數組】,在介紹的時候會有幾篇文章介紹實現倒排索引技術需要的一些演算法和資料結構。
代碼託管在github上,地址是https://github.com/wyh267/FalconEngine,代碼還在不斷更新中,目前代碼量,去掉單元測試檔案,大約是6000行,因為是想到哪寫到哪,有些函數也沒有用,所以還有最佳化空間,也希望大家提交你的patch,後面講的時候可以對照代碼看看。
代碼結構如下,再說一遍,代碼量不大,結構也非常簡單,雖然我寫的代碼注釋不多,但是沒有使用任何進階功能,閉包都沒有,直接看沒任何難度。
文章的更新頻率會在一周3到5篇左右吧,歡迎大家掃描一下下面的公眾號訂閱,首先會在這裡發出來:)