目錄
Sphinx是一個基于SQL的全文檢索引擎,可以結(jié)合MySQL,PostgreSQL做全文搜索,它可以提供比數(shù)據(jù)庫本身更專業(yè)的搜索功能,使得應(yīng)用程序更容易實現(xiàn)專業(yè)化的全文檢索。Sphinx特別為一些腳本語言設(shè)計搜索API接口,如PHP,Python,Perl,Ruby等,同時為MySQL也設(shè)計了一個存儲引擎插件。
從http://dev.mysql.com上下載MySQL5.0.45版安裝配置好MySQL,采用utf-8字符集
從Sphinx官網(wǎng)上http://www.sphinxsearch.com/downloads.html下載mysql-5.0.45-sphinxse-r871-win32.zip和sphinx-0.9.8-svn-r985-win32.zip
如果您的MySQL服務(wù)已啟動請先停止掉
解壓mysql-5.0.45-sphinxse-r871-win32.zip,將里面bin與share目錄覆蓋掉你的mysql安裝目錄下的相應(yīng)目錄
解壓sphinx-0.9.8-svn-r985-win32.zip ,將里面的文件解壓到D:\sphinx
sphinx的配置與實際應(yīng)用是相關(guān)的,因此以下我以例子進(jìn)行說明,至此sphinx安裝部分結(jié)束
下載mysql-5.1.22-rc.tar.gz解壓至/root/mysql-5.1.22
下載sphinx-0.9.8-svn-r985.tar.gz,解壓至/root/sphinx-0.9.8-svn-r985
將/root/sphinx-0.9.8-svn-r985/mysqlse下的文件復(fù)制至/root/mysql-5.1.22/storage/sphinx
在/root/mysql-5.1.22目錄下運行
sh BUILD/autorun.sh
./configure --prefix=/usr/local/mysql --with-charset=utf8 --with-extra-charsets=all \
--enable-thread-safe-client --enable-assembler --with-readline --with-big-tables \
--with-plugins=sphinx
make && make install
groupadd mysql
useradd –g mysql mysql
chown mysql:mysql /usr/local/mysql -R
cd /usr/local/mysql
bin/mysql_install_db –user=mysql
(此時系統(tǒng)可能會提示:
[Warning] Storage engine 'SPHINX' has conflicting typecode. Assigning value 42.
可忽略,不影響使用)
cp /root/mysql-5.1.22/support-files/mysql.server /etc/init.d/mysqld
chmod 700 /etc/init.d/mysqld
cp /root/mysql-5.1.22/support-files/my-medium.cnf /etc/my.cnf
/etc/init.d/mysql start
(至些mysql啟動了)
然后進(jìn)入mysql命令行,運行show engines,看是不是有一個叫sphinx的engine,有的話就表示sphinxSE(mysql的sphinx引擎)安裝正常了
進(jìn)入/root/sphinx-0.9.8-svn-r985,運行
ldconfig /usr/local/mysql/lib/mysql
ldconfig /usr/local/mysql/include/mysql
./configure --prefix=/usr/local/sphinx --with-mysql=/usr/local/mysql
make && make install
為更好說明如何應(yīng)用Sphinx,現(xiàn)結(jié)合實例說明,我們以網(wǎng)站的新聞文章表為例。我們想要對新聞文章表進(jìn)行全文檢索(主要是標(biāo)題與內(nèi)容),新聞文章表的相關(guān)信息如下:
CREATE TABLE `eht_articles` (
`ARTICLESID` int(11) NOT NULL auto_increment,
`TITLE` varchar(100) NOT NULL default '',
`TITLECOLOR` varchar(20) default NULL,
`AUTHOR` varchar(200) default NULL,
`COMEFROM` varchar(200) default NULL,
`KEYWORD` varchar(200) default NULL,
`HTMLURL` varchar(200) default NULL,
`CATALOGID` int(6) default NULL,
`CONTENTS` mediumtext,
`EDITUSERID` int(6) default NULL,
`ADDTIME` int(10) default NULL,
`UPDATETIME` int(10) default NULL,
`HITS` int(6) default NULL,
PRIMARY KEY (`ARTICLESID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
在這個表中,我主要想對標(biāo)題(TITLE)與內(nèi)容(CONTENTS)字段進(jìn)行全文檢索,在檢索過程中可能我會根據(jù)文章的欄目(CATALOGID),編輯(EDITUSERID),時間段(ADDTIME)進(jìn)行條件性的全文檢索,然后可能會根據(jù)主鍵ID(ARTICLESID),人氣(HITS)進(jìn)行排序顯示,如何配置Sphinx來實現(xiàn)呢?
sphinx是以sphinx.conf為配置文件,索引與搜索均以這個文件為依據(jù)進(jìn)行,要進(jìn)行全文檢索,首先就要配置好sphinx.conf,告訴sphinx哪些字段需要進(jìn)行索引,哪些字段需要在where,orderby,groupby中用到。
安裝完Sphinx后,在D:/sphinx目錄有一個sphinx.conf.in,這個相當(dāng)于sphinx的配置例子文件,我們以這個文件為藍(lán)本,重新創(chuàng)建一個空白內(nèi)容的sphinx.conf,存放在d:/sphinx根目錄。
sphinx.conf的內(nèi)容組成
source 源名稱1{
…
}
index 索引名稱1{
source=源名稱1
…
}
source 源名稱2{
…
}
index 索引名稱2{
source = 源名稱2
…
}
indexer{
…
}
searchd{
…
}
從組成我們可以發(fā)現(xiàn)sphinx可以定義多個索引與數(shù)據(jù)源,不同的索引與數(shù)據(jù)源可以應(yīng)用到不同表或不同應(yīng)用的全文檢索。
根據(jù)前面的實例,我們配置出我們需要的sphinx.conf,如下:
source cgfinal
{
type = mysql
strip_html = 0
index_html_attrs =
sql_host = localhost
sql_user = root
sql_pass = admin
sql_db = test
sql_port= 3306 # optional, default is 3306
sql_query_pre= SET NAMES utf8
sql_query = SELECT ARTICLESID,TITLE,CONTENTS,AUTHOR,CATALOGID,ADDTIME,EDITUSERID,\
HITS FROM a.eht_news_articles
#sql_query = SELECT * FROM a.eht_news_articles
sql_attr_uint= CATALOGID
sql_attr_uint= EDITUSERID
sql_attr_uint = HITS
sql_attr_timestamp = ADDTIME
sql_query_post =
sql_ranged_throttle= 0
#sql_query_info = SELECT * FROM a.eht_news_articles WHERE ARTICLESID=$id
}
index cgfinal
{
source = cgfinal
path = d:/sphinx/data/cgfinal
docinfo = extern
mlock = 0
morphology = none
stopwords =
min_word_len = 1
charset_type = utf-8
charset_table = U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z,\
A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6,\
U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101,\
U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109,\
U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F,\
U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, \
U+0116->U+0117,U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D,\
U+011D,U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, \
U+0134->U+0135,U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, \
U+013C,U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, \
U+0143->U+0144,U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, \
U+014B,U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, \
U+0152->U+0153,U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159,\
U+0159,U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, \
U+0160->U+0161,U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, \
U+0167,U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, \
U+016E->U+016F,U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175,\
U+0175,U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, \
U+017B->U+017C,U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, \
U+0430..U+044F,U+05D0..U+05EA, U+0531..U+0556->U+0561..U+0586, U+0561..U+0587, \
U+0621..U+063A, U+01B9,U+01BF, U+0640..U+064A, U+0660..U+0669, U+066E, U+066F, \
U+0671..U+06D3, U+06F0..U+06FF,U+0904..U+0939, U+0958..U+095F, U+0960..U+0963, \
U+0966..U+096F, U+097B..U+097F,U+0985..U+09B9, U+09CE, U+09DC..U+09E3, U+09E6..U+09EF, \
U+0A05..U+0A39, U+0A59..U+0A5E,U+0A66..U+0A6F, U+0A85..U+0AB9, U+0AE0..U+0AE3, \
U+0AE6..U+0AEF, U+0B05..U+0B39,U+0B5C..U+0B61, U+0B66..U+0B6F, U+0B71, U+0B85..U+0BB9, \
U+0BE6..U+0BF2, U+0C05..U+0C39,U+0C66..U+0C6F, U+0C85..U+0CB9, U+0CDE..U+0CE3, \
U+0CE6..U+0CEF, U+0D05..U+0D39, U+0D60,U+0D61, U+0D66..U+0D6F, U+0D85..U+0DC6, \
U+1900..U+1938, U+1946..U+194F, U+A800..U+A805,U+A807..U+A822, U+0386->U+03B1, \
U+03AC->U+03B1, U+0388->U+03B5, U+03AD->U+03B5,U+0389->U+03B7, U+03AE->U+03B7, \
U+038A->U+03B9, U+0390->U+03B9, U+03AA->U+03B9,U+03AF->U+03B9, U+03CA->U+03B9, \
U+038C->U+03BF, U+03CC->U+03BF, U+038E->U+03C5,U+03AB->U+03C5, U+03B0->U+03C5, \
U+03CB->U+03C5, U+03CD->U+03C5, U+038F->U+03C9,U+03CE->U+03C9, U+03C2->U+03C3, \
U+0391..U+03A1->U+03B1..U+03C1,U+03A3..U+03A9->U+03C3..U+03C9, U+03B1..U+03C1, \
U+03C3..U+03C9, U+0E01..U+0E2E,U+0E30..U+0E3A, U+0E40..U+0E45, U+0E47, U+0E50..U+0E59, \
U+A000..U+A48F, U+4E00..U+9FBF,U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF, \
U+2F800..U+2FA1F, U+2E80..U+2EFF,U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF, \
U+3040..U+309F, U+30A0..U+30FF,U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF, \
U+3130..U+318F, U+A000..U+A48F,U+A490..U+A4CF
min_prefix_len = 0
min_infix_len = 1
ngram_len = 1
ngrams_chars = U+4E00..U+9FBF, U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF,\
U+2F800..U+2FA1F, U+2E80..U+2EFF, U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF,\
U+3040..U+309F, U+30A0..U+30FF, U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF,\
U+3130..U+318F, U+A000..U+A48F, U+A490..U+A4CF
}
indexer
{
mem_limit = 32M
}
searchd
{
# address = 0.0.0.0
port = 3312
log = d:/sphinx/log/searchd.log
query_log = d:/sphinx/log/query.log
read_timeout = 5
max_children = 30
pid_file = d:/sphinx/log/searchd.pid
max_matches = 1000
seamless_rotate = 1
}
相關(guān)配置項說明:
Source部分配置項說明
#type 數(shù)據(jù)庫類型,目前支持mysql與pgsql
#strip_html 是否去掉html標(biāo)簽
#sql_host 數(shù)據(jù)庫主機地址
#sql_user 數(shù)據(jù)庫用戶名
#sql_pass 數(shù)據(jù)庫密碼
#sql_db 數(shù)據(jù)庫名稱
#sql_port 數(shù)據(jù)庫采用的端口
#sql_query_pre 執(zhí)行sql前要設(shè)置的字符集,用utf8必須SET NAMES utf8
#sql_query 全文檢索要顯示的內(nèi)容,在這里盡可能不使用where或group by,將where與
groupby的內(nèi)容交給sphinx,由sphinx進(jìn)行條件過濾與groupby效率會更高
#注意:select 出來的字段必須至少包括一個唯一主鍵(ARTICLESID)以及要全文檢索的
字段,你計劃原本在where中要用到的字段也要select出來
#這里不用使用orderby
#sql_attr_開頭的表示一些屬性字段,你原計劃要用在where,orderby,groupby中的字段要
在這里定義
#根據(jù)我們原先的SQL:
#select * from eht_articles where title like ? and catalogid=? And edituserid=? \
And addtime between ? and ? order by hits desc
#我們需要對catalogid,edituserid,addtime,hits進(jìn)行屬性定義(這四個字段也要在select的
字段列表中),定義時不同的字段類型有不同的屬性名稱,具體可以見sphinx.conf.in中的說明
index部分配置項說明
#source 數(shù)據(jù)源名
#path 索引記錄存放目錄,如d:/sphinx/data/cgfinal,實際存放時會存放在d:/sphinx/data目
錄,然后創(chuàng)建多個cgfinal名稱,不同擴展名的索引文件。
#其他的配置如min_word_len,charset_type,charset_table,ngrams_chars,ngram_len這些則是支
持中文檢索需要設(shè)置的內(nèi)容。
#如果檢索的不是中文,則charset_table,ngrams_chars,min_word_len就要設(shè)置不同的內(nèi)容,具
體官方網(wǎng)站的論壇中有很多,大家可以去搜索看看。
首先要對數(shù)據(jù)進(jìn)行索引或重建索引
進(jìn)入命令行,運行d:/sphinx/bin/release/indexer --config d:/sphinx/sphinx.conf cgfinal
如果您在sphinx.conf中配置了多個數(shù)據(jù)源,想一次性全部索引則d:/sphinx/bin/release/indexer --config d:/sphinx/sphinx.conf --all
如果只是想對某個數(shù)據(jù)源進(jìn)行索引,則d:/sphinx/bin/release/indexer --config d:/sphinx/sphinx.conf 索引名稱(這里的索引名稱是你在sphinx.conf中定義的索引名稱)
運行檢索守護(hù)進(jìn)程searchd
進(jìn)入命令行,運行d:/sphinx/bin/release/searchd --config d:/sphinx/sphinx.conf,此時系統(tǒng)會在3312端口偵聽mysql的全文檢索請求,所以如果您的mysql與sphinx不在同一臺機器,要保證3312端口不被防火墻阻隔。
SPH_MATCH_ALL,匹配所有查詢詞(缺省模式)
SPH_MATCH_ANY,匹配任意查詢詞
SPH_MATCH_PHRASE,短語匹配
SPH_MATCH_BOOLEAN,布爾表達(dá)式匹配
SPH_MATCH_EXTENDED,查詢匹配一個Sphinx內(nèi)部查詢語言表達(dá)式
布爾查詢允許使用下面特殊操作符:
AND:hello & world
OR:hello | world
NOT:hello -world或hello !world
Grouping:(hello world)
( cat -dog ) | ( cat -mouse)
AND是一個隱式操作符,“hello world”就相當(dāng)于“hello & world”。
OR的優(yōu)先級高于AND,所以“looking for cat | dog | mouse”的意思是“looking for (cat | dog | mouse)”而不是“(looking for cat) | dog | mouse”
象“-dog”這種隱式地包含了所有查詢記錄,是不會被執(zhí)行的。這主要是考慮到技術(shù)上與性能上的原因,從技術(shù)上來說,sphinx不能總保持所有文章的ID列表,性能上來說,當(dāng)結(jié)果集巨大(10-100M),執(zhí)行這樣的查詢將費耗較長時間。
擴展查詢允許合我下面特殊操作符:
操作符OR:hello | world
操作符NOT:hello -world或hello !world
字段搜索操作符:@title hello @body world
短語(phrase)搜索符:"hello world"
臨近(proximity)搜索符:"hello world"~10
"hello world" @title "example program"~5 @body python -(php|perl)
AND是一個隱式操作符,"hello world"表示hello與world都要出現(xiàn)在匹配的記錄中。
OR的優(yōu)先級高于AND,所以“looking for cat | dog | mouse”的意思是“looking for (cat | dog | mouse)”而不是“(looking for cat) | dog | mouse”
臨近距離在串中標(biāo)明了,主要是用來調(diào)整單詞數(shù)量,應(yīng)用在引號中的所有查詢字串。"cat dog mouse"~5表示包括這三個單詞在內(nèi),總共不能多于8個單詞的間隔。比如"CAT aaa bbb ccc DOG eee fff MOUSE"就不能匹配這個查詢,因為單詞間隔剛好是8個。
象aaa | ( bbb ccc | ( ddd eee ) )這樣的括號嵌套查詢目前還不支持,但以后會修正的。
否定(如NOT)只允許出現(xiàn)在頂層,不允許出現(xiàn)在括號內(nèi)(如groups)。這點是不會改變的。因為支持否定嵌套查詢會讓短語排序(phrase ranking)的實現(xiàn)變得過于復(fù)雜。
采用什么權(quán)重功能取決于搜索模式(Search mode)
在權(quán)重函數(shù)中,有兩個主要部分:(短語排名)phrase rank和statistical rank(統(tǒng)計排名)
短語排名是基于搜索詞在文檔和查詢短語中的最長公共子序列(LCS)的長度。所以如果在記錄中有切確的短語匹配,記錄的短語排名將有可能是最高的,等于查詢單詞的總個數(shù)。
統(tǒng)計排名是建立在經(jīng)典的BM25算法基礎(chǔ)之上,它只考慮詞頻。詞在全部文檔集合中以低的頻度出現(xiàn)或高頻度出現(xiàn)在匹配的文檔中,那么它獲得的權(quán)重就越大,最終的BM25權(quán)重是一個介于0到1之間的小數(shù)。
好的子短語匹配得到好的排名,最好的匹配放到最頂端。Sphinx作者的經(jīng)驗是:基于排名的密切短語比其它任何單獨的統(tǒng)計方式表現(xiàn)出較好的搜索質(zhì)量。
在SPH_MATCH_BOOLEAN 模式中,不需要計算權(quán)重,每條匹配記錄的權(quán)重都是1
在SPH_MATCH_ALL和SPH_MATCH_PHRASE模式中,最終的權(quán)重是短語排名權(quán)重的總和
(TOFIX:翻譯不暢)在SPH_MATCH_ANY模式中,本質(zhì)上是一樣的,但它也增加了每個字段的匹配單詞數(shù)量,在這之前,短語排名權(quán)重乘以一個足夠大的值以保證在任意一個字段的較高短語排名可以匹配排名較高者,即使它的字段權(quán)重比較低。
在SPH_MATCH_EXTENDED模式中,最終的權(quán)重是短語權(quán)重和BM25權(quán)重的總和,再乘以1000取整。
按上面配置,第5節(jié)點對數(shù)據(jù)庫進(jìn)行了索引,通過Sphinx自帶的search(在bin/release目錄)就可以在命令行進(jìn)行搜索:
(搜索CGArt)
windows上:
search -c d:/sphinx/sphinx.conf CGArt
Linux上:
cd /usr/local/sphinx
./bin/search -c sphinx.conf CGArt
運行后,系統(tǒng)提示一堆信息:
....
....
words:
1. 'cgart': 36 documents, 189 hits
這個表示庫中有36條記錄符合要求,出現(xiàn)CGArt的有189處。
應(yīng)用程序如果想調(diào)用Sphinx,可以從兩個方面:
一是通過Sphinx官方提供的API接口(接口有Python,Java,Php三種版本)
二是通過安裝SphinxSE(具體見1.2部分),然后創(chuàng)建一個中介sphinxSE類型的表,再通過執(zhí)行特定的SQL語句實現(xiàn)。
通過官方API調(diào)用Sphinx(以PHP為例)
在sphinx安裝目錄有一個API目錄,里面有三個PHP文件:test.php,test2.php和sphinxapi.php。sphinxapi.php是sphinx調(diào)用接口封裝文件,test.php是一個在命令行下執(zhí)行的查詢例子文件,test2.php是一個生成摘要的例子文件。
在命令下行運行test.php(Linux上沒有API目錄,需要從源程序包中復(fù)制api目錄至/usr/local/sphinx)
Windows上:
D:\sphinx\bin\release>c:\php5.2\php.exe -c c:\php5.2\php.ini ..\..\api\test.php -i cgfinal CGart
Linux上(php在/usr/local/php目錄,sphinx.conf在/usr/local/sphinx目錄):
cd /usr/local/sphinx
/usr/local/php/bin/php api/test.php -i cgfinal CGArt
Sphinx的API查詢接口主要有這些內(nèi)容(其實對照 一下sphinxapi.php就清楚了):
//創(chuàng)建Sphinx的客戶端接口對象$cl->Query()返回的內(nèi)容print_r后大概是:
$cl = new SphinxClient ();
//設(shè)置連接Sphinx主機名與端口
$cl->SetServer('localhost',3312);
//可選,為每一個全文檢索字段設(shè)置權(quán)重,主要根據(jù)你在sql_query中定義的字段的順序,Sphinx系統(tǒng)以后會調(diào)整,可以按字段名稱來設(shè)定權(quán)重
$cl->SetWeights ( array ( 100, 1 ) );
//設(shè)定搜索模式,SPH_MATCH_ALL,SPH_MATCH_ANY,SPH_MATCH_BOOLEAN,SPH_MATCH_EXTENDED,SPH_MATCH_PHRASE
$cl->SetMatchMode(SPH_MATCH_ALL);
//設(shè)定過濾條件$attribute是屬性名,相當(dāng)于字段名(用SPH_MATCH_EXTENDED時),$value是值,$exclude是布爾型,
當(dāng)為true時,相當(dāng)于$attribute!=$value,默認(rèn)值是false
$cl->SetFilter($attribute, $values, $exclude);
//設(shè)定group by
//根據(jù)分組方法,匹配的記錄集被分流到不同的組,每個組都記錄著組的匹配記錄數(shù)以及根據(jù)當(dāng)前排序方法本組中的最佳匹配記錄。
//最后的結(jié)果集包含各組的一個最佳匹配記錄,和匹配數(shù)量以及分組函數(shù)值
//結(jié)果集分組可以采用任意一個排序語句,包括文檔的屬性以及sphinx的下面幾個內(nèi)部屬性
//@id--匹配文檔ID
//@weight, @rank, @relevance--匹配權(quán)重
//@group--group by 函數(shù)值
//@count--組內(nèi)記錄數(shù)量
//$groupsort的默認(rèn)排序方法是@group desc,就是按分組函數(shù)值大小倒序排列
$cl->SetGroupBy($attribute, $func, $groupsort);
//設(shè)定order by的內(nèi)容,第一個參數(shù)是排序方法名,值有
// SPH_SORT_RELEVANCE,SPH_SORT_ATTR_DESC,SPH_SORT_ATTR_ASC,SPH_SORT_TIME_SEGMENTS,SPH_SORT_EXTENDED
//$sortby的值如"HITS desc"
$cl->SetSortMode(SPH_SORT_EXTENDED, $sortby);
//set count-distinct attribute for group-by queries,$distinct為字符串
$cl->SetGroupDistinct ( $distinct );
//相當(dāng)于mysql的limit $offset,$limit
$cl->SetLimits($start,$limit)
//$q是查詢的關(guān)鍵字,$index是索引名稱,當(dāng)?shù)扔?時表查詢所有索引
$res = $cl->Query ( $q, $index );
Array
(
[error] =>
[warning] =>
[status] => 0
[fields] => Array
(
[0] => title
[1] => contents
[2] => author
)
[attrs] => Array
(
[catalogid] => 1
[addtime] => 2
[edituserid] => 1
[hits] => 1
)
[matches] => Array
(
[380] => Array
(
[weight] => 1
[attrs] => Array
(
[catalogid] => 7
[addtime] => 1112677492
[edituserid] => 1
[hits] => 1470
)
)
[599] => Array
(
[weight] => 101
[attrs] => Array
(
[catalogid] => 7
[addtime] => 1115910729
[edituserid] => 1
[hits] => 1749
)
)
[850] => Array
(
[weight] => 1
[attrs] => Array
(
[catalogid] => 2
[addtime] => 1118741392
[edituserid] => 1
[hits] => 289
)
)
[877] => Array
(
[weight] => 1
[attrs] => Array
(
[catalogid] => 2
[addtime] => 1118898869
[edituserid] => 1
[hits] => 9870
)
)
[1040] => Array
(
[weight] => 101
[attrs] => Array
(
[catalogid] => 2
[addtime] => 1120708579
[edituserid] => 1
[hits] => 318
)
)
)
[total] => 129
[total_found] => 129
[time] => 0.000
[words] => Array
(
[design] => Array
(
[docs] => 129
[hits] => 265
)
)
)
從上面可以看出Query并不能全部取得我們想要的記錄內(nèi)容,比如說Title,Contents字段就沒有取出來,根據(jù)官方的說明是sphinx并沒有連到mysql去取記錄,只是根據(jù)它自己的索引內(nèi)容進(jìn)行計算,因此如果想用sphinxAPI去取得我們想要的記錄,還必須將Query的結(jié)果為依據(jù)去查詢MySQL才可以得到最終我們想要的結(jié)果集。
test2.php是一個摘要生成的例子文件,如果你的本地機器已裝好sphinx,php運行環(huán)境,你可以通過瀏覽器看查看test2.php的運行效果。
假設(shè)我要搜索關(guān)鍵詞"test",通過sphinx可以取到搜索結(jié)果,在顯示搜索結(jié)果時,我希望將含有"test"的進(jìn)行紅色或加粗顯示,同時,我不希望全部都顯示出來,只需要顯示一段摘要,就象google或百度那樣,搜出來的結(jié)果不是全篇顯示,只是部分顯示,這個就是摘要的作用。
以test2.php中為例,以下是test2.php的代碼:
<?php在IE上運行的效果是:
require ( "sphinxapi.php" );
$docs = array
(
"this is my test text to be highlighted, and for the sake of the testing we need to pump its length somewhat",
"another test text to be highlighted, below limit",
"test number three, without phrase match",
"final test, not only without phrase match, but also above limit and with swapped phrase text test as well",
);
$words = "test";
$index = "cgfinal";
$opts = array
(
"before_match" => "<span style='font-weight:bold;color:red'>",
"after_match" => "</span>",
"chunk_separator" => " ... ",
"limit" => 60,
"around" => 3,
);
foreach ( array(0,1) as $exact )
{
$opts["exact_phrase"] = $exact;
print "exact_phrase=$exact\n";
$cl = new SphinxClient ();
$res = $cl->BuildExcerpts ( $docs, $index, $words, $opts );
if ( !$res )
{
die ( "ERROR: " . $cl->GetLastError() . ".\n" );
} else
{
$n = 0;
foreach ( $res as $entry )
{
$n++;
print "n=$n, res=$entry<br/>";
}
print "\n";
}
}
?>
在實際環(huán)境中,上面代碼的$docs是我們用sphinx搜索出來的結(jié)果,這個結(jié)果利用BuildExcerpts方法可以實現(xiàn)摘要的功能。
采用SphinxSE方式調(diào)用Sphinx
采用sphinxSE必須要求為mySQL安裝sphinxSE Engine驅(qū)動,方法在第1節(jié)中我已講到
要創(chuàng)建一張sphinx 專用表,你可以這樣建
CREATE TABLE `sphinx` (
`id` int(11) NOT NULL,
`weight` int(11) NOT NULL,
`query` varchar(255) NOT NULL,
`CATALOGID` INT NOT NULL,
`EDITUSERID` INT NOT NULL,
`HITS` INT NULL,
`ADDTIME` INT NOT NULL,
KEY `Query` (`Query`)
) ENGINE=SPHINX DEFAULT CHARSET=utf8 CONNECTION='sphinx://localhost:3312/cgfinal';
注:與一般mysql表不同的是ENGINE=SPHINX DEFAULT CHARSET=utf8 CONNECTION='sphinx://localhost:3312/cgfinal';,這里表示這個表采用SPHINXSE引擎,字符集是utf8,與sphinx的連接串是'sphinx://localhost:3312/cgfinal,cgfinal是索引名稱
根據(jù)sphinx官方說明,這個表必須至少有三個字段,字段起什么名稱無所謂,但類型的順序必須是integer,integer,varchar,分別表示記錄標(biāo)識document ID,匹配權(quán)重weight與查詢query,同時document ID與query必須建索引。另外這個表還可以建立幾個字段,這幾個字段的只能是integer或TIMESTAMP類型,字段是與sphinx的結(jié)果集綁定的,因此字段的名稱必須與在sphinx.conf中定義的屬性名稱一致,否則取出來的將是Null值。
比如我在上面有定義了sql_attr_uint= CATALOGID,sql_attr_uint= EDITUSERID,sql_attr_uint = HITS,sql_attr_timestamp = ADDTIME,那么在這個表里頭,你就可以再定義CATALOGID,EDITUSERID,HITS,ADDTIME四個字段。
通過sql語句實現(xiàn)查詢。通過select * from sphinx where query='sphinx表達(dá)式' 的方式可以實現(xiàn)查詢,通過讓sphinx表與eht_articles或其他表并聯(lián)查詢(條件是sphinx.id=eht_articles.Articlesid)還可以實現(xiàn)更為復(fù)雜的sql,基本上可以符合我們?nèi)粘5囊蟆?/p>
sphinx表達(dá)式在sphinx的手冊中也提到了,這里我簡單說明幾條:
query='關(guān)鍵字' ,關(guān)鍵字就是你要搜索的關(guān)鍵字,如query='CGArt'表示你要全文搜索CGArt
mode,搜索模式,值有:all,any,phrase,boolean,extended,默認(rèn)是all
sort,排序模式,必須是relevance,attr_desc,attr_asc,time_segments,extended中的一種,在所有模式中除了relevance外,屬性名(或用extended排序)前面都需要一個冒號。
... where query='test;sort=attr_asc:hits';
... where query='test;sort=extended:@weight desc,hits asc';
offset,結(jié)果記錄集的起始位置,默認(rèn)是0
limit,從結(jié)果記錄集中取出的數(shù)量,默認(rèn)是20條
index,要搜索的索引名稱
... where query='test;index=cgfinal';
... where query='test;index=test1,test2,test3;';
minid,maxid,匹配最小與最大文檔ID
weights,以逗號分割的分配給sphinx全文檢索字段的權(quán)重列表
... where query='test;weights=1,2,3;';
filter,!filter,以逗號分隔的屬性名與一堆要匹配的值
#只包括1,5,19的組
... where query='test;filter=group_id,1,5,19;';
#不包括3,11的組
... where query='test;!filter=group_id,3,11';
range,!range,逗號分隔的屬性名一最小與最大要匹配的值
#從3至7的組
... where query='test;range=group_id,3,7;';
#不包括從5至25的組
... where query='test;!range=group_id,5,25;';
maxmatches,每個查詢最大匹配的值
... where query='test;maxmatches=2000;';
groupby,group by 方法與屬性
... where query='test;groupby=day:published_ts;';
... where query='test;groupby=attr:group_id;';
groupsort,group by 的排序
... where query='test;gropusort='@count desc';
需要注意的重要一點是讓sphinx進(jìn)行排序,過濾,切分結(jié)果記錄集比用MySQL的where,orderby 和limit將有更好的效率。有兩個原因,首先sphinx做了很多優(yōu)化,在這些任務(wù)上它比mySQL做得更出色,其次searchd在打包,sphinxSE在傳輸與解包上需要的數(shù)據(jù)量更少。
你可以通過運用join在sphinxSE的搜索表和其他引擎類型的表做并聯(lián)查詢。這有一個從example.sql中documents表的例子:
mysql> SELECT content, date_added FROM test.documents docs
-> JOIN t1 ON (docs.id=t1.id)
-> WHERE query="one document;mode=any";
+-------------------------------------+---------------------+
| content | docdate |
+-------------------------------------+---------------------+
| this is my test document number two | 2006-06-17 14:04:28 |
| this is my test document number one | 2006-06-17 14:04:28 |
+-------------------------------------+---------------------+
2 rows in set (0.00 sec)
mysql> SHOW ENGINE SPHINX STATUS;
+--------+-------+---------------------------------------------+
| Type | Name | Status |
+--------+-------+---------------------------------------------+
| SPHINX | stats | total: 2, total found: 2, time: 0, words: 2 |
| SPHINX | words | one:1:2 document:2:2 |
+--------+-------+---------------------------------------------+
2 rows in set (0.00 sec)
從eht_articles中查詢標(biāo)題含有“動畫”關(guān)鍵字的記錄。
select c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='@title 動畫;mode=extended'
說明:要指定某個字段進(jìn)行搜索,要用@字段名+空格+關(guān)鍵字+分號+mode=extended 如果不指定字段,則系統(tǒng)會對TITLE,CONTENTS進(jìn)行搜索 ,對什么字段進(jìn)行全文檢索取決于在sphinx.conf中sql_query定義的select 中的字段(文本類型)
從eht_articles中查詢文章內(nèi)容或標(biāo)題含有“CGArt”關(guān)鍵字的記錄。
select c.* from eht_articles as c,sphinx as t where c.articlesid=sphinx.id and query='動畫'
若AUTHOR,TITLE,CONTENTS三個字段都全文索引了,但只想搜title,或contents中含有“動畫”關(guān)鍵字的文章
select c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='@title 動畫 | @contents 動畫;mode=extended'
查詢標(biāo)題含有“動畫”關(guān)鍵字,catalogid為7,edituserid為1的記錄
select c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='@title 動畫;filter=edituserid,1;filter=catalogid,7;mode=extended'
采用filter=字段名稱,值就相當(dāng)于where中的 字段名=值,filter提到的字段必須在sphinx的source部分的字段屬性定義中定義,如
sql_attr_uint = CATALOGID
sql_attr_uint = EDITUSERID
sql_attr_uint = HITS
sql_attr_timestamp = ADDTIME
查詢標(biāo)題含有“動畫”關(guān)鍵字,按人氣Hits從大至小,欄目ID從大至小排序
select c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='@title 動畫;mode=extended;sort=extended:hits desc,catalogid desc'
在sphinx中,select出來的內(nèi)容是按weight從大至小排序的,weight是根據(jù)sphinx內(nèi)部一定的算法算出來的,越大就表示越匹配
,如果想按匹配度從大至小排序,則可以:
select c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='@title 動畫;mode=extended;sort=@weight desc'
搜內(nèi)容或標(biāo)題含有優(yōu)秀或Icon或設(shè)計,按catalogid分組,按匹配度從高至低排序
select t.*,c.* from eht_articles as c,sphinx as t where c.articlesid=t.id and query='優(yōu)秀 | Icon | 設(shè)計;mode=extended;groupby=attr:catalogid;groupsort=@weight;'
Sphinx官方網(wǎng)站:www.sphinxsearch.com
用php構(gòu)建自定義搜索引擎:http://www.ibm.com/developerworks/cn/opensource/os-php-sphinxsearch/index.html