下载coreseek 3.2.14
wget http://www.coreseek.cn/uploads/csft/3.2/coreseek-3.2.14.tar.gz
wget http://pecl.php.net/get/sphinx-1.3.2.tgz #sphinx扩展
coreseek安装需要预装的软件:
yum install make gcc g++ gcc-c++ libtool autoconf automake imake mysql-devel libxml2-devel expat-devel
安装xmlpipe2支持(如果上面已安装可以不用再安装)
[[email protected] tools]#yum -y install expat-devel*
[[email protected] tools]#tar -xzvf coreseek-3.2.14.tar.gz
[[email protected] tools]#cd coreseek-3.2.14
安装中文分词插件mmseg-3.2.14
[[email protected] coreseek-3.2.14]#cd mmseg-3.2.14
[[email protected] mmseg-3.2.14]# ./configure --prefix=/usr/local/mmseg3
安装时如果出现
config.status: error: cannot find input file: src/Makefile.in
可以通过安装autoconf和automake解决
[[email protected] mmseg-3.2.14]#yum -y install autoconf automake
[[email protected] mmseg-3.2.14]#aclocal
如果出现下面错误:
configure.in:26: warning: macro `AM_PROG_LIBTOOL‘ not found in library
[[email protected] mmseg-3.2.14]#yum -y install libtool
[[email protected] mmseg-3.2.14]#aclocal
[[email protected] mmseg-3.2.14]# libtoolize --force
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `config‘.
libtoolize: linking file `config/ltmain.sh‘
libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])‘ to configure.in and
libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree.
libtoolize: Consider adding `-I m4‘ to ACLOCAL_AMFLAGS in Makefile.am.
[[email protected] mmseg-3.2.14]# automake --add-missing
[[email protected] mmseg-3.2.14]# autoconf
[[email protected] mmseg-3.2.14]# autoheader
[[email protected] mmseg-3.2.14]# make clean
[[email protected] mmseg-3.2.14]# ./configure --prefix=/usr/local/mmseg3
[[email protected] mmseg-3.2.14]# make && make install
[[email protected] mmseg-3.2.14]# ln -s /usr/local/mmseg3/bin/mmseg /bin/mmseg
接下来安装Coreseek 3.2.14
[[email protected] mmseg-3.2.14]# cd ..
[[email protected] coreseek-3.2.14]# cd csft-3.2.14
[[email protected] csft-3.2.14]# ./configure --prefix=/usr/local/coreseek --without-unixodbc --with-mmseg-includes=/usr/local/mmseg3/include/mmseg/ --with-mmseg-libs=/usr/local/mmseg3/lib/ --with-mysql
[[email protected] csft-3.2.14]# make && make install
安装sphinx扩展模块
1)安装libsphinxclient依赖包
[[email protected] coreseek-3.2.14]#cd api/libsphinxclient
[[email protected] libsphinxclient]#./configure
[[email protected] libsphinxclient]# make && make install
2)安装PHP扩展
[[email protected] coreseek-3.2.14]# tar -xzvf sphinx-1.3.2.tgz
[[email protected] coreseek-3.2.14]# cd sphinx-1.3.2
[[email protected] sphinx-1.3.2]# /usr/local/php/bin/phpize
[[email protected] sphinx-1.3.2]# ./configure --with-php-config=/usr/local/php/bin/php-config --with-sphinx
[[email protected] sphinx-1.3.2]# make && make install
修改PHP配置文件,添加sphinx扩展
[[email protected] sphinx-1.3.2]# vi /usr/local/php/etc/php.ini
添加extension=sphinx.so
保存退出
重启PHP
/etc/init.d/php-fpm restart
测试coreseek中文分词
cd coreseek-3.2.14/testpack/
/usr/local/mmseg3/bin/mmseg -d /usr/local/mmseg3/etc var/test/test.xml
显示
Word Splite took: 35 ms.
[[email protected] testpack]#/usr/local/coreseek/bin/indexer -c etc/csft.conf --all
[[email protected] testpack]#/usr/local/coreseek/bin/search -c etc/csft.conf 网络搜索
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file ‘etc/csft.conf‘...
index ‘xml‘: query ‘网络搜索 ‘: returned 1 matches of 1 total in 0.001 sec
displaying matches:
1. document=1, weight=1, published=Thu Apr 1 22:20:07 2010, author_id=1
words:
1. ‘网络‘: 1 documents, 1 hits
2. ‘搜索‘: 2 documents, 5 hits
测试完毕,下面是一些错误提示以及相应的解决方法:
错误一:
/usr/local/mmseg3/include/mmseg/mmthunk.h: In member function ‘u2 css::ChunkQueue::getToken()‘:
/usr/local/mmseg3/include/mmseg/mmthunk.h:143: warning: comparison between signed and unsigned integer expressions
/usr/local/mmseg3/include/mmseg/mmthunk.h:161: warning: comparison between signed and unsigned integer expressions
sphinx.cpp: In member function ‘virtual void CSphIndex_VLN::DebugDumpDocids(FILE*)‘:
sphinx.cpp:15267: warning: format ‘%d‘ expects type ‘int‘, but argument 3 has type ‘long unsigned int‘
sphinxstd.h: In member function ‘bool CSphHTMLStripper::SetRemovedElements(const char*, CSphString&)‘:
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
sphinxstd.h: In member function ‘bool CSphHTMLStripper::SetIndexedAttrs(const char*, CSphString&)‘:
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
sphinxstd.h: In member function ‘virtual bool CSphIndex_VLN::GetKeywords(CSphVector<CSphKeywordInfo>&, const char*, bool)‘:
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
sphinxstd.h: In member function ‘virtual int CSphIndex_VLN::Build(const CSphVector<CSphSource*>&, int, int)‘:
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
sphinxstd.h:579: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true
make[2]: *** [sphinx.o] Error 1
make[2]: Leaving directory `/root/tools/coreseek-3.2.14/csft-3.2.14/src‘
make[1]: *** [all] Error 2
make[1]: Leaving directory `/root/tools/coreseek-3.2.14/csft-3.2.14/src‘
make: *** [all-recursive] Error 1
官网解决办法:
In the meantime I‘ve change the configuration file and set
#define USE_LIBICONV 0 in line 8179.
修改configure 文件把 #define USE_LIBICONV 0 最后的数值由1改为0
make && make install
错误二:
make[2]: *** [indexer] Error 1
make[2]: Leaving directory `/www/tmp/csft-3.1/src‘
make[1]: *** [all] Error 2
make[1]: Leaving directory `/www/tmp/csft-3.1/src‘
make: *** [all-recursive] Error 1
解决办法
vi ./src/sphinx.cpp
注释以下代码
#case TOKENIZER_ZHCN_GBK:
#pTokenizer = sphCreateGBKChineseTokenizer
#(tSettings.m_sDictPath.cstr(), tSettings.m_nBest); break;
然后重新编译
make clean
make && make install
错误三:索引不生成
/usr/local/coreseek/bin/indexer -c etc/csft.conf -all
改为
/usr/local/coreseek/bin/indexer -c etc/csft.conf --all
下面开始配置coreseek
cd /usr/local/coreseek/etc
cp sphinx-min.conf.dist csft.conf
vi csft.conf
#
# Minimal Sphinx configuration sample (clean, simple, functional)
#
source test1
{
type = mysql
sql_host = localhost
sql_user = root
sql_pass = root
sql_db = test
sql_port = 3306 # optional, default is 3306
sql_query_pre = SET NAMES utf8 #sql_query_pre是在执行查询之前执行的SQL语句。(注意:在coreseek只能识别utf8字符集编码,所以我们要执行转换一下)
sql_query = \
SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
FROM documents #sql_query是要查询进行索引的SQL语句
sql_attr_uint = group_id #sql_attr_uint:uint无符号整型属性,以上group_id、date_added都可用此设置,使用SetFilter()过滤,或者使用SetFilterRange()过滤;sql_attr_float :浮点数属性
sql_attr_timestamp = date_added #时间戳属性,经常被用于做排序
sql_query_info = SELECT * FROM documents WHERE id=$id #命令行获取信息查询.我们进行索引一般只会返回主键id,而不会返回表中的所有字段。但是在调试的时候,
#我们一般需要返回表中的字段,那这个时候,就需要使用sql_query_info。同时这个字段只在控制台有效,在api中是无效的。
}
index test1
{
source = test1 #索引数据源
type = plain #索引类型,包括有plain,distributed和rt。分别是普通索引/分布式索引/增量索引。默认是plain。
path = /usr/local/coreseek/var/data/test1 #索引文件存放路径
docinfo = extern #文档信息的存储模式,包括有none,extern,inline。默认是extern。docinfo指的就是数据的所有属性(field)构成的一个集合。
#首先文档id是存储在一个文件中的(spa),当使用inline的时候,文档的属性和文件的id都是存放在spa中的,所以进行查询过滤的时候,
#不需要进行额外操作。当使用extern的时候,文档的属性是存放在另外一个文件(spd)中的,但是当启动searchd的时候,会把这个文件加载到内存中。
#extern就意味着每次做查询过滤的时候,除了查找文档id之外,还需要去内存中根据属性进行过滤。
charset_dictpath = /usr/local/mmseg3/etc/ #必须设置,表示词典文件的目录,该目录下必须有uni.lib词典文件存在;特别注意,更换或者修改词典后,需要重新索引数据并重启searchd才能生效。
charset_type = utf-8 #字符集编码类型,可以为sbcs,utf-8。对于Coreseek,还可以有zh_cn.utf-8,zh_ch.gbk,zh_ch.big5。
#必须设置,表示启用中文分词功能;否则中文分词功能无效,使用sphinx的其他处理模式。
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F#表示可被一元字符切分模式认可的有效字符集
ngram_chars = U+3000..U+2FA1F #表示要进行一元字符切分模式的字符集
ngram_len = 1 #必须设置,0表示取消原有的一元字符切分模式,不使其对中文分词产生干扰;1表示使用一元字符切分模式,从而得以对单个中文字符进行索引;
#启用中文分词功能后,需要source数据源之中,读取的数据编码字符集为UTF-8,否则无法正确处理;
#morphology = none #词形处理器。词形处理是什么意思呢?比如在英语中,dogs是dog的复数,所以dog是dogs的词干,这两个实际上是同一个词。
#所以英语的词形处理器会讲dogs当做dog来进行处理。
#min_stemming_len = 1 #根据词的长度来决定是否要使用词形处理器。
#index_exact_words = 1 #词形处理后是否还要检索原词
#stopwords = /usr/local/coreseek/var/data/stopwords.txt #停止词,停止词是不被索引的词。
#wordforms = /usr/local/coreseek/var/data/wordforms.txt #自定义词形字典
#exceptions = /usr/local/coreseek/var/data/exceptions.txt #词汇特殊处理。有的一些特殊词我们希望把它当成另外一个词来处理。比如,c++ => cplusplus来处理。
#min_word_len = 1 #最小索引词长度,小于这个长度的词不会被索引。
#enable_star = 0 #是否启用通配符,默认为0,不启用。min_prefix_len,min_infix_len,prefix_fields,infix_fields都是在enable_star开启的时候才有效果。
#min_prefix_len = 0 #最小前缀索引长度。
#min_infix_len = 0 #最小索引中缀长度。
#prefix_fields = filename #前缀索引字段列表。
#infix_fields = url, domain #中缀索引字段列表。
#html_strip = 0 #html标记清理,是否从输出全文数据中去除HTML标记。
#html_index_attrs = img=alt,title; a=title; #HTML标记属性索引设置。
#html_remove_elements = style, script #需要清理的html元素
#preopen = 1 #searchd是预先打开全部索引还是每次查询再打开索引。
}
indexer
{
mem_limit = 32M #建立索引的时候,索引内存限制
#max_iops = 40 #每秒最大I/O操作次数,用于限制I/O操作
#max_iosize = 1048576 #最大允许的I/O操作大小,以字节为单位,用于I/O节流
#max_xmlpipe2_field = 4M #对于XMLLpipe2数据源允许的最大的字段大小,以字节为单位
#write_buffer = 1M #写缓冲区的大小,单位是字节
#max_file_field_buffer = 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 #进程id文件
max_matches = 1000 #守护进程在内存中为每个索引所保持并返回给客户端的匹配数目的最大值
seamless_rotate = 1 #无缝轮转。防止 searchd 轮换在需要预取大量数据的索引时停止响应
preopen_indexes = 0 #索引预开启,是否强制重新打开所有索引文件
unlink_old = 1 #索引轮换成功之后,是否删除以.old为扩展名的索引拷贝
#max_packet_size = 8M #网络通讯时允许的最大的包的大小
#crash_log_path = /usr/local/coreseek/var/log/crash #崩溃日志文件路径
#max_filters = 256 #每次查询允许设置的过滤器的最大个数
#max_filter_values = 4096 #单个过滤器允许的值的最大个数
#listen_backlog = 5 #TCP监听待处理队列长度
#read_buffer = 256K #每个关键字的读缓冲区的大小
#read_unhinted = 32K #无匹配时读操作的大小
#max_batch_queries = 32 #每次批量查询的查询数限制
#dist_threads = 4 #并发查询线程数
#binlog_path = /usr/local/coreseek/var/data/ #二进制日志路径
#binlog_max_log_size = 256M #二进制日志大小限制
#thread_stack = 128K #线程堆栈
#expansion_limit = 1000 #关键字展开限制
#rt_flush_period = 900 #RT索引刷新周期
#query_log_format = sphinxql #查询日志格式,可选项,可用值为plain、sphinxql,默认为plain。
#plugin_dir = /usr/local/sphinx/lib #插件目录
#collation_server = utf8_general_ci #服务端默认字符集
#watchdog = 1 #线程服务看守
#compat_sphinxql_magics = 1 #兼容模式
}
创建索引
[[email protected] bin]# /usr/local/coreseek/bin/indexer -c /usr/local/coreseek/etc/csft.conf test1
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file ‘/usr/local/coreseek/etc/csft.conf‘...
indexing index ‘test1‘...
collected 1431 docs, 0.1 MB
sorted 0.0 Mhits, 100.0% done
total 1431 docs, 57482 bytes
total 0.082 sec, 697427 bytes/sec, 17362.29 docs/sec
total 1 reads, 0.000 sec, 54.0 kb/call avg, 0.0 msec/call avg
total 5 writes, 0.000 sec, 30.7 kb/call avg, 0.0 msec/call avg
运行coreseek服务进程searchd
[[email protected] bin]# /usr/local/coreseek/bin/searchd -c /usr/local/coreseek/etc/csft.conf
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file ‘/usr/local/coreseek/etc/csft.conf‘...
listening on all interfaces, port=9312
测试:默认显示20条结果
[[email protected] bin]# /usr/local/coreseek/bin/search -i test1 技巧
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file ‘/usr/local/coreseek/etc/csft.conf‘...
index ‘course‘: query ‘技巧 ‘: returned 30 matches of 30 total in 0.003 sec
displaying matches:
1. document=37, weight=1
2. document=201, weight=1
3. document=202, weight=1
4. document=250, weight=1
5. document=285, weight=1
6. document=286, weight=1
7. document=356, weight=1
8. document=360, weight=1
9. document=393, weight=1
10. document=439, weight=1
11. document=493, weight=1
12. document=494, weight=1
13. document=527, weight=1
14. document=711, weight=1
15. document=732, weight=1
16. document=737, weight=1
17. document=790, weight=1
18. document=791, weight=1
19. document=869, weight=1
20. document=915, weight=1
words:
1. ‘技巧‘: 30 documents, 30 hits
接下来把这两个进程放在crontab里定时运行
*/5 * * * * /usr/local/coreseek/bin/indexer -c /usr/local/coreseek/etc/csft.conf --rotate --all >/dev/null 2>&1
至此服务器部分安装完成
接下来在thinkphp里进行搜索
class SearchAction extends Action
{
protected $sp;
protected function _initialize(){
$this->sp = new SphinxClient();
$this->sp->SetServer("localhost",9312);
}
/**
*
* 搜索入口
* @param string $type 索引名称(test1)
* @param string $word 搜索关键字
* @param int $page 页码
* @param int $length 每页显示条数
* @return array
*/
protected function _search($type,$word,$page=1,$length=10){
if(empty($type)||empty($word)){
return;
}
$this->sp->SetLimits(($page-1)*$length, $length);
if(!$rs = $this->sp->query($word,$type)){
return ;
}
$this->sp->Close();
return $rs;
}
/**
*
* 合并处理搜索结果中的ID
* @param array $value
* @return string 将ID用逗号连接起来的字符串
* [matches] => Array
(
[1596] => Array
(
[weight] => 1
[attrs] => Array
(
)
)
[1989] => Array
(
[weight] => 1
[attrs] => Array
(
)
)
)
*/
protected function _searchValueCombine($value){
if(!$value||!is_array($value)){
return ;
}
$str = ‘‘;
foreach ($value as $key => $v){
$str .= ‘,‘.$key;
}
$str = trim($str,‘,‘);
return $str;
}
function search(){
$page = (int)I(‘get.page‘,1);//页码
$keyword = I(‘get.key_word‘);//关键字
if(empty($keyword)){
$this->error();
}
$length = 16;
$result = $this->_search(‘test1‘, $keyword,$page,$length);
$ids = $this->_searchValueCombine($result[‘matches‘]);
if($result[‘total‘]>$length){//分页
$pg = new Page($result[‘total‘],$length,‘‘,"/search/$keyword?page=__PAGE__");
$purl = $pg->show();
$this->assign(‘page‘,$purl);
}
$s = D(‘test‘);
$search_result = $s->field(‘id,name‘)->where("id IN ($ids)")->select();
//高亮显示
$title = array();
foreach ($search_result as $k => $v){
$title[] = $v[‘title‘];
}
$opt = array();
$opt[‘before_match‘] = ‘<b><font style="color:red;">‘;//匹配字符之前添加的
$opt[‘after_match‘] = ‘</font></b>‘;//匹配字符后面添加的
$title = $this->sp->BuildExcerpts($title, ‘test1‘, $keyword,$opt);//spinx内置的高亮方法
foreach ($search_result as $k => $v){
$search_result[$k][‘title‘] = $title[$k];
}
$this->assign(‘result‘,$search_result);
$this->display();
}
}