標籤:redis 搜尋引擎 資料庫 資訊檢索 go語言
用GO語言實現一個簡單的搜尋引擎
項目地址是:https://github.com/wyh267/FalconEngine
對搜尋引擎感興趣的可以去看看這本書,比較淺並且也比較完整的介紹了一個搜尋引擎的全部機能。
我的這個搜尋引擎未經處理資料是MySql資料庫的,大家可以根據需要進行二次開發,用來支援其他資料庫或者本地檔案,Detail檔案是儲存在Redis資料庫中,同樣這部分也可以根據自己的需要二次開發,使用本地檔案或者其他資料庫,倒排索引和正排索引本機存放區的時候使用的json格式,比較耗磁碟,第一版暫時這樣了吧,後續再做最佳化。
使用方法依賴以下幾個庫
- github.com/outmana/log4jzl log檔案
- github.com/ewangplay/config 設定檔解析
- github.com/go-sql-driver/mysql mysql驅動
- github.com/garyburd/redigo/redis Redis驅動
- github.com/huichen/sego 分詞器,作者首頁非常感謝他的分析器,他首頁上也有個搜尋引擎,沒看具體實現,大家感興趣可以去看看。
編譯
運行
- 從github.com/huichen/sego擷取分詞的字典檔案
- 運行索引器,會將索引檔案產生到index目錄下
bin/FalconEngine -mode=build
bin/FalconEngine -mode=search
基本概念
以下幾個概念需要理解,如果完全不瞭解的話,還需要自己稍微百度一下:倒排索引
,正排檔案
,Detail檔案
,全量索引
,增量索引
,雜湊函數
,DocId
基礎資料結構
搜尋引擎首先並不神秘,基礎的資料結構就那麼幾個,定了以後後面就是在上面添磚加瓦了。
假如有下面五個文檔需要進行搜尋
文檔編號 |
內容 |
1 |
你好,搜尋引擎 |
2 |
搜尋引擎有一條資料 |
3 |
你好,有一條測試資料 |
倒排索引
倒排索引是搜尋引擎基礎中的基礎,主要的檢索都是從倒排索引開始的,所以,首先,設計一個倒排索引的資料結構是所有搜尋引擎的基礎。
搜尋引擎的基礎是DocId,也就是文檔ID,DocId是唯一的並且是連續的,而倒排索引就是一組DocId鏈表,每個鏈表對應一個關鍵詞。
上面的文檔建立號倒排索引的基礎結構如
關鍵詞 |
文檔編號 |
你好 |
1,3 |
搜尋引擎 |
1,2 |
資料 |
2,3 |
有一條 |
2,3 |
測試 |
3 |
所以,當我們檢索資料
這個詞的時候能迅速知道在文檔2和3有這條資料,就能進行檢索了。
是不是很簡單,關鍵問題是檢索資料
的時候,如何能迅速定位到第三行資料,這裡就用到雜湊表
了,所以,一個完整的倒排包括兩部分,一部分是上面的這個表,第二個是一個雜湊表,通過這個雜湊表能知道資料
這個詞的下標為3
,從而找到2,3
這兩個文檔。
雜湊表
的具體實現就不詳細展開了,雜湊表
有很多種實現方式,並且雜湊函數也有很多種實現方式,總之,對於一個關鍵詞的定位
- 首先,通過計算這個關鍵詞的hash,得到它的下標
- 然後,尋找倒排索引的下標,得到文檔ID的鏈表
在代碼的InvertIndex.go
中是倒排索引的資料結構,StringIndexDic.go
是關鍵詞的雜湊表,這兩個檔案產生的資料都會序列化成json
檔案儲存體下來。
正排索引
正排索引相對倒排就簡單多了,實際上就是一個字典檔案,key
是DocId,value
是這個DocId對應的內容,主要用來做結果集的過濾,所謂倒排檢索,正排過濾
,什麼情境需要這樣的東西呢?下面的情境你肯定經曆過。
你在一個某東的網站搜尋運動鞋
,肯定出來一堆鞋子,但是你只想看nike
的鞋子,這時候你可以再運動鞋後面加上Nike,搜尋nike運動鞋
,但是結果不一定準,因為並不是每個nike的鞋子的標題上都會寫上nike,這時候就需要用到正排了,他會把nike鞋子給你過濾出來。
正排索引就是一個數組,數組的下標就是DocId
,檔案中的NumberProfile.go
和TextProfile.go
是具體的實現檔案
Detail檔案
Detail檔案使用的是Redis實現的,沒有具體的資料結構,實際上就是以主鍵ID為key來實現的。
累加式更新
累加式更新使用的是掃描mysql中的一個last_modify_time
欄位,擷取資料,然後和redis
中的資料進行對比,如果更新了就添加到索引中,添加索引按照如下的步驟進行
因為DocId是連續的,倒排欄位更新的話,要修改倒排鏈表,而目前的倒排鏈表是數組的,所以直接建立一個BitMap,將對應的DocId刪除,後續改成鏈表形式的話,可以動態刪除。
累加式更新使用的一個go的協程來做的,掃描的是資料庫欄位,後續可以改成從kafka
擷取資料或者其他方式擷取累加式更新
資料檢索
資料檢索分成以下幾個步驟
- 根據關鍵詞從倒排索引中擷取DocId鏈,有多個關鍵詞的時候求交集
- 通過
BitMap
過濾掉已經刪除的DocId
- 最後得到的DocId按照正排檔案的條件進行過濾操作,擷取最終的DocId鏈
- 通過DocId反查出文檔的真實ID,並通過Redis擷取文檔的詳細資料用於顯示
檔案中的IndexSet.go
主要實現了上述步驟
待續。。。。。。。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
用GO語言實現一個簡單的搜尋引擎