Sphinx+MySQL5.1x+SphinxSE+mmseg中文分詞
搜索引擎架構搭建手記
什么是Sphinx
Sphinx是一個全文檢索引擎,一般而言,Sphinx是一個獨立的搜索引擎,意圖為其他應用提供高速、低空間占用、高結果相關度的全文搜索功能。Sphinx可以非常容易的與SQL數據庫和腳本語言集成。當前系統內置MySQL和PostgreSQL數據庫數據源的支持,也支持從標準輸入讀取特定格式的XML數據。通過修改源代碼,用戶可以自行增加新的數據源(例如:其他類型的DBMS的原生支持)。
Sphinx的特性
高速的建立索引(在當代CPU上,峰值性能可達到10 MB/秒);
高性能的搜索(在2–4GB的文本數據上,平均每次檢索響應時間小于0.1秒);
可處理海量數據(目前已知可以處理超過100 GB的文本數據,在單一CPU的系統上可處理100 M文檔);
提供了優秀的相關度算法,基于短語相似度和統計(BM25)的復合Ranking方法;支持分布式搜索;
provides documentexceprts generation;
可作為MySQL的存儲引擎提供搜索服務;
支持布爾、短語、詞語相似度等多種檢索模式;
文檔支持多個全文檢索字段(最大不超過32個);
文檔支持多個額外的屬性信息(例如:分組信息,時間戳等);
停止詞查詢;
支持單一字節編碼和UTF-8編碼;
原生的MySQL支持(同時支持MyISAM和InnoDB);
原生的PostgreSQL支持.
安裝
本文以CentOS5.5+mysql-5.1.55+sphinx-0.9.9(coreseek-3.2.14.tar.gz)為例介紹
Sphinx+MySQL5.1x+SphinxSE存儲引擎+mmseg中文分詞搜索引擎架構搭建過程。
1.安裝MySQL+SphinxSE,進入軟件包目錄
tar zxvfmysql-5.1.55.tar.gz
tar zxvfsphinx-0.9.9.tar.gz
cp -rsphinx-0.9.9/mysqlse/ mysql-5.1.55/storage/sphinxà把sphinx的源代碼復制到mysql源碼中
cdmysql-5.1.55
./BUILD/autorun.sh
./configure
--prefix=/usr/local/webserver/mysql/ --enable-assembler
--with-extra-charsets=complex --enable-thread-safe-client --with-big-tables
--with-readline --with-ssl --with-embedded-server --enable-local-infile
--with-plugins=partition,innobase,myisammrg,sphinx
make
make install
#/usr/sbin/groupadd mysql
#/usr/sbin/useradd -g mysql mysql
# chmod +w/usr/local/webserver/mysql
# chown -Rmysql:mysql /usr/local/webserver/mysql
①、創建MySQL數據庫存放目錄
#---------------------------------+
# mkdir -p /data0/mysql/3306/data/
# chown -Rmysql:mysql /data0/mysql/
#---------------------------------+
②、以mysql用戶帳號的身份建立數據表:
#---------------------------------+
#/usr/local/webserver/mysql/bin/mysql_install_db--basedir=/usr/local/webserver/mysql --datadir=/data0/mysql/3306/data--user=mysql
#---------------------------------+
③、創建my.cnf配置文件:
#--------------------------------+
# vi /data0/mysql/3306/my.cnf
#--------------------------------+
my.cnf輸入以下內容:
[client]
default-character-set= utf8
port = 3306
socket =/tmp/mysql.sock
[mysql]
no-auto-rehash
[mysqld]
user = mysql
port = 3306
socket =/tmp/mysql.sock
basedir =/usr/local/webserver/mysql
datadir =/data0/mysql/3306/data
open_files_limit= 10240
back_log = 600
max_connections= 3000
max_connect_errors= 6000
table_cache =614
external=locking= FALSE
max_allowed_packet= 32M
sort_buffer_size= 2M
join_buffer_size= 2M
thread_cache_size= 300
thread_concurrency= 8
query_cache_size= 32M
query_cache_limit= 2M
query_cache_min_res_unit= 2k
default-storage-engine= MyISAM
default_table_type= MyISAM
thread_stack =192K
transaction_isolation= READ-COMMITTED
tmp_table_size= 246M
max_heap_table_size= 246M
long_query_time= 1
log_long_format
log-bin = /data0/mysql/3306/binlog
binlog_cache_size = 4M
binlog_format= MIXED
max_binlog_cache_size= 8M
max_binlog_size= 512M
expire_logs_days= 7
key_buffer_size= 256M
read_buffer_size= 1M
read_rnd_buffer_size= 16M
bulk_insert_buffer_size= 64M
myisam_sort_buffer_size= 128M
myisam_max_sort_file_size= 10G
myisam_repair_threads= 1
myisam_recover
skip-name-resolve
master-connect-retry= 10
slave-skip-errors= 1032,1062,126,1114,1146,1048,1396
server-id = 1
[mysqldump]
quick
max_allowed_packet= 32M
#--------------------------------開啟MYSQL:---------------+
/usr/local/webserver/mysql/bin/mysqld_safe--defaults-file=/data0/mysql/3306/my.cnf 2>&1 > /dev/null &
#-----------------------------------------------------------+
#--------------------------------關閉MYSQL:---------------+
/usr/local/webserver/mysql/bin/mysqladmin-u root -p -S /tmp/mysql.sock shutdown
#-----------------------------------------------------------+
⑦、通過命令行登錄管理MySQL服務器(提示輸入密碼時直接回車):
#----------------------------------------------------------------+
#/usr/local/webserver/mysql/bin/mysql -u root -p -S /tmp/mysql.sock
#----------------------------------------------------------------+
。
安裝完成啟動MySQL后查看sphinx存儲引擎是否安裝成功
在mysql命令行下執行
show engines;
如果出現如下圖紅色方框內的信息說明SphinxSE已經安裝成功!
安裝Sphinx全文檢索服務器
Sphinx默認不支持中文索引及檢索,以前用Coreseek的補丁來解決,目前Coreseek不單獨提供補丁文件,而基于sphinx開發了Coreseek全文檢索服務器,Coreseek應該是現在用的最多的sphinx中文全文檢索,它提供了為Sphinx設計的中文分詞包LibMMSeg包含mmseg中文分詞,其實coreseek-3.2.14.tar.gz中已經包含了sphinx,前面安裝SphinxSE時也可以使用這個壓縮包里的mysqlse。
我們來看一下的安裝過程:
安裝autoconf
Bzip2 –dautoconf-2.65.tar.bz2
tar xvfautoconf-2.65.tar
cdautoconf-2.65
./configure--prefix=/usr
make
make install
cd ..
安裝Coreseek
tar zxvfcoreseek-3.2.14.tar.gz
cdcoreseek-3.2.14
cdmmseg-3.2.14/
./bootstrap
./configure--prefix=/usr/local/mmseg3
make
make install
cd../csft-3.2.14/
shbuildconf.sh
./configure--prefix=/usr/local/coreseek --without-python --without-unixodbc --with-mmseg--with-mmseg-includes=/usr/local/mmseg3/include/mmseg/--with-mmseg-libs=/usr/local/mmseg3/lib/ --with-mysql=/usr/local/webserver/mysql--host=arm
make
make install
ln -s/usr/local/webserver/mysql/lib/mysql/libmysqlclient.so.16 /usr/lib
cd/usr/local/coreseek/etc
進入配置目錄通過命令ls可以看到3個文件
example.sqlsphinx.conf.distsphinx-min.conf.dist
其中example.sql是示例sql腳本我們將其導入到數據庫中的test數據庫中作為測試數據(會創建兩張表documents和tags)
vi sphinx.conf
輸入以下內容
#定義一個數據庫源,名字為src1
source src1
{
type=mysql
sql_host=localhost
sql_user=root
sql_pass=
sql_db= test
sql_port=3306# optional, default is 3306
sql_sock= /tmp/mysql.sock
sql_query_pre= SET NAMES utf8
sql_query=\
SELECT id,title,content FROM songs
sql_query_info= SELECT * FROM songs WHERE id=$id
}
#定義建立索引項
index test1
{
source=src1
path=/usr/local/coreseek/var/data/test1
charset_type= zh_cn.utf-8
charset_dictpath= /usr/local/mmseg3/etc/
}
#建索引程序的設置
indexer
{
#建索引時所用的內存限制
mem_limit=32M
}
#提供服務的進程配置
searchd
{
port=9312
log=/usr/local/coreseek/var/log/searchd.log
query_log=/usr/local/coreseek/var/log/query.log
read_timeout=5
max_children=30
pid_file=/usr/local/coreseek/var/log/searchd.pid
max_matches=1000
seamless_rotate= 1
preopen_indexes= 0
unlink_old=1
}
說明:
代碼段source src1{***}代表數據源里面主要包含了數據庫的配置信息,src1表示數據源名字,可以隨便寫。
代碼段index test1{***}代表為哪個數據源創建索引,與source ***是成對出現的,其中的source參數的值必須是某一個數據源的名字。
其他參數可以查看手冊,這里不再贅述。
生成索引
/usr/local/coreseek/bin/indexer-c /usr/local/coreseek/etc/sphinx.conf --all
其中參數--all表示生成所有索引
當然也可以是索引的名字例如:/usr/local/coreseek/bin/indexer-c /usr/local/coreseek/etc/sphinx.conf test1
執行后可以在/usr/local/coreseek/var/data目錄中看到多出一些文件,是以索引名為文件名的不同的擴展名的文件
在不啟動sphinx的情況下即可測試命令:
/usr/local/coreseek/bin/search -c/usr/local/coreseek/etc/sphinx.conf number
可以看到將內容中含有number數據的數據查詢出來。
/usr/local/coreseek/bin/search
-c /usr/local/coreseek/etc/sphinx.conf研究生創業
可以看到我們輸入的查詢文字已經被拆分成了兩個詞,只是因為我們的測試數據中沒有中文數據查詢結果為空。我們插入幾條新數據。
INSERT INTO`test`.`documents` (
`id` ,
`group_id` ,
`group_id2` ,
`date_added` ,
`title` ,
`content`
)
VALUES (
NULL , '2',
'3', '2011-02-01 00:37:12', '研究生的故事', '研究生自主創業'
), (
NULL , '1',
'1', '2011-01-28 00:38:22', '研究', '為了創業而研究生命科學'
);
我們再來看以下數據庫中的主要數據
插入新數據后需要重新生成索引
/usr/local/coreseek/bin/indexer-c /usr/local/coreseek/etc/sphinx.conf test1
然后執行查詢測試/usr/local/coreseek/bin/search -c /usr/local/coreseek/etc/sphinx.conf研究生創業
我們搜索的詞語是“研究生創業”,可以看到詞語被拆分成了研究生和創業兩個詞,雖然有兩條記錄都包含“創業和”研究生”這幾個字但是“研究生命科學”中的“研究生”三個字雖然是緊挨著的但是不是一個詞語,結果是只匹配一條“研究生自主創業”,我們在搜索“研究”這個詞語
/usr/local/coreseek/bin/search
-c /usr/local/coreseek/etc/sphinx.conf研究
同樣匹配一條記錄,而“研究生的故事”和“研究生自主創業”的詞語卻沒有被查詢出來,可以看出sphinx與分詞技術結合可以匹配出相關度更高的結果。
當然我們的目的不僅限與命令行下的測試,我們可以通過搜索API調用來執行搜索,搜索API支持PHP、Python、Perl、Rudy和Java。如果從PHP腳本檢索需要先啟動守護進程searchd,PHP腳本需要連接到searchd上進行檢索:
/usr/local/coreseek/bin/searchd
-c /usr/local/coreseek/etc/sphinx.conf
在解壓后的sphinx-0.9.9/api目錄下的sphinxapi.php就是sphinx官方為我們提供的API文件(其實也可以使用PHP的sphinx擴展),只需將其包含進自己的PHP腳本文件就可以了。
示例代碼:
include('sphinxapi.php');
$cl=newSphinxClient();
//設置sphinx服務器地址與端口,如果是本機則可以為localhost
$cl->SetServer("192.168.16.6",9312);
//以下設置用于返回數組形式的結果
$cl->SetArrayResult (true);
//$cl->SetMatchMode( SPH_MATCH_ANY);//匹配模式
//$cl->SetFilter( 'group_id', array( 2 ) );
$result=$cl->Query('研究生創業','test1');//參數 關鍵字索引名
if($result===false) {
echo"Query failed: ".$cl->GetLastError() .".\n";
}
else{
if($cl->GetLastWarning() ) {
echo"WARNING: ".$cl->GetLastWarning() ."";
}
echo'<pre>';
print_r($result);
}
?>
執行后的結果:
Array
(
[error] =>
[warning] =>
[status] => 0
[fields] => Array
(
[0] => title
[1] => content
)
[attrs] => Array
(
[group_id] => 1
[date_added] => 2
)
[matches] => Array
(
[5] => Array
(
[weight] => 2
[attrs] => Array
(
[group_id] => 2
[date_added] => 1296491832
)
)
)
[total] => 1
[total_found] => 1
[time] => 0.078
[words] => Array
(
[研究生] =>Array
(
[docs] => 1
[hits] => 2
)
[創業] =>Array
(
[docs] => 2
[hits] => 2
)
)
)
在matches中的就是查詢結果,我們注意到sphinx是將記錄中的主鍵ID值返回而不是返回所有數據,上面的例子中的鍵名5就是記錄的ID(如果在查詢前執行$cl->SetArrayResult
( true );則數組結構會有些許差異)。至此搜索服務器已經為我們完成了大部分工作,接下來我們通過主鍵ID值來查詢我們想要的數據就可以了。
Sphinx存儲引擎的使用
SphinxSE是一個可以編譯進MySQL 5.x版本的MySQL存儲引擎,它利用了該版本MySQL的插件式體系結構。盡管被稱作“存儲引擎”,SphinxSE自身其實并不存儲任何數據。它其實是一個允許MySQL服務器與searchd交互并獲取搜索結果的嵌入式客戶端。所有的索引和搜索都發生在MySQL之外。
SphinxSE的適用于:
使將MySQL FTS應用程序移植到Sphinx
使沒有Sphinx API的那些語言也可以使用Sphinx
當需要在MySQL端對Sphinx結果集做額外處理(例如對原始文檔表做JOIN,MySQL端的額外過濾等等)時提供優化。
要通過SphinxSE搜索,需要建立特殊的ENGINE=SPHINX的“搜索表”,然后使用SELECT語句從中檢索,把全文查詢放在WHERE子句中。
創建一張表t1
CREATE TABLEt1
(
idINTEGER UNSIGNED NOT NULL,
weightINTEGER NOT NULL,
queryVARCHAR(3072) NOT NULL,
group_idINTEGER,
INDEX(query)
)ENGINE=SPHINX CONNECTION="sphinx://localhost:9312/test1";
搜索表前三列的類型必須是INTEGER,INTEGER和VARCHAR,這三列分別對應文檔ID,匹配權值和搜索查詢。查詢列必須被索引,其他列必須無索引。列的名字會被忽略,所以可以任意命名,參數CONNECTION來指定用這個表搜索時的默認搜索主機、端口號和索引,語法格式:CONNECTION="sphinx://HOST:PORT/INDEXNAME"。
執行SQL語句select d.id,d.title,d.content from t1 join documents as d on t1.id
= d.id and t1.query = '研究生創業';
+----+--------------------+-----------------------+
| id |title| content|
+----+--------------------+-----------------------+
|5 |研究生的故事|研究生自主創業|
+----+--------------------+-----------------------+
1 row in set(0.04 sec)
結果返回了我們想要的數據,可見利用SphinxSE可以僅僅在SQL語句上做很小的改動即可很方便的實現全文檢索!
主索引+增量索引
前提:數據不會被改變
第一步:建表:(用來存索引過的最大的記錄id)
Create table a
{
Id int unsigned not nullprimary key,
Max_idint unsigned,
}
第二步:修改配置文件為:見sphinx配置文件.doc
第三步:先執行./bin/indexer–c ./etc/sphinx.conf –test1生成所有的索引-〉一個數據源的主查詢,只有第一次執行
第四步:定期執行:./bin/indexer–c./etc/sphinx.conf delta --rotateà生成增量的索引文件
第五步:合并到主索引中./bin/indexer –merge test1 delta –c ./etc/sphinx.conf --rotate