倒排索引增量更新如何被實時檢索?

正排索引與倒排索引

索引的目的: 使根據 key 查詢 value 的速度變快

正排索引:Forward Index ,以一個對象的唯一ID 爲Key 的哈希索引結構
倒排索引:Inverted Index 根據具體內容,反過來查詢文檔 key ,根據內容(字典),查詢對應的文檔列表(記錄列表)

倒排索引的創建:

1 文檔唯一編號,排序,遍歷文檔
2 解析文檔,生成, <關鍵字,文檔ID,關鍵字Index> (查詢多個關鍵字時,可以比較多個關鍵字的位置)
3 生成 關鍵字 對應的 (文檔ID,關鍵字Index) 的 記錄列表

這樣查詢某個關鍵字,就能得到所有包含關鍵字的文檔ID的 記錄列表 O(1)

當查詢多個關鍵字時,就需要依次查詢出 多個記錄列表,然後進行歸併排序 ,取出其中的交集,O(m+n+…)

可想而知,一個支持根據內容查詢文檔的檢索引擎,需要很多龐大的倒排索引支持,無論有多少的歷史數據,當倒排索引建立之後,查詢速度都會變快,那麼當一些新的數據加入的時候,如何立刻被檢索到?

倒排索引的更新是如何設計的 ?

假設你設計一個倒排索引,將這個倒排索引存儲在內存中,這會讓檢索系統的檢索速度很快,假設這個索引規模不大,當有一個新的文檔錄入時,完全可以按照上面創建倒排索引的方法,增量的去將文檔遍歷,增加到對應的關鍵字 記錄列表中

但這樣存在一個問題,當我們更新文檔,會給這個倒排索引加上鎖,這樣當用戶訪問這個索引時,就會引發錯誤和崩潰

那麼如何去增量的更新索引呢?

這裏用到的思想是,雙緩衝的概念 Double Buffer ,

同時維護兩個一樣的索引,索引A和索引B,索引A只提供讀取功能,索引B只提供寫的功能,這裏AB雙緩衝的設計概念其實也是讀寫分離,
增量的索引更新到索引B中,寫入由B負責,這樣就不會有加鎖產生的問題,當B更新完成之後,進行原子操作,將訪問指針從A切換到B上面,完成讀索引的切換

redis - rehash

這裏其實和 redis 中的 rehash 是相似的設計
https://blog.csdn.net/qq_28018283/article/details/103710590 ReHash 字典 章節

rehash的過程:

字典鍵值對存放在 ht[0]

  • 1 參照要執行的操作和字典中鍵值對的個數,爲ht[1] 哈希表分配空間,
  • 2 將保存在 ht[0] 中的鍵值對重新計算哈希值和索引,然後存放到ht[1]中
  • 3 當 ht[0] 中的數據全部遷移到 ht[1] 後,檢查是否整個表遷移完成 rehash ht[0].used==0 已全部rehash到 ht[1] 之後,將 ht[1] 設爲 ht[0] ,並將ht[1]新創建一個空白哈希表 -> 重複步驟1

當索引的規模很大的時候,一般不會存儲在內存中,而是存儲在磁盤中,這時候,用上面的雙緩存切換的機制更新就不信了,此時常用的方案有全量結合增量索引
維護一個全量索引,爲了搜索效率全量索引不加鎖,新增加的文檔,維護一個在內存中的倒排索引,也就是增量索引,當查詢發生的時候,我們同時查詢全量和增量索引,合併查詢的結果。

全量結合增量的策略很實用,但是增量索引不可能一直在內存中增長,必然要將增量索引定期的合併到全量索引中,這裏用到的是 滾動合併法:

具體就是把索引按照多層次分開,再進行歸併排序 ,保證小索引合併到中索引再合併到大索引,避免的是 大索引產生大量的複製操作的問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章