天天看點

MySQL · 引擎介紹 · Sphinx源碼剖析(一)

sphinx是一個全文索引引擎,他被設計為可以非常簡單友善的與各種資料庫(mysql,pg…)進行互動。它提供了兩種讀取接口,a) sphinx自己實作的mysql協定的接口, sphinxql。b) 各種語言用戶端的接口,也就是native搜尋api. c) 也可以直接通過mysql server的一個存儲引擎插件來通路, sphinxse.

接下來我們會有一些列文章來分析sphinx的設計以及源碼實作。

本篇是第一篇,主要是簡要的介紹sphinx的源碼結構,設計以及索引檔案的構成。我們目前分析的代碼版本是sphinx-2.3.2-beta.tar.gz.

sphinx的源碼結構比較簡單,下面主要是一些比較重要的目錄:

api 這個目錄主要是包含了各種sphinx的native用戶端.

config 這個目錄包含了configure需要的一些檔案.

cmake 這個目錄包含了cmake建構需要的一些子產品(目前sphinx支援兩種構模組化式).

mysqlse 這個目錄包含了sphinxse

src 這個目錄就是最主要的源碼目錄。

src/http search服務的http接口

sphinx最終會生成4個可執行檔案,分别是:

indexer 主要是操作索引檔案,比如合并索引,重新建構索引等等

indextool dump索引的一些資訊,比如統計資訊等

searchd 搜尋服務

spelldump 拼寫檢查的工具

我們先來看sphinx源碼的cmakefiles(src/cmakelists.txt) :

通過上面的建構檔案我們可以看到4個可執行檔案對應4個源檔案(除了搜尋服務,searchdha.cpp是分布式搜尋,searchdhttp.cpp是搜尋服務的http接口實作).剩下的源代碼都會被編譯為一個libsphinx的庫.

是以下面簡單介紹下libsphinx的幾個檔案主要作用:

sphinx.cpp 核心的檔案,一些核心功能的實作都在這裡,比如讀寫索引檔案,比如搜尋的核心方法

sphinxexcerpt.cpp 生成excerpt

sphinxquery.cpp 處理query

sphinxstemen.cpp sphinxstemru.cpp sphinxstemcz.cpp sphinxstemar.cpp 各種語言的解析器

sphinxutils.cpp 一些工具函數,比如讀寫檔案,日志,動态庫等

sphinxstd.cpp 庫函數,實作了很多基本資料結構,比如 list/vector 等

sphinxexpr.cpp 處理搜尋的query

sphinxfilter.cpp 處理query的filter

sphinxsearch.cpp 核心的搜尋處理函數

sphinxrt.cpp rt index的實作

sphinxjson.cpp json的處理

以rt索引為例,sphinx會有配置來決定記憶體中的索引大小(rt_mem_limit),超過這個大小後,sphinx将會把記憶體索引重新整理到磁盤中。接下來我們就來看sphinx的索引的含義以及原始格式。

在sphinx中所有的索引最終都是被壓縮的,壓縮算法比較簡單,要麼是delta encoding, 要麼是vlb(variable length byte string):

delta encoding

主要用來儲存遞增的一個序列,每一個元素都儲存和前一個元素的內插補點。這種壓縮更高效,結果更小(比起vlb) 比如:

vlb

将一個固定大小(34/64)的整數值轉換為一個字元串,每個位元組分為高1位和低七位,最高位表示目前是否解析結束,低7位表示壓縮的值,原理很簡單,那麼就是對于大多數整數來說,不需要完整的8個位元組(或者4個位元組)來表示一個整數,因為沒有那麼大。而由于是每次移動7位,那麼對于最高位為1的情況也可以處理(因為每次移動完畢的最高位都是無意義的值)。

例子:

下面我們來看代碼,對應的函數是csphreader::unzipint以及csphwriter::zipint,其中前一個是解壓縮,後一個是壓縮。

先來看壓縮, dword可以簡單地認為是int64_t,代碼比較簡單,首先先計算可以用幾個位元組來儲存目前的數(ibytes),然後循環的儲存每個位元組:

然後是解壓縮,剛好和壓縮相反,也就是通過最高位來判斷是否結束解壓縮,然後通過左移以及累加來不斷地計算原有的值。

在介紹索引檔案之前,我們先介紹幾個概念:

document

每一條資料也就是一個document。

word

這裡word表示一個單詞,也就是sphinx分詞器處理完一條document之後,所得到的分詞。

hits

也就是一個word在一條document中的頻率。

attribute

一些擴充的字段,主要是為了做一些過濾(filter)。

然後來看索引檔案的簡單介紹.

然後我們來看索引的種類以及格式,在sphinx中,每一個索引都包含了下面幾個檔案:

sph檔案 儲存了索引的頭檔案,主要是一些索引元資訊

實作在writeheader/loadheader中。

spi檔案 儲存了wordlist,也就是索引檔案中最核心的一個檔案。

也就是通過spi檔案可以迅速的從一個keywords(word)映射到一堆document list。下面就是spi檔案的格式(dict=keywords):

檔案生成是在cidxhit中。

spa檔案 儲存了attribute

sps檔案 單獨儲存string類型的attribute值

spd檔案 儲存了document list

所有的document id都儲存在這個這個檔案中,也就是通過spi檔案得到document list的資訊後,可以迅速在spd檔案中定位document list。

spe檔案 儲存了skip list

spk檔案 儲存了 kill list

spm檔案 儲存了mva 值

spp檔案 儲存了hit list。

儲存了一個word在document中的所有出現的位置。也就是給定一個document 和一個keywords,這個檔案将會傳回所有的比對位置(在目前的document中).

其中spp/spi/spd/spa/spe檔案的生成都在rtindex_t::savediskdataimpl中實作。

在下一篇文章,我們會詳細的介紹每個索引檔案的生成。

http://sphinxsearch.com/docs/current.html

繼續閱讀