sphinx是c++語言編寫的一個開源全文檢索項目,索引文件創建速度和檢索速度都是不錯的。由於公司的項目需要我對其源碼進行了解讀,並在其上進行了一定程度的改寫以適應項目檢索提速的需求。這篇文章就是我對sphinx源碼的解讀心得,sphinx基於2.1.9版本。
大體上來講sphinx分成indexer和searchd兩個最主要的進程,indexer負責創建索引文件,searchd負責接收網絡包並進行檢索返回結果,當有新的索引文件生成或者舊的索引文件發生了變更(如merge了新的數據)則indexer會通過輪轉的方式通知searchd。輪轉這個操作就是將索引文件mv成一個.new文件(如有索引文件名爲hour.sp*,會被mv成hour.new.sp*),然後向searchd發送一個SIGHUP信號,由searchd接收信號後將.new文件mv回原格式,然後更新自己的維護列表。這其中indexer是通過創建之初就提供給他的一個.conf配置文件知道searchd的pid存放文件路徑的。
一個索引文件分爲幾個主要的子文件,仍然以hour索引爲例,通常會有如下幾個最主要的文件:
spa 存儲文檔屬性,僅在extern存儲模式中使用,用於存儲hit信息。
spd 存儲每個wordID可匹配的docID列表,這是我們檢索的核心文件,通過該文件可以用關鍵字檢索到對應的docID。
spi 存儲詞列表(詞ID和指向.spd文件的指針),可以認爲是在spd上的二級索引,檢索時先遍歷spi得到word在spd上的範圍。Spi分爲dict和checkpoint兩部分,dict爲具體每個word的wordid、doc數、hit數等等信息,而checkpoint則每128個word記錄一個wordID和該word在spi上的位置。
sph 存儲索引頭信息,除了必要配置信息外還存了checkpoint在spi上的位置
spe存儲skip-lists,skip-lists可以認爲是在hits記錄(spp)上的二級索引。如果不存儲hits則spp文件大小爲0。
spp 存儲每個詞ID的hit(或者說記賬,或者詞的出現)列表,如果在conf配置文件裏配置hitless=all則大小爲0。
上面涉及了幾個名詞docID是一行的標記,可以認爲是mysql裏一行數據的id,wordID是關鍵字轉化的一個哈希值,hit不太好理解,可以認爲是一個關鍵字在一行記錄裏的具體位置,例如關鍵字pokeman出現在mysql某一行的記錄中位置爲第3個字段的第5個字符,則hit可能爲0000000300000005這樣的格式,當然這只是個例子,具體格式肯定不是這樣的。這裏的docID、wordID、hit就是sphinx的核心三元組
關於這核心三元組和幾個核心文件的關係可以看這個圖:
索引文件的創建流程如下,創建流程最爲核心的是cidxHit函數,該函數實現了將每一個hit壓縮到對應文件的功能: