Sphinx(斯芬克司)
    Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL,PostgreSQL做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。Sphinx特别为一些脚本语言设计搜索API接口,如PHP,Python,Perl,Ruby等,同时为MySQL也设计了一个存储引擎插件。
  Sphinx 单一索引最大可包含1亿条记录,在1千万条记录情况下的查询速度为0.x秒(毫秒级)。Sphinx创建索引的速度为:创建100万条记录的索引只需 3~4分钟,创建1000万条记录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒。

下载安装包:
然后解压

[root@localhost src]# tar -zxf sphinx-2.0.6-release.tar.gz
[root@localhost src]# cd sphinx-2.0.6-release
[root@localhost sphinx-2.0.6-release]#./configure --prefix=/usr/local/sphinx --with-mysql=/usr/local/mysql/ --with-iconv
[root@localhost sphinx-2.0.6-release]# make && make install
#在64位系统中,后面还应该加 --enable-id64

然后,我们进入mysql把sphinx带的模板测试库导入mysql

[root@localhost sphinx-2.0.6-release]# mysql
mysql> use test
mysql> source /usr/local/sphinx/etc/example.sql;
mysql> quit

修该sphinx配置文件:

[root@localhost sphinx-2.0.6-release]# cd /usr/local/sphinx/etc/
[root@localhost etc]# cp sphinx.conf.dist sphinx.conf
[root@localhost etc]# vim sphinx.conf
sql_host = localhost
sql_user = root
sql_pass = root
sql_db = test
sql_port = 3306

然后保存退出

[root@localhost etc]# /usr/local/sphinx/bin/indexer --all

    这个命令是建立索引,当然数据基础是刚刚导入的example.sql的数据,如果这里出错,最大的可能是你的sphinx.conf中的数据库配置错了,你需要回去检查并修正。但是,还有可能出现sphinx必须的库文件无法找到,例如出现以下两种错误: 

/usr/local/sphinx/bin/indexer: error while loading shared libraries: libmysqlclient.so.15: cannot open shared
object file: No such file or directory
/usr/local/sphinx/bin/indexer: error while loading shared libraries: libiconv.so.2: cannot open shared object file:
No such file or directory

    这主要是因为你安装了一些库后,没有能够配置相应的环境变量。你可以通过建立连接的方式修正这个问题,运行如下命令: 

[root@localhost etc]# ln -s /usr/local/mysql/lib/libmysqlclient.so.15 /usr/lib/libmysqlclient.so.15
[root@localhost etc]# ln -s /usr/local/lib/libiconv.so.2 /usr/lib/libiconv.so.2 

    这里我假设你相应的软件包安装在/usr/local/xxx 目录下,如果你不是安装在相应目录下,你就需要使用你自己的路径。如果你没有安装libiconv软件包,则需要安装下,这个安装比较简单,就不多说了。
    如果还出现类似错误,照上面的方法修正。 

[root@localhost etc]# /usr/local/sphinx/bin/indexer --all --config /usr/local/sphinx/etc/sphinx.conf --rotate
[root@localhost etc]# /usr/local/sphinx/bin/search test

