本篇較長較枯燥,請保持耐心看完。git
前面兩章介紹了一下倒排索引以及倒排索引字典的兩種存儲結構,分別是跳躍表和哈希表,本篇咱們介紹另外一種數據結構,他也被大量使用在信息檢索領域,我在github
上實現的搜索引擎的詞典也是用的這個數據結構,它就是B+樹。github
首先,咱們看看什麼是樹,樹是程序設計中一個很是基礎的數據結構,記得大學時候的數據結構課,鏈表,棧,隊列,而後就是樹了,雖然那時候想必你們都被前序遍歷,中序遍歷,後序遍歷折騰過,不過樹確實是一種很是有用的數據結構。算法
上一篇咱們說過,表2的第一列首要解決的問題就是能快速找到對應的詞,而後找到對應詞的倒排列表,除了跳躍表和哈希表,B+樹也能知足條件,B+樹是B樹的變種,咱們B樹咱們就不看了,感興趣的你們能夠直接去google一下,咱們主要講的是B+樹,下圖就是一個3層的B+樹,我畫出來可能和你們搜出來的有點出入,可是不要緊,關鍵B+樹這種數據結構的思想你們瞭解了就行。sql
假設咱們有一組數字 34,40,67,5,37,12,45,24,那麼,把他們存成B+樹就是下圖這個樣子。數據庫
咱們很明顯看到幾個特色編程
我儘可能的把B+樹說簡單點,網上的資料也好,查書也好,看上去都挺複雜的,首先咱們看看怎麼創建這棵樹,我儘可能用圖了,少一些文字也好理解一點,前方大量圖預警。數組
首先,咱們的數組是34,12,5,67,37,40,45,24服務器
####第一步,初始化B+樹,是這樣子的微信
這時候,啥也沒有,可是佔用了兩個節點,標識爲無的,表示這個元素無心義,標記爲NULL表示無窮大cookie
####第二步,插入34這個元素,那麼圖變成這樣子
咱們看到,插入的過程是順着指針一直走到葉子節點,發現葉子節點是空的,而後把元素插入到葉子節點的頭部,而後返回上一級節點,將NULL後移,而後把第一個元素置爲他的子節點的最大值,請記住這句話:置爲他的子節點的最大值
####第三步,接着插入第二個元素12
這個步驟複雜一點
####第四步,而後是插入5
這一步更復雜一點,產生了分裂
####第五步,接着咱們插入67
這一步比較簡單
####第六步,咱們插入37,插完這個後面的我就不寫了,感興趣能夠本身畫一下
這一步複雜了,這一步不只分裂了,並且分裂了兩次,而且層數增長了一層
按照這六步,前5個元素就插入到B+樹中了,後面的步驟您能夠本身走一走,B+樹基本的思想就是這樣子的,可能我沒有按照教科書上的作法來講,但這並不影響你們的理解,我相信看完了之後雖然你腦子裏沒有標準的算法步驟,但應該有個大體的輪廓了,只不過須要本身再仔細想一想步驟。
####總的來講,B+樹的插入步驟無外乎如下幾個步驟
查找操做和更新操做幾乎同樣,就是更新操做的前面兩步,就不說了。
通常的更新的時候也是先查找,找到葉子節點,再更新,而後順着指針往上走繼續分裂,這個順着往上走通常狀況下首先想到的是雙向指針,可是雙向指針分裂的時候有點麻煩,須要把兩個指針都從新指新節點,我實現的時候用了一個棧,查找葉子節點的時候把通過的節點依次壓棧,到達葉子節點後,完成插入操做,往上遍歷的時候依次把棧彈出來就好了,少了一個指針。
回到上一篇說的那個表2的第一列,若是是那個表的話,用這個B+樹加上倒排鏈的話,最後的數據結構就長成這樣子了(字符串的大小我隨便寫的,中文的順序排列哥的腦子排不出來,你就把他們當作從小到大的順序吧)
好了,至此,一個倒排索引就創建好了,由兩部分組成,我實現的時候就是這麼實現的,一個結構用B+樹存儲字典,另一個就是一個順序的文件,B+樹的葉子節點存一個指向倒排文件的文件偏移量,固然,你也能夠用前面的哈希表或者跳躍表,甚至還有其餘類型的樹,好比trie樹來實現,或者你還有其餘新的高效數據結構也行。
####咱們再來講說B+樹,爲何選它?
以前我實現的時候用的是哈希表,並且大部分的搜索引擎用的都是哈希表,爲何用樹呢
最後說說我實現的這棵B+樹,首先,爲了更少的佔用內存,我是用的磁盤的形式實現的,而且用了mmap的方式來加快讀寫速度,沒有用雙向指針,而用的棧來記錄查詢的路徑,速度還行吧,構造一棵10萬個隨機字符串的樹大約須要3秒,隨機查詢10萬次大約須要150毫秒,每次1.5微秒。
固然,我實現的時候比較倉促,就是按照算法硬編碼快速擼出來的,因此我這個B+樹還有很是大的優化空間,首先,個人key如今是肯定的,不能超過64字節,而且每一個節點最多100個元素,當時爲了快,肯定的key和元素個數比較好編程,若是變成動態的更加節省空間,其次,沒有特別的考慮連續key的狀況,連續key的插入會形成空間浪費一半,還有,把速度問題交給了mmap來解決,若是內存足夠,實際上啓動的時候預讀取非葉子節點到內存的話,查詢起來會更快,不過目前基本上知足需求了,你們若是對B+樹實現很感興趣,能夠看看bolt這個項目,這個是一個B+樹實現的KVDB,並且是帶事務的哦。
若是你以爲不錯,歡迎轉發給更多人看到,也歡迎關注個人公衆號,主要聊聊搜索,推薦,廣告技術,還有瞎扯。。文章會在這裏首先發出來:)掃描或者搜索微信號XJJ267或者搜索西加加語言就行