What/Sphinx是什么
定義:Sphinx是一個全文檢索引擎迟蜜。
特性:
索引和性能優(yōu)異
易于集成SQL和XML數(shù)據(jù)源,并可使用SphinxAPI娜睛、SphinxQL或者SphinxSE搜索接口
易于通過分布式搜索進(jìn)行擴(kuò)展
高速的索引建立(在當(dāng)代CPU上,峰值性能可達(dá)到10 ~ 15MB/秒)
高性能的搜索 (在1.2G文本卦睹,100萬條文檔上進(jìn)行搜索畦戒,支持高達(dá)每秒150~250次查詢)
Why/為什么使用Sphinx
遇到的使用場景
遇到一個類似這樣的需求:用戶可以通過文章標(biāo)題和文章搜索到一片文章的內(nèi)容,而文章的標(biāo)題和文章的內(nèi)容分別保存在不同的庫结序,而且是跨機(jī)房的障斋。
可選方案
A、直接在數(shù)據(jù)庫實(shí)現(xiàn)跨庫LIKE查詢
優(yōu)點(diǎn):簡單操作
缺點(diǎn):效率較低徐鹤,會造成較大的網(wǎng)絡(luò)開銷
B垃环、結(jié)合Sphinx中文分詞搜索引擎
優(yōu)點(diǎn):效率較高,具有較高的擴(kuò)展性
缺點(diǎn):不負(fù)責(zé)數(shù)據(jù)存儲
使用Sphinx搜索引擎對數(shù)據(jù)做索引凳干,數(shù)據(jù)一次性加載進(jìn)來晴裹,然后做了所以之后保存在內(nèi)存。這樣用戶進(jìn)行搜索的時候就只需要在Sphinx服務(wù)器上檢索數(shù)據(jù)即可救赐。而且涧团,Sphinx沒有MySQL的伴隨機(jī)磁盤I/O的缺陷只磷,性能更佳。
其他典型使用場景
1泌绣、快速钮追、高效、可擴(kuò)展和核心的全文檢索
數(shù)據(jù)量大的時候阿迈,比MyISAM和InnoDB都要快元媚。
能對多個源表的混合數(shù)據(jù)創(chuàng)建索引,不限于單個表上的字段苗沧。
能將來自多個索引的搜索結(jié)果進(jìn)行整合刊棕。
能根據(jù)屬性上的附加條件對全文搜索進(jìn)行優(yōu)化。
2待逞、高效地使用WHERE子句和LIMIT字句
當(dāng)在多個WHERE條件做SELECT查詢時甥角,索引選擇性較差或者根本沒有索引支持的字段,性能較差识樱。sphinx可以對關(guān)鍵字做索引嗤无。區(qū)別是,MySQL中怜庸,是內(nèi)部引擎決定使用索引還是全掃描当犯,而sphinx是讓你自己選擇使用哪一種訪問方法。因?yàn)閟phinx是把數(shù)據(jù)保存到RAM中割疾,所以sphinx不會做太多的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ù)中同時產(chǎn)生幾份結(jié)果,同樣是使用固定量的內(nèi)存燕垃。作為對比枢劝,傳統(tǒng)SQL方法要么運(yùn)行兩個查詢,要么對每個搜索結(jié)果集創(chuàng)建一個臨時表卜壕。而sphinx用一個multi-query機(jī)制來完成這項(xiàng)任務(wù)您旁。不是一個接一個地發(fā)起查詢,而是把幾個查詢做成一個批處理轴捎,然后在一個請求里提交鹤盒。
5蚕脏、向上擴(kuò)展和向外擴(kuò)展
向上擴(kuò)展:增加CPU/內(nèi)核、擴(kuò)展磁盤I/O
向外擴(kuò)展:多個機(jī)器侦锯,即分布式sphinx
6驼鞭、聚合分片數(shù)據(jù)
適合用在將數(shù)據(jù)分布在不同物理MySQL服務(wù)器間的情況。
例子:有一個1TB大小的表尺碰,其中有10億篇文章挣棕,通過用戶ID分片到10個MySQL服務(wù)器上,在單個用戶的查詢下當(dāng)然很快亲桥,如果需要實(shí)現(xiàn)一個歸檔分頁功能洛心,展示某個用戶的所有朋友發(fā)表的文章。那么就要同事訪問多臺MySQL服務(wù)器了两曼。這樣會很慢皂甘。而sphinx只需要創(chuàng)建幾個實(shí)例,在每個表里映射出經(jīng)常訪問的文章屬性悼凑,然后就可以進(jìn)行分頁查詢了,總共就三行代碼的配置璧瞬。
How/如何使用Sphinx
Sphinx工作流程圖:
流程圖解釋:
- Database:數(shù)據(jù)源户辫,是Sphinx做索引的數(shù)據(jù)來源。因?yàn)镾phinx是無關(guān)存儲引擎嗤锉、數(shù)據(jù)庫的渔欢,所以數(shù)據(jù)源可以是MySQL、PostgreSQL瘟忱、XML等數(shù)據(jù)奥额。
- Indexer:索引程序,從數(shù)據(jù)源中獲取數(shù)據(jù)访诱,并將數(shù)據(jù)生成全文索引垫挨。可以根據(jù)需求触菜,定期運(yùn)行Indexer達(dá)到定時更新索引的需求九榔。
- Searchd:Searchd直接與客戶端程序進(jìn)行對話,并使用Indexer程序構(gòu)建好的索引來快速地處理搜索查詢涡相。
- APP:客戶端程序哲泊。接收來自用戶輸入的搜索字符串,發(fā)送查詢給Searchd程序并顯示返回結(jié)果催蝗。
Sphinx的工作原理
Sphinx的整個工作流程就是Indexer程序到數(shù)據(jù)庫里面提取數(shù)據(jù)切威,對數(shù)據(jù)進(jìn)行分詞,然后根據(jù)生成的分詞生成單個或多個索引丙号,并將它們傳遞給searchd程序先朦。然后客戶端可以通過API調(diào)用進(jìn)行搜索缰冤。
介紹了Sphinx的工作原理后,那么接下來就要讓Sphinx工作起來烙无,先來看看Sphinx的配置锋谐。
Sphinx的配置
數(shù)據(jù)源配置
先來看一份數(shù)據(jù)源的配置文件示例:
source test
{
type? ? ? ? ? ? ? ? ? ? = mysql
sql_host? ? ? ? ? ? ? ? = 127.0.0.1
sql_user? ? ? ? ? ? ? ? = root
sql_pass? ? ? ? ? ? ? ? = root
sql_db? ? ? ? ? ? ? ? ? = test
sql_port? ? ? ? ? ? ? ? = 3306? ? # optional, default is 3306
sql_query_pre? ? ? ? ? = SET NAMES utf8
sql_query? ? ? = SELECT id, name, add_time FROM tbl_test
sql_attr_timestamp? ? ? = add_time
sql_query_info_pre? ? ? = SET NAMES utf8
sql_query_info? ? ? ? ? = SELECT * FROM tbl_test WHERE id=$id
}
其中
source后面跟著的是數(shù)據(jù)源的名字,后面做索引的時候會用到截酷;
type:數(shù)據(jù)源類型涮拗,可以為MySQL,PostreSQL迂苛,Oracle等等三热;
sql_host、sql_user三幻、sql_pass就漾、sql_db、sql_port是連接數(shù)據(jù)庫的認(rèn)證信息念搬;
sql_query_pre:定義查詢時的編碼
sql_query:數(shù)據(jù)源配置核心語句抑堡,sphinx使用此語句從數(shù)據(jù)庫中拉取數(shù)據(jù);
sql_attr_*:索引屬性朗徊,附加在每個文檔上的額外的信息(值)首妖,可以在搜索的時候用于過濾和排序。設(shè)置了屬性之后爷恳,在調(diào)用Sphinx搜索API時有缆,Sphinx會返回已設(shè)置了的屬性;
sql_query_info_pre:設(shè)置查詢編碼温亲,如果在命令行下調(diào)試出現(xiàn)問號亂碼時棚壁,可以設(shè)置此項(xiàng);
sql_query_info:設(shè)置命令行下返回的信息栈虚。
索引配置
index test_index
{
source? ? ? ? ? ? ? ? ? ? = test
path? ? ? ? ? ? ? ? ? ? ? = /usr/local/coreseek/var/data/test
docinfo? ? ? ? ? ? ? ? ? = extern
charset_dictpath? ? ? ? ? = /usr/local/mmseg3/etc/
charset_type? ? ? ? ? ? ? = zh_cn.utf-8
ngram_len? ? ? ? ? ? ? ? = 1
ngram_chars? ? ? ? ? ? ? = U+3000..U+2FA1F
}
其中
index后面跟的test_index是索引名稱
source:數(shù)據(jù)源名稱袖外;
path:索引文件基本名,indexer程序會將這個路徑作為前綴生成出索引文件名节芥。例如在刺,屬性集會存在/usr/local/sphinx/data/test1.spa中,等等头镊。
docinfo:索引文檔屬性值存儲模式蚣驼;
charset_dictpath:中文分詞時啟用詞典文件的目錄,該目錄下必須要有uni.lib詞典文件存在相艇;
charset_type:數(shù)據(jù)編碼類型颖杏;
ngram_len:分詞長度;
ngram_chars:要進(jìn)行一元字符切分模式認(rèn)可的有效字符集坛芽。
中文分詞核心配置
一元分詞
charset_type = utf8
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
mmseg分詞
charset_type = utf8
charset_dictpath = /usr/local/mmseg3/etc/
ngram_len = 0
運(yùn)行示例
數(shù)據(jù)庫數(shù)據(jù)
使用indexer程序做索引
查詢
可以看到留储,配置文件中的add_time被返回了翼抠,如上圖的1所示。而sql_query_info返回的信息如上圖的2所示获讳。
Sphinx的配置不是很靈活阴颖,此處根據(jù)工作流程給出各部分的配置,更多的高級配置可以在使用時查閱文檔丐膝。
介紹了Sphinx的配置之后量愧,繼續(xù)介紹在Sphinx中,負(fù)責(zé)做索引的程序Indexer是如何做索引的帅矗。
sphinx使用配置文件從數(shù)據(jù)庫讀出數(shù)據(jù)之后偎肃,就將數(shù)據(jù)傳遞給Indexer程序,然后Indexer就會逐條讀取記錄浑此,根據(jù)分詞算法對每條記錄建立索引累颂,分詞算法可以是一元分詞/mmseg分詞。下面先介紹Indexer做索引時使用的數(shù)據(jù)結(jié)構(gòu)和算法凛俱。
倒排索引
倒排索引是一種數(shù)據(jù)結(jié)構(gòu)紊馏,用來存儲在全文搜索下某個單詞在一個文檔或者一組文檔中的存儲位置的映射。它是文檔檢索系統(tǒng)中最常用的數(shù)據(jù)結(jié)構(gòu)蒲犬。
倒排索引(Inverted Index):倒排索引是實(shí)現(xiàn)“單詞-文檔矩陣”的一種具體存儲形式瘦棋,通過倒排索引,可以根據(jù)單詞快速獲取包含這個單詞的文檔列表暖哨。
傳統(tǒng)的索引是:索引ID->文檔內(nèi)容,而倒排索引是:文檔內(nèi)容(分詞)->索引ID凰狞∑茫可以類比正向代理和反向代理的區(qū)別來理解。正向代理把內(nèi)部請求代理到外部赡若,反向代理把外部請求代理到內(nèi)部达布。所以應(yīng)該理解為轉(zhuǎn)置索引比較合適。
倒排索引主要由兩個部分組成:“單詞詞典”和“倒排文件”逾冬。
單詞詞典是倒排索引中非常重要的組成部分黍聂,它用來維護(hù)文檔集合中出現(xiàn)過的所有單詞的相關(guān)信息,同時用來記載某個單詞對應(yīng)的倒排列表在倒排文件中的位置信息身腻。在支持搜索時产还,根據(jù)用戶的查詢詞,去單詞詞典里查詢嘀趟,就能夠獲得相應(yīng)的倒排列表脐区,并以此作為后續(xù)排序的基礎(chǔ)。
對于一個規(guī)模很大的文檔集合來說她按,可能包含幾十萬甚至上百萬的不同單詞牛隅,能否快速定位某個單詞直接影響搜索時的響應(yīng)速度炕柔,所以需要高效的數(shù)據(jù)結(jié)構(gòu)來對單詞詞典進(jìn)行構(gòu)建和查找,常用的數(shù)據(jù)結(jié)構(gòu)包括哈希加鏈表結(jié)構(gòu)和樹形詞典結(jié)構(gòu)媒佣。
倒排索引基礎(chǔ)知識
文檔(Document):一般搜索引擎的處理對象是互聯(lián)網(wǎng)網(wǎng)頁匕累,而文檔這個概念要更寬泛些,代表以文本形式存在的存儲對象默伍,相比網(wǎng)頁來說欢嘿,涵蓋更多種形式,比如Word巡验,PDF际插,html,XML等不同格式的文件都可以稱之為文檔显设。再比如一封郵件框弛,一條短信,一條微博也可以稱之為文檔捕捂。在本書后續(xù)內(nèi)容瑟枫,很多情況下會使用文檔來表征文本信息。
文檔集合(Document Collection):由若干文檔構(gòu)成的集合稱之為文檔集合指攒。比如海量的互聯(lián)網(wǎng)網(wǎng)頁或者說大量的電子郵件都是文檔集合的具體例子慷妙。
文檔編號(Document ID):在搜索引擎內(nèi)部,會將文檔集合內(nèi)每個文檔賦予一個唯一的內(nèi)部編號允悦,以此編號來作為這個文檔的唯一標(biāo)識膝擂,這樣方便內(nèi)部處理,每個文檔的內(nèi)部編號即稱之為“文檔編號”隙弛,后文有時會用DocID來便捷地代表文檔編號架馋。
單詞編號(Word ID):與文檔編號類似,搜索引擎內(nèi)部以唯一的編號來表征某個單詞全闷,單詞編號可以作為某個單詞的唯一表征叉寂。
Indexer程序就是根據(jù)配置好地分詞算法,將獲取到的記錄進(jìn)行分詞总珠,然后用倒排索引做數(shù)據(jù)結(jié)構(gòu)保存起來屏鳍。
分詞算法
一元分詞
一元分詞的核心配置
charsey_type = zh_cn.utf8
ngram_len = 1
ugram_chars = U+4E00..U+9FBF
ngram_len是分詞的長度。
ngram_chars標(biāo)識要進(jìn)行一元分詞切分模式的字符集局服。
原生的Sphinx支持的分詞算法是一元分詞钓瞭,這種分詞算法是對記錄的每個詞切割后做索引,這種索引的優(yōu)點(diǎn)就是覆蓋率高腌逢,保證每個記錄都能被搜索到降淮。缺點(diǎn)就是會生成很大的索引文件,更新索引時會消耗很多的資源。所以佳鳖,如果不是特殊需求霍殴,而且數(shù)據(jù)不是特別少的時候,都不建議使用一元分詞系吩。
國人在sphinx的基礎(chǔ)上開發(fā)了支持中文分詞的Coreseek来庭。Coreseek與Sphinx唯一的不同就是Coreseek還支持mmseg分詞算法做中文分詞。
mmseg分詞
mmseg分詞算法是基于統(tǒng)計(jì)模型的穿挨,所以算法的規(guī)則也是來自對語料庫的分析和數(shù)學(xué)歸納月弛,因?yàn)橹形淖址麤]有明確的分界,會導(dǎo)致大量的字符分界歧義科盛,而且帽衙,中文里面,詞和短語也很難界定贞绵,因此厉萝,算法除了要做統(tǒng)計(jì)和數(shù)學(xué)歸納之外,還要做歧義的解決榨崩。
在mmseg分詞中谴垫,有一個叫chunk的概念。
chunk母蛛,是一句話的分詞方式翩剪。包括一個詞條數(shù)組和四個規(guī)則。
如:研究生命彩郊,有“研究/生命”和“研究生/命”兩種分詞方式前弯,這就是兩個chunk。
一個chunk有四個屬性:長度秫逝、平均長度(長度/分詞數(shù))博杖、方差、單字自由度(各單詞條詞頻的對數(shù)之和)筷登。
做好分詞之后,會得到多種分詞方式哩盲,這時候就要使用一些過濾規(guī)則來完成歧義的解決前方,以得到最終的分詞方式。
歧義解決規(guī)則:
1廉油、最大匹配
匹配最大長度的詞惠险。如“國際化”,有“國際/化”抒线、“國際化”兩種分詞方式班巩,選擇后者。
2、最大平均詞長度
匹配平均詞最大的chunk抱慌。如“南京市長江大橋”逊桦,有“南京市/長江大橋”、“南京/市長/江大橋”三種分詞方式抑进,前者平均詞長度是7/2=3.5强经,后者是7/3=2.3,故選擇前者的分詞方式寺渗。
3匿情、最大方差
去方差最大的chunk。如“研究生命科學(xué)”信殊,有“研究生/命/科學(xué)”炬称、“研究/生命/科學(xué)“兩種分詞方式,而它們的詞長都一樣是2涡拘。所以需要繼續(xù)過濾玲躯,前者方差是0.82,后者方差是0鲸伴。所以選擇第一種分詞方式府蔗。
4、最大單字自由度
選擇單個字出現(xiàn)最高頻率的chunk汞窗。比如”主要是因?yàn)椤靶粘啵小敝饕?是/因?yàn)椤埃敝?要是/因?yàn)椤皟煞N分詞方式仲吏,它們的詞長不铆、方差都一樣,而”是“的詞頻較高裹唆,所以選擇第一種分詞方式誓斥。
如果經(jīng)過上述四個規(guī)則的過濾,剩下的chunk仍然大于一许帐,那這個算法也無能為力了劳坑,只能自己寫擴(kuò)展完成。
最后的最后
當(dāng)然成畦,有人會說數(shù)據(jù)庫的索引也可以做到sphinx索引距芬,只是數(shù)據(jù)結(jié)構(gòu)不一樣而已,但是循帐,最大的不同是sphinx就像一張沒有任何關(guān)系查詢支持的單表數(shù)據(jù)庫框仔。而且,索引主要用在搜索功能的實(shí)現(xiàn)而不是主要的數(shù)據(jù)來源拄养。因此离斩,你的數(shù)據(jù)庫也許是符合第三范式的,但索引會完全被非規(guī)范化而且主要包含需要被搜索的數(shù)據(jù)。
另外一點(diǎn)跛梗,大部分?jǐn)?shù)據(jù)庫都會遭遇一個內(nèi)部碎片的問題寻馏,它們需要在一個大請求里遭遇太多的半隨機(jī)I/O任務(wù)。那就是說茄袖,考慮一個在數(shù)據(jù)庫的索引中操软,查詢指向索引,索引指向數(shù)據(jù)宪祥,如果數(shù)據(jù)因?yàn)樗槠瑔栴}被分開在不同的磁盤中聂薪,那么此次查詢將占用很長的時間。
總結(jié)
通過一個項(xiàng)目的實(shí)踐蝗羊,發(fā)現(xiàn)sphinx的使用要點(diǎn)主要在配置文件上藏澳,如果懂得配置了,那么基本用法很容易掌握。如果要深入研究,比如研究其工作原理侥啤,那就得查閱更多的資料蝇率。高級特性還沒有用到凡泣,日后用到再做分享。最后,如果還想擴(kuò)展sphinx,定制更強(qiáng)大的功能撮抓,可以直接閱讀源代碼,然后編寫擴(kuò)展摇锋。使用sphinx也有弊端丹拯,如果需要保證高質(zhì)量的搜索,那么就要經(jīng)常手動維護(hù)詞庫荸恕。如果不能保持經(jīng)常更新詞庫乖酬,那么可以考慮百度搜索之類的插件。如果可以加入機(jī)器學(xué)習(xí)的話融求,那么會更好咬像。
原創(chuàng)文章,文筆有限生宛,才疏學(xué)淺施掏,文中若有不正之處,萬望告知茅糜。
如果本文對你有幫助,望點(diǎn)個贊素挽。