Sphinx的介绍和原理探索
What/Sphinx是什么
定義
Sphinx是一個(gè)全文檢索引擎。
特性
- 索引和性能優(yōu)異
- 易于集成SQL和XML數(shù)據(jù)源,并可使用SphinxAPI、SphinxQL或者SphinxSE搜索接口
- 易于通過(guò)分布式搜索進(jìn)行擴(kuò)展
- 高速的索引建立(在當(dāng)代CPU上,峰值性能可達(dá)到10 ~ 15MB/秒)
- 高性能的搜索 (在1.2G文本,100萬(wàn)條文檔上進(jìn)行搜索,支持高達(dá)每秒150~250次查詢)
?
Why/為什么使用Sphinx
遇到的使用場(chǎng)景
遇到一個(gè)類似這樣的需求:用戶可以通過(guò)文章標(biāo)題和文章搜索到一片文章的內(nèi)容,而文章的標(biāo)題和文章的內(nèi)容分別保存在不同的庫(kù),而且是跨機(jī)房的。
可選方案
A、直接在數(shù)據(jù)庫(kù)實(shí)現(xiàn)跨庫(kù)LIKE查詢
優(yōu)點(diǎn):簡(jiǎn)單操作
缺點(diǎn):效率較低,會(huì)造成較大的網(wǎng)絡(luò)開(kāi)銷
B、結(jié)合Sphinx中文分詞搜索引擎
優(yōu)點(diǎn):效率較高,具有較高的擴(kuò)展性
缺點(diǎn):不負(fù)責(zé)數(shù)據(jù)存儲(chǔ)
使用Sphinx搜索引擎對(duì)數(shù)據(jù)做索引,數(shù)據(jù)一次性加載進(jìn)來(lái),然后做了所以之后保存在內(nèi)存。這樣用戶進(jìn)行搜索的時(shí)候就只需要在Sphinx服務(wù)器上檢索數(shù)據(jù)即可。而且,Sphinx沒(méi)有MySQL的伴隨機(jī)磁盤I/O的缺陷,性能更佳。
其他典型使用場(chǎng)景
1、快速、高效、可擴(kuò)展和核心的全文檢索
- 數(shù)據(jù)量大的時(shí)候,比MyISAM和InnoDB都要快。
- 能對(duì)多個(gè)源表的混合數(shù)據(jù)創(chuàng)建索引,不限于單個(gè)表上的字段。
- 能將來(lái)自多個(gè)索引的搜索結(jié)果進(jìn)行整合。
- 能根據(jù)屬性上的附加條件對(duì)全文搜索進(jìn)行優(yōu)化。?
2、高效地使用WHERE子句和LIMIT字句
當(dāng)在多個(gè)WHERE條件做SELECT查詢時(shí),索引選擇性較差或者根本沒(méi)有索引支持的字段,性能較差。sphinx可以對(duì)關(guān)鍵字做索引。區(qū)別是,MySQL中,是內(nèi)部引擎決定使用索引還是全掃描,而sphinx是讓你自己選擇使用哪一種訪問(wèn)方法。因?yàn)閟phinx是把數(shù)據(jù)保存到RAM中,所以sphinx不會(huì)做太多的I/O操作。而mysql有一種叫半隨機(jī)I/O磁盤讀,把記錄一行一行地讀到排序緩沖區(qū)里,然后再進(jìn)行排序,最后丟棄其中的絕大多數(shù)行。所以sphinx使用了更少的內(nèi)存和磁盤I/O。
3、優(yōu)化GROUP BY查詢
在sphinx中的排序和分組都是用固定的內(nèi)存,它的效率比類似數(shù)據(jù)集全部可以放在RAM的MySQL查詢要稍微高些。
4、并行地產(chǎn)生結(jié)果集
sphinx可以讓你從相同數(shù)據(jù)中同時(shí)產(chǎn)生幾份結(jié)果,同樣是使用固定量的內(nèi)存。作為對(duì)比,傳統(tǒng)SQL方法要么運(yùn)行兩個(gè)查詢,要么對(duì)每個(gè)搜索結(jié)果集創(chuàng)建一個(gè)臨時(shí)表。而sphinx用一個(gè)multi-query機(jī)制來(lái)完成這項(xiàng)任務(wù)。不是一個(gè)接一個(gè)地發(fā)起查詢,而是把幾個(gè)查詢做成一個(gè)批處理,然后在一個(gè)請(qǐng)求里提交。
5、向上擴(kuò)展和向外擴(kuò)展
- 向上擴(kuò)展:增加CPU/內(nèi)核、擴(kuò)展磁盤I/O
- 向外擴(kuò)展:多個(gè)機(jī)器,即分布式sphinx
6、聚合分片數(shù)據(jù)
適合用在將數(shù)據(jù)分布在不同物理MySQL服務(wù)器間的情況。
例子:有一個(gè)1TB大小的表,其中有10億篇文章,通過(guò)用戶ID分片到10個(gè)MySQL服務(wù)器上,在單個(gè)用戶的查詢下當(dāng)然很快,如果需要實(shí)現(xiàn)一個(gè)歸檔分頁(yè)功能,展示某個(gè)用戶的所有朋友發(fā)表的文章。那么就要同事訪問(wèn)多臺(tái)MySQL服務(wù)器了。這樣會(huì)很慢。而sphinx只需要?jiǎng)?chuàng)建幾個(gè)實(shí)例,在每個(gè)表里映射出經(jīng)常訪問(wèn)的文章屬性,然后就可以進(jìn)行分頁(yè)查詢了,總共就三行代碼的配置。
?
介紹了Sphinx的工作原理,關(guān)于如何安裝的文章在網(wǎng)上有很多,筆者就不再?gòu)?fù)述了,現(xiàn)在繼續(xù)講解Sphinx的配置文件,讓Sphinx工作起來(lái)。
How/如何使用Sphinx
Sphinx工作流程圖
?
流程圖解釋
Database:數(shù)據(jù)源,是Sphinx做索引的數(shù)據(jù)來(lái)源。因?yàn)镾phinx是無(wú)關(guān)存儲(chǔ)引擎、數(shù)據(jù)庫(kù)的,所以數(shù)據(jù)源可以是MySQL、PostgreSQL、XML等數(shù)據(jù)。
Indexer:索引程序,從數(shù)據(jù)源中獲取數(shù)據(jù),并將數(shù)據(jù)生成全文索引。可以根據(jù)需求,定期運(yùn)行Indexer達(dá)到定時(shí)更新索引的需求。
Searchd:Searchd直接與客戶端程序進(jìn)行對(duì)話,并使用Indexer程序構(gòu)建好的索引來(lái)快速地處理搜索查詢。
APP:客戶端程序。接收來(lái)自用戶輸入的搜索字符串,發(fā)送查詢給Searchd程序并顯示返回結(jié)果。
Sphinx的工作原理
Sphinx的整個(gè)工作流程就是Indexer程序到數(shù)據(jù)庫(kù)里面提取數(shù)據(jù),對(duì)數(shù)據(jù)進(jìn)行分詞,然后根據(jù)生成的分詞生成單個(gè)或多個(gè)索引,并將它們傳遞給searchd程序。然后客戶端可以通過(guò)API調(diào)用進(jìn)行搜索。
介紹了Sphinx工作原理以及Sphinx的配置之后,繼續(xù)介紹在Sphinx中,負(fù)責(zé)做索引的程序Indexer是如何做索引的。
sphinx使用配置文件從數(shù)據(jù)庫(kù)讀出數(shù)據(jù)之后,就將數(shù)據(jù)傳遞給Indexer程序,然后Indexer就會(huì)逐條讀取記錄,根據(jù)分詞算法對(duì)每條記錄建立索引,分詞算法可以是一元分詞/mmseg分詞。下面先介紹Indexer做索引時(shí)使用的數(shù)據(jù)結(jié)構(gòu)和算法。
?
數(shù)據(jù)源配置
先來(lái)看一份數(shù)據(jù)源的配置文件示例:
1 source test2 {3 type = mysql4 5 sql_host = 127.0.0.16 sql_user = root7 sql_pass = root8 sql_db = test9 sql_port = 3306 # optional, default is 3306 10 11 sql_query_pre = SET NAMES utf8 12 sql_query = SELECT id, name, add_time FROM tbl_test 13 14 sql_attr_timestamp = add_time 15 16 sql_query_info_pre = SET NAMES utf8 17 sql_query_info = SELECT * FROM tbl_test WHERE id=$id 18 }?
其中
source后面跟著的是數(shù)據(jù)源的名字,后面做索引的時(shí)候會(huì)用到;
type:數(shù)據(jù)源類型,可以為MySQL,PostreSQL,Oracle等等;
sql_host、sql_user、sql_pass、sql_db、sql_port是連接數(shù)據(jù)庫(kù)的認(rèn)證信息;
sql_query_pre:定義查詢時(shí)的編碼
sql_query:數(shù)據(jù)源配置核心語(yǔ)句,sphinx使用此語(yǔ)句從數(shù)據(jù)庫(kù)中拉取數(shù)據(jù);
sql_attr_*:索引屬性,附加在每個(gè)文檔上的額外的信息(值),可以在搜索的時(shí)候用于過(guò)濾和排序。設(shè)置了屬性之后,在調(diào)用Sphinx搜索API時(shí),Sphinx會(huì)返回已設(shè)置了的屬性;
sql_query_info_pre:設(shè)置查詢編碼,如果在命令行下調(diào)試出現(xiàn)問(wèn)號(hào)亂碼時(shí),可以設(shè)置此項(xiàng);
sql_query_info:設(shè)置命令行下返回的信息。
索引配置
1 index test_index2 {3 source = test4 path = /usr/local/coreseek/var/data/test5 docinfo = extern6 charset_dictpath = /usr/local/mmseg3/etc/7 charset_type = zh_cn.utf-88 ngram_len = 19 ngram_chars = U+3000..U+2FA1F 10 }
其中
index后面跟的test_index是索引名稱
source:數(shù)據(jù)源名稱;
path:索引文件基本名,indexer程序會(huì)將這個(gè)路徑作為前綴生成出索引文件名。例如,屬性集會(huì)存在/usr/local/sphinx/data/test1.spa中,等等。
docinfo:索引文檔屬性值存儲(chǔ)模式;
charset_dictpath:中文分詞時(shí)啟用詞典文件的目錄,該目錄下必須要有uni.lib詞典文件存在;
charset_type:數(shù)據(jù)編碼類型;
ngram_len:分詞長(zhǎng)度;
ngram_chars:要進(jìn)行一元字符切分模式認(rèn)可的有效字符集。
中文分詞核心配置
一元分詞
1 charset_type = utf8 2 3 ngram_len = 1 4 5 ngram_chars = U+3000..U+2FA1Fmmseg分詞
1 charset_type = utf8 2 3 charset_dictpath = /usr/local/mmseg3/etc/ 4 5 ngram_len = 0運(yùn)行示例
數(shù)據(jù)庫(kù)數(shù)據(jù)
?
使用indexer程序做索引
?
查詢
可以看到,配置文件中的add_time被返回了,如上圖的1所示。而sql_query_info返回的信息如上圖的2所示。
?
Sphinx的配置不是很靈活,此處根據(jù)工作流程給出各部分的配置,更多的高級(jí)配置可以在使用時(shí)查閱文檔。
倒排索引
倒排索引是一種數(shù)據(jù)結(jié)構(gòu),用來(lái)存儲(chǔ)在全文搜索下某個(gè)單詞在一個(gè)文檔或者一組文檔中的存儲(chǔ)位置的映射。它是文檔檢索系統(tǒng)中最常用的數(shù)據(jù)結(jié)構(gòu)。
倒排索引(Inverted Index):倒排索引是實(shí)現(xiàn)“單詞-文檔矩陣”的一種具體存儲(chǔ)形式,通過(guò)倒排索引,可以根據(jù)單詞快速獲取包含這個(gè)單詞的文檔列表。
傳統(tǒng)的索引是:索引ID->文檔內(nèi)容,而倒排索引是:文檔內(nèi)容(分詞)->索引ID。可以類比正向代理和反向代理的區(qū)別來(lái)理解。正向代理把內(nèi)部請(qǐng)求代理到外部,反向代理把外部請(qǐng)求代理到內(nèi)部。所以應(yīng)該理解為轉(zhuǎn)置索引比較合適。
倒排索引主要由兩個(gè)部分組成:“單詞詞典”和“倒排文件”。
單詞詞典是倒排索引中非常重要的組成部分,它用來(lái)維護(hù)文檔集合中出現(xiàn)過(guò)的所有單詞的相關(guān)信息,同時(shí)用來(lái)記載某個(gè)單詞對(duì)應(yīng)的倒排列表在倒排文件中的位置信息。在支持搜索時(shí),根據(jù)用戶的查詢?cè)~,去單詞詞典里查詢,就能夠獲得相應(yīng)的倒排列表,并以此作為后續(xù)排序的基礎(chǔ)。
對(duì)于一個(gè)規(guī)模很大的文檔集合來(lái)說(shuō),可能包含幾十萬(wàn)甚至上百萬(wàn)的不同單詞,能否快速定位某個(gè)單詞直接影響搜索時(shí)的響應(yīng)速度,所以需要高效的數(shù)據(jù)結(jié)構(gòu)來(lái)對(duì)單詞詞典進(jìn)行構(gòu)建和查找,常用的數(shù)據(jù)結(jié)構(gòu)包括哈希加鏈表結(jié)構(gòu)和樹(shù)形詞典結(jié)構(gòu)。
倒排索引基礎(chǔ)知識(shí)
- 文檔(Document):一般搜索引擎的處理對(duì)象是互聯(lián)網(wǎng)網(wǎng)頁(yè),而文檔這個(gè)概念要更寬泛些,代表以文本形式存在的存儲(chǔ)對(duì)象,相比網(wǎng)頁(yè)來(lái)說(shuō),涵蓋更多種形式,比如Word,PDF,html,XML等不同格式的文件都可以稱之為文檔。再比如一封郵件,一條短信,一條微博也可以稱之為文檔。在本書后續(xù)內(nèi)容,很多情況下會(huì)使用文檔來(lái)表征文本信息。
- 文檔集合(Document Collection):由若干文檔構(gòu)成的集合稱之為文檔集合。比如海量的互聯(lián)網(wǎng)網(wǎng)頁(yè)或者說(shuō)大量的電子郵件都是文檔集合的具體例子。
- 文檔編號(hào)(Document ID):在搜索引擎內(nèi)部,會(huì)將文檔集合內(nèi)每個(gè)文檔賦予一個(gè)唯一的內(nèi)部編號(hào),以此編號(hào)來(lái)作為這個(gè)文檔的唯一標(biāo)識(shí),這樣方便內(nèi)部處理,每個(gè)文檔的內(nèi)部編號(hào)即稱之為“文檔編號(hào)”,后文有時(shí)會(huì)用DocID來(lái)便捷地代表文檔編號(hào)。
- 單詞編號(hào)(Word ID):與文檔編號(hào)類似,搜索引擎內(nèi)部以唯一的編號(hào)來(lái)表征某個(gè)單詞,單詞編號(hào)可以作為某個(gè)單詞的唯一表征。
?Indexer程序就是根據(jù)配置好地分詞算法,將獲取到的記錄進(jìn)行分詞,然后用倒排索引做數(shù)據(jù)結(jié)構(gòu)保存起來(lái)。
?分詞算法
一元分詞
一元分詞的核心配置
1 charsey_type = zh_cn.utf8 2 ngram_len = 1 3 ugram_chars = U+4E00..U+9FBFngram_len是分詞的長(zhǎng)度。
ngram_chars標(biāo)識(shí)要進(jìn)行一元分詞切分模式的字符集。
?
原生的Sphinx支持的分詞算法是一元分詞,這種分詞算法是對(duì)記錄的每個(gè)詞切割后做索引,這種索引的優(yōu)點(diǎn)就是覆蓋率高,保證每個(gè)記錄都能被搜索到。缺點(diǎn)就是會(huì)生成很大的索引文件,更新索引時(shí)會(huì)消耗很多的資源。所以,如果不是特殊需求,而且數(shù)據(jù)不是特別少的時(shí)候,都不建議使用一元分詞。
國(guó)人在sphinx的基礎(chǔ)上開(kāi)發(fā)了支持中文分詞的Coreseek。Coreseek與Sphinx唯一的不同就是Coreseek還支持mmseg分詞算法做中文分詞。
mmseg分詞
mmseg分詞算法是基于統(tǒng)計(jì)模型的,所以算法的規(guī)則也是來(lái)自對(duì)語(yǔ)料庫(kù)的分析和數(shù)學(xué)歸納,因?yàn)橹形淖址麤](méi)有明確的分界,會(huì)導(dǎo)致大量的字符分界歧義,而且,中文里面,詞和短語(yǔ)也很難界定,因此,算法除了要做統(tǒng)計(jì)和數(shù)學(xué)歸納之外,還要做歧義的解決。
在mmseg分詞中,有一個(gè)叫chunk的概念。
chunk,是一句話的分詞方式。包括一個(gè)詞條數(shù)組和四個(gè)規(guī)則。
如:研究生命,有“研究/生命”和“研究生/命”兩種分詞方式,這就是兩個(gè)chunk。
一個(gè)chunk有四個(gè)屬性:長(zhǎng)度、平均長(zhǎng)度(長(zhǎng)度/分詞數(shù))、方差、單字自由度(各單詞條詞頻的對(duì)數(shù)之和)。
做好分詞之后,會(huì)得到多種分詞方式,這時(shí)候就要使用一些過(guò)濾規(guī)則來(lái)完成歧義的解決,以得到最終的分詞方式。
歧義解決規(guī)則:
1、最大匹配
匹配最大長(zhǎng)度的詞。如“國(guó)際化”,有“國(guó)際/化”、“國(guó)際化”兩種分詞方式,選擇后者。
2、最大平均詞長(zhǎng)度
匹配平均詞最大的chunk。如“南京市長(zhǎng)江大橋”,有“南京市/長(zhǎng)江大橋”、“南京/市長(zhǎng)/江大橋”三種分詞方式,前者平均詞長(zhǎng)度是7/2=3.5,后者是7/3=2.3,故選擇前者的分詞方式。
3、最大方差
去方差最大的chunk。如“研究生命科學(xué)”,有“研究生/命/科學(xué)”、“研究/生命/科學(xué)“兩種分詞方式,而它們的詞長(zhǎng)都一樣是2。所以需要繼續(xù)過(guò)濾,前者方差是0.82,后者方差是0。所以選擇第一種分詞方式。
4、最大單字自由度
選擇單個(gè)字出現(xiàn)最高頻率的chunk。比如”主要是因?yàn)椤?#xff0c;有”主要/是/因?yàn)椤?#xff0c;”主/要是/因?yàn)椤皟煞N分詞方式,它們的詞長(zhǎng)、方差都一樣,而”是“的詞頻較高,所以選擇第一種分詞方式。
如果經(jīng)過(guò)上述四個(gè)規(guī)則的過(guò)濾,剩下的chunk仍然大于一,那這個(gè)算法也無(wú)能為力了,只能自己寫擴(kuò)展完成。
?
最后的最后
當(dāng)然,有人會(huì)說(shuō)數(shù)據(jù)庫(kù)的索引也可以做到sphinx索引,只是數(shù)據(jù)結(jié)構(gòu)不一樣而已,但是,最大的不同是sphinx就像一張沒(méi)有任何關(guān)系查詢支持的單表數(shù)據(jù)庫(kù)。而且,索引主要用在搜索功能的實(shí)現(xiàn)而不是主要的數(shù)據(jù)來(lái)源。因此,你的數(shù)據(jù)庫(kù)也許是符合第三范式的,但索引會(huì)完全被非規(guī)范化而且主要包含需要被搜索的數(shù)據(jù)。
另外一點(diǎn),大部分?jǐn)?shù)據(jù)庫(kù)都會(huì)遭遇一個(gè)內(nèi)部碎片的問(wèn)題,它們需要在一個(gè)大請(qǐng)求里遭遇太多的半隨機(jī)I/O任務(wù)。那就是說(shuō),考慮一個(gè)在數(shù)據(jù)庫(kù)的索引中,查詢指向索引,索引指向數(shù)據(jù),如果數(shù)據(jù)因?yàn)樗槠瑔?wèn)題被分開(kāi)在不同的磁盤中,那么此次查詢將占用很長(zhǎng)的時(shí)間。
?
總結(jié)
通過(guò)一個(gè)項(xiàng)目的實(shí)踐,發(fā)現(xiàn)sphinx的使用要點(diǎn)主要在配置文件上,如果懂得配置了,那么基本用法很容易掌握。如果要深入研究,比如研究其工作原理,那就得查閱更多的資料。高級(jí)特性還沒(méi)有用到,日后用到再做分享。最后,如果還想擴(kuò)展sphinx,定制更強(qiáng)大的功能,可以直接閱讀源代碼,然后編寫擴(kuò)展。使用sphinx也有弊端,如果需要保證高質(zhì)量的搜索,那么就要經(jīng)常手動(dòng)維護(hù)詞庫(kù)。如果不能保持經(jīng)常更新詞庫(kù),那么可以考慮百度搜索之類的插件。如果可以加入機(jī)器學(xué)習(xí)的話,那么會(huì)更好。
轉(zhuǎn):
http://www.cnblogs.com/h-hq/p/5408933.html
如何聯(lián)系我:【萬(wàn)里虎】www.bravetiger.cn 【QQ】3396726884 (咨詢問(wèn)題100元起,幫助解決問(wèn)題500元起) 【博客】http://www.cnblogs.com/kenshinobiy/總結(jié)
以上是生活随笔為你收集整理的Sphinx的介绍和原理探索的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: No result defined fo
- 下一篇: 策略模式学习三---总结