Sphinx 2.0.1-id64-beta (r2792)
Copyright (c) 2001-2011, Andrew Aksyonoff
Copyright (c) 2008-2011, Sphinx Technologies Inc (http://sphinxsearch.com)

using config file '/usr/local/sphinx/etc/sphinx.conf'...
index 'test1': query 'test ': returned 3 matches of 3 total in 0.015 sec
displaying matches:
1. document=1, weight=2421, group_id=1, date_added=Mon Nov 19 16:57:01 2012
                id=1
                group_id=1
                group_id2=5
                date_added=2013-01-07 14:12:18
                title=test one
                content=this is my test document number one. also checking search within phrases.
2. document=2, weight=2421, group_id=1, date_added=Mon Nov 19 16:57:01 2012
                id=2
                group_id=1
                group_id2=6
                date_added=2013-01-07 14:12:18
                title=test two
                content=this is my test document number two
3. document=4, weight=1442, group_id=2, date_added=Mon Nov 19 16:57:01 2012
                id=4
                group_id=2
                group_id2=8
                date_added=2013-01-07 14:12:18
                title=doc number four
                content=this is to test groups

words:
1. 'test': 3 documents, 5 hits

index 'test1stemmed': query 'test ': returned 3 matches of 3 total in 0.000 sec

displaying matches:
1. document=1, weight=2421, group_id=1, date_added=Mon Nov 19 16:57:01 2012
                id=1
                group_id=1
                group_id2=5
                date_added=2013-01-07 14:12:18
                title=test one
                content=this is my test document number one. also checking search within phrases.
2. document=2, weight=2421, group_id=1, date_added=Mon Nov 19 16:57:01 2012
                id=2
                group_id=1
                group_id2=6
                date_added=2013-01-07 14:12:18
                title=test two
                content=this is my test document number two
3. document=4, weight=1442, group_id=2, date_added=Mon Nov 19 16:57:01 2012
                id=4
                group_id=2
                group_id2=8
                date_added=2013-01-07 14:12:18
                title=doc number four
                content=this is to test groups

words:
1. 'test': 3 documents, 5 hits

index 'rt': search error: /usr/local/sphinx/var/data/rt.sph is invalid header file (too old index version?).

 上面的命令是搜索测试,测试的关键词就是 test 了,如果成功的话,你应该看到搜到的结果,出现字串“index 'test1': query 

'test ': returned 3 matches of 3 total in 0.000 sec”,后面跟的是结果表示成功了。  

[root@localhost etc]# /usr/local/sphinx/bin/searchd
[root@localhost etc]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1077/php-fpm
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 1416/rsync
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1373/mysqld
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1418/nginx
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1094/sshd
tcp 0 0 0.0.0.0:9306 0.0.0.0:* LISTEN 3684/searchd
tcp 0 0 0.0.0.0:9312 0.0.0.0:* LISTEN 3684/searchd

tcp 0 0 0.0.0.0:10050 0.0.0.0:* LISTEN 1427/zabbix_agentd
tcp 0 0 0.0.0.0:10051 0.0.0.0:* LISTEN 1439/zabbix_server

Sphinx.conf 配置文档参数解释

其结构组成主要如下 :
Source 源名称 1{ // 指定数据源
一些配置
}
Index 索引名称 1{
Source= 源名称 1
}
Source 源名称 2{
一些配置
}
Index 索引名称 2{
Source= 源名称 2
}
Indexer{
mem_limit = 32M
}
Searchd{ // 配置 searchd 守护程序本身
}
二. Source 源名称 相关配置说明
Type= 数据库类型 (Mysql 或 SQL);
Sql_host= 数据库主机地址 ( 如果是外网 , 请确保防火墙允许链接 )
Sql_user= 数据库用户名
Sql_pass= 数据库密码
Sql_db= 数据库名称
Sql_port= 数据库端口
Sql_query_pre= 执行 SQL 前设置的编码 (SET NAMES UTF8/GBK)
#下面的语句是更新sph_counter表中的 max_doc_id。
sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(id) FROM document

Sql_query= 全文检索要显示的内容 , 据官方说法 : 尽可能不要使用 WHERE 或 GROUPBY , 将其交给 SPHINX 效率会更高 ;select 出来的字段必须包含至少一个唯一主键 , 以及全文检索的字段
Sql_query_info=
SELECT * FROM Inventory WHERE id=$id
Strip_html= 0/1 是否去掉 HTML 标签
Sql_attr_uint= 无符号整数属性 , 可以设置多个 , 设置数据库字段 , 设置哪个能显示出哪个字段数据的×××来 .
Sql_attr_float 浮点型
Sql_attr_timestamp 时间戳
Sql_attr_str2ordinal字符串型 这个属性类型(简称为字串序数)的设计是为了允许按字符串值排序,但不存储字符串本身。
三. Index 中配置说明
Source= 数据源名称
Path = 索引记录存放目录 , 注 : d:/sphinx/data/cg 这个的意思是 在 data 目录下创建一个名为 cg 的文件
min_word_len= 索引的词的最小长度 设为 1 既可以搜索单个字节搜索 , 越小 索引越精确 , 但建立索引花费的时间越长
charset_type= utf-8/gbk 设置数据编码
charset_table= 字符表和大小写转换规则 . 频繁应用于 sphinx 的分词过程
min_prefix_len = 最小前缀 (0)
min_infix_len = 最小中缀 (1)
//以下三句是关于UTF-8中文一元分词的配置
ngram_len = 对于非字母型数据的长度切 (1)
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
四. searchd 配置说明
port= sphinx 的端口 (9312)
log= 服务进程日志存放路径,一旦 sphinx 出现异常,基本上可以从这里查询有效信息
query_log= 客户端查询日志 尤为有用 它将在运行时显示每次搜索并显示结果
read_timeout= 请求超时 (5)
max_children= 同时可执行的最大 searchd 进程数 (30)
pid_file= 进程 ID 文件
max_matches= 查询结果的最大返回数
seamless_rotate= 是否支持无缝切换,做增量索引时通常需要 (0/1)
至此 spninx.conf 配置文件结束 ; 注意 : 如果有换行 必须用反斜杠 \ 链接
五. sphinx 建立所以 及监听
切换到 DOS sphinx/bin 目录下
1. 建立索引
Indexer –c sphinx.conf 索引名称 /--all (--all 参数是建立所有索引 )
完成后提示如下 :
total 535600 docs, 10707632 bytes
total 34.323 sec, 311958 bytes/sec, 15604.27 docs/sec
total 5 reads, 0.282 sec, 45592.6 kb/call avg, 56.4 msec/call avg
total 547 writes, 12.172 sec, 1017.0 kb/call avg, 22.2 msec/call avg
2. 建立完成后
可以执行 search [–c] sphinx.conf 搜索内容 (-c 参数 : 是否允许模糊搜索 )
3. 监听端口
Searchd
运行后 提示
listening on all interfaces, port=9312
accepting connections
监听成功后 既可以运行 PHP 程序 进行 搜索
PHPCODE:
require("sphinxapi.php"); // 加载类文件
$cl=new SphinxClient(); // 实例化类
$cl->SetServer('localhost',9312); // 设置服务
$search->setSearch_start(($page -1) * $pageSize);//分页
$search->setSearch_limit($pageSize * 1);
$cl->SetArrayResult(true); // 设置 显示结果集方式
$cl->SetLimits(0,10); // 同 sql 语句中的 LIMIT
$cl->SetSortMode(“mode”); // 排序模式 SPH_SORT_ATTR_DESC 和 SPH_SORT_ATTR_ASC
$result=$cl->Query('ff',[ 索引名称可选 ]); // 执行搜索,索引名称指的是下面例子中的member, member_delta
Var_dump($result); // 输出

Sphinx.conf 配置文档案例: 

source member
{
type = mysql


sql_host = localhost
sql_user = XXX
sql_pass = XXX
sql_db = XXX
sql_port = 3306

sql_query_pre = SET NAMES utf8
sql_query_pre = SET SESSION query_cache_type=OFF

sql_query = \
SELECT members.uid as uid,members.username as username FROM members where member_status =1 and uid not in \
(SELECT distinct user_id FROM `fct_faction_member` )

}

source member_delta : member
{

sql_query_pre = SET NAMES utf8
sql_query_pre = SET SESSION query_cache_type=OFF

sql_query = \
SELECT members.uid as uid,members.username as username FROM members where member_status =1 and uid not in \
(SELECT distinct user_id FROM `fct_faction_member` )
}
index member
{
source = member
path = /data0/coreseek/var/data/member_test
docinfo = extern
charset_dictpath = /usr/local/webserver/mmseg/etc/
mlock = 0
morphology = none
min_word_len = 1
html_strip = 0
charset_type = zh_cn.utf-8
ngram_len = 0

}


index member_delta
{
source = member_delta
path = /data0/coreseek/var/data/member_delta_test
docinfo = extern
charset_dictpath = /usr/local/webserver/mmseg/etc/
mlock = 0
morphology = none
min_word_len = 1
html_strip = 0
charset_type = zh_cn.utf-8
ngram_len = 0
}
sphinx的原理是每天定时的去处理一些大的sql语句,将查询出来的结果放在文件中,在你每次去搜索时是根据条件在文件的基础上去搜索的,这样节省时间!
#注意:member_delta 中的sql_query_pre的个数需和member对应,否则可能搜索不出相应的结果
例子:
source main
{
type = mysql #数据库类型
sql_host = 127.0.0.1 #数据库ip
sql_user = root #数据库用户名
sql_pass = #数据库密码
sql_db = ssc #数据库名
sql_port = 3306 # 数据库端口

sql_query_pre = SET NAMES utf8
sql_query_pre = REPLACE INTO sphinx_counter SELECT 1, MAX(searchid) FROM search_data

sql_query = SELECT searchid, adddate, siteid, typeid, contentid, data,thumb FROM search_data \
WHERE searchid>=$start AND searchid<=$end
sql_query_range = SELECT 1,max_doc_id FROM sphinx_counter WHERE counter_id=1
sql_range_step = 5000

#字符串属性设置、需要过滤、排序的时候用到
sql_attr_uint = typeid
sql_attr_uint = siteid
sql_attr_uint = contentid
sql_attr_timestamp = adddate
sql_attr_uint = thumb
sql_query_info = SELECT * FROM search_data WHERE searchid=$id
}

source delta
{
type = mysql #数据库类型
sql_host = 127.0.0.1 #数据库ip
sql_user = root #数据库用户名
sql_pass = cespc123 #数据库密码
sql_db = ssc #数据库名
sql_port = 3306 # 数据库端口

sql_query_pre = SET NAMES utf8
sql_query = SELECT searchid, adddate, siteid, typeid, contentid, data,thumb FROM search_data \
WHERE searchid >( SELECT max_doc_id FROM sphinx_counter WHERE counter_id=1 )
sql_query_post = REPLACE INTO sphinx_counter SELECT 1, MAX(searchid) FROM search_data
#字符串属性设置、需要过滤、排序的时候用到
sql_attr_uint = typeid
sql_attr_uint = siteid
sql_attr_uint = contentid
sql_attr_timestamp = adddate
sql_attr_uint = thumb
sql_query_info = SELECT * FROM search_data WHERE searchid=$id
}

#主索引
index main
{
source = main
# 放索引的目录
path = /usr/local/sphinx/var/data/ssc
# 编码
charset_type = utf-8
# 指定utf-8的编码表
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
# 简单分词,只支持0和1,如果要搜索中文,请指定为1
ngram_len = 1
# 需要分词的字符,如果要搜索中文,去掉前面的注释
ngram_chars = U+3000..U+2FA1F
}

#增量索引
index delta
{
source = delta
path = /usr/local/sphinx/var/data/delta
# 编码
charset_type = utf-8
# 指定utf-8的编码表
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
# 简单分词,只支持0和1,如果要搜索中文,请指定为1
ngram_len = 1
# 需要分词的字符,如果要搜索中文,去掉前面的注释
ngram_chars = U+3000..U+2FA1F
}

indexer
{
mem_limit = 128M
}

searchd
{
port = 9312
log = /usr/local/sphinx/var/log/searchd.log
query_log = /usr/local/sphinx/var/log/query.log
read_timeout = 5
max_children = 30
pid_file = /usr/local/sphinx/var/log/searchd.pid
max_matches = 2000
seamless_rotate = 0
preopen_indexes = 0
unlink_old = 1
compat_sphinxql_magics = 0
}

其实单纯的sphinx对中文支持不是很好,推荐使用sphinx-for-chinese

一些郁闷的错误处理

[root@localhost bin]# ./search test1 -c ../etc/sphinx.conf                                        
sphinx-for-chinese 2.1.0-dev (r3361)
Copyright (c) 2008-2012, sphinx-search.com

using config file '../etc/sphinx.conf'...
index 'test1': search error: .

解决办法:如下标红的命令后面加参数就可以,-i是指的默认索引

[root@localhost bin]# ./search -i test1 -q 分享身边的精彩 -c ../etc/sphinx.conf
sphinx-for-chinese 2.1.0-dev (r3361)
Copyright (c) 2008-2012, sphinx-search.com

using config file '../etc/sphinx.conf'...
index 'test1': query '分享身边的精彩 ': returned 0 matches of 0 total in 0.000 sec

words:
1. '分享': 0 documents, 0 hits
2. '身边': 0 documents, 0 hits
3. '的': 0 documents, 0 hits
4. '精彩': 0 documents, 0 hits