伍哥点评:非常专业的一篇文章!
Sphinx搜索引擎架构与使用文档(和MySQL结合)V1.1
作者:张宴 (http://blog.s135.com) 时间:2008-11-18
目 录
一、XX网搜索引擎架构设计: 1、搜索引擎架构图(基于PHP+MySQL+Sphinx): 2、搜索引擎架构设计思路: ⑴、调用方式最简化: ⑵、创建索引、查询速度快: ⑶、按服务类型进行分离: ⑷、“主索引+增量索引”更新方式: ⑸、“Ext3文件系统+tmpfs内存文件系统”相结合: ⑹、中文分词词库:二、MySQL+Sphinx+SphinxSE安装步骤:
3、编译安装MySQL 5.1.26-rc、Sphinx、SphinxSE存储引擎 5、创建MySQL配置文件(以线上配置文件为准) ⑴、创建配置文件/mysql/3306/my.cnf(以db11的3306端口为例) ⑵、创建配置文件/mysql/3406/my.cnf(以db11的3406端口为例) 6、制作一份MySQL Slave供搜索引擎使用 7、创建快捷启动、停止、重启、杀死MySQL进程的脚本(以db11的3306端口为例)三、Sphinx配置:
1、生成Sphinx中文分词词库 ⑴、词典的构造 ⑵、词典文件格式 ⑶、XX网搜索引擎的中文分词词库 2、创建Sphinx主索引文件、增量索引文件存放目录 4、初始化sphinx.conf中配置的全部索引 5、创建两个shell脚本,一个用来创建主索引、一个用来创建增量索引。 ⑴、主索引更新脚本 ①、创建脚本build_main_index.sh: ②、赋予主索引更新脚本可执行权限: ③、每天凌晨定时重建主索引: ⑵、增量索引更新脚本 ①、创建脚本build_delta_index.sh: ②、赋予增量索引更新脚本可执行权限: ③、每3分钟自动重建一次搜索引擎的增量索引: 6、启动Sphinx守护进程(searchd) 7、配置服务器开机启动时需要自动执行的命令(以db11为例) 8、创建Sphinx存储引擎表: ⑴、设置/etc/hosts ⑵、登录运行在3306端口的MySQL服务器(提供“搜索查询服务”): ⑶、创建数据库“Sphinx”和相对应的Sphinx表(SQL语句): 示例SQL:四、如何通过SQL语句调用搜索引擎:
1、搜索应用实例 ⑴、XX网北京出租房搜索 ⑵、XX网北京小区搜索 ⑶、在指定字段中搜索(例如在字段“title”中搜索关键字“中关村”) 2、SphinxSE存储引擎及SQL语法详细说明一、XX网搜索引擎架构设计:
1、搜索引擎架构图(基于PHP+MySQL+Sphinx): 注:目前有两台搜索数据库,db9(192.168.113.209)(MySQL 3306端口用于搜索查询、3406端口用于建索引)和db11(192.168.113.211)(MySQL 3306、3307端口用于搜索查询,3406端口用于建索引),dbsearch为NetScaler虚拟IP 192.168.113.163(做db9的3306,db11的3306、3307负载均衡)的hosts。2、搜索引擎架构设计思路:
⑴、调用方式最简化: 尽量方便前端Web工程师,只需要一条简单的SQL语句“SELECT … FROM … JOIN … ON (…=…) WHERE query=’…’;”即可实现高效搜索。 ⑵、创建索引、查询速度快: ①、Sphinx Search 是由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包,在GPL与商业协议双许可协议下发行。 Sphinx的特征: ·Sphinx支持高速建立索引(可达10 MB/秒,而Lucene建立索引的速度是1.8MB/秒) ·高性能搜索(在2-4 GB的文本上搜索,平均0.1秒内获得结果) ·高扩展性(在单一CPU上,实测最高可对100GB的文本建立索引,单一索引可包含1亿条记录) ·支持分布式检索 ·支持基于短语和基于统计的复合结果排序机制 ·支持任意数量的文件字段(数值属性或全文检索属性) ·支持不同的搜索模式(“完全匹配”,“短语匹配”和“任一匹配”) ·支持作为Mysql的存储引擎②、通过国外《High Performance MySQL》专家组的测试可以看出,根据主键进行查询的类似“SELECT … FROM … WHERE id = …”的SQL语句(其中id为PRIMARY KEY),每秒钟能够处理10000次以上的查询,而普通的SELECT查询每秒只能处理几十次到几百次:
③、Sphinx不负责文本字段的存储。假设将数据库的id、date、title、body字段,用sphinx建立搜索索引。根据关键字、时 间、类别、范围等信息查询一下sphinx,sphinx只会将查询结果的ID号告诉我们。要显示title、body等信息,还需要根据此ID号去查询 MySQL数据库,或者从Memcachedb等其他的存储中取得。安装SphinxSE作为MySQL的存储引擎,将MySQL与Sphinx结合起 来,是一种便捷的方法。
创建一张Sphinx类型表,将MyISAM表的主键ID和Sphinx表的ID作一个JOIN联合查询。这样,对于MyISAM表来所,只相当于一个 WHERE id=…的主键查询,WHERE后的条件都交给Sphinx去处理,可以充分发挥两者的优势,实现高速搜索查询。⑶、按服务类型进行分离:
为了保证数据的一致性,我在配置Sphinx读取索引源的MySQL数据库时,进行了锁表。Sphinx读取索引源的过程会耗费一定时间,由于 MyISAM存储引擎的读锁和写锁是互斥的,为了避免写操作被长时间阻塞,导致数据库同步落后跟不上,我将提供“搜索查询服务”的和提供“索引源服务”的 MySQL数据库进行了分开。监听3306端口的MySQL提供“搜索查询服务”,监听3406端口的MySQL提供“索引源服务”。⑷、“主索引+增量索引”更新方式:
XX网的特征:发帖较为频繁;刚发完的帖被用户自己编辑、修改的可能性大;新发的帖会被编辑审核(删除、标记为中介等);两天以前的老帖变动性较小。 基于这个特征,我设计了Sphinx主索引和增量索引。对于前天17:00之前的记录建立主索引,每天凌晨自动重建一次主索引;对于前天17:00之后到当前最新的记录,间隔3分钟自动重建一次增量索引。⑸、“Ext3文件系统+tmpfs内存文件系统”相结合:
为了避免每4分钟重建增量索引导致磁盘IO较重,从而引起系统负载上升,我将主索引文件创建在磁盘,增量索引文件创建在tmpfs内存文件系统“/dev /shm/”内。“/dev/shm/”内的文件全部驻留在内存中,读写速度非常快。但是,重启服务器会导致“/dev/shm/”内的文件丢失,针对这 个问题,我会在服务器开机时自动创建“/dev/shm/”内目录结构和Sphinx增量索引。⑹、中文分词词库:
XX网搜索引擎使用到的中文分词词库,为本人根据“百度早期中文分词库”+“搜狗拼音输入法细胞词库”+“XX网地标词库”+“LibMMSeg高频字库”综合处理而成。二、MySQL+Sphinx+SphinxSE安装步骤:
1、安装python支持(以下针对CentOS系统,其他Linux系统请使用相应的方法安装) yum install -y python python-devel2、编译安装LibMMSeg(LibMMSeg是为Sphinx全文搜索引擎设计的中文分词软件包,其在GPL协议下发行的中文分词法,采用Chih-Hao Tsai的MMSEG算法。LibMMSeg在本文中用来生成中文分词词库。)
wget http://www.coreseek.com/uploads/sources/mmseg-0.7.3.tar.gz tar zxvf mmseg-0.7.3.tar.gz cd mmseg-0.7.3/ ./configure make make install cd ../3、编译安装MySQL 5.1.26-rc、Sphinx、SphinxSE存储引擎
wget http://blog.s135.com/soft/linux/nginx_php/mysql/mysql-5.1.26-rc.tar.gz tar zxvf mysql-5.1.26-rc.tar.gzwget http://www.sphinxsearch.com/downloads/sphinx-0.9.8-rc2.tar.gz
wget http://www.coreseek.com/uploads/sources/sphinx-0.98rc2.zhcn-support.patch wget http://www.coreseek.com/uploads/sources/fix-crash-in-excerpts.patch tar zxvf sphinx-0.9.8-rc2.tar.gz cd sphinx-0.9.8-rc2/ patch -p1 < ../sphinx-0.98rc2.zhcn-support.patch patch -p1 < ../fix-crash-in-excerpts.patch cp -rf mysqlse ../mysql-5.1.26-rc/storage/sphinx cd ../cd mysql-5.1.26-rc/
sh BUILD/autorun.sh ./configure --with-plugins=sphinx --prefix=/usr/local/mysql-search/ --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-big-tables --with-readline --with-ssl --with-embedded-server --enable-local-infile make && make install cd ../cd sphinx-0.9.8-rc2/
CPPFLAGS=-I/usr/include/python2.4 LDFLAGS=-lpython2.4 ./configure --prefix=/usr/local/sphinx --with-mysql=/usr/local/mysql-search make make install cd ../4、创建Sphinx索引文件和MySQL数据文件存放目录(/mysql/3306/data和/mysql/3406/data)
mkdir -p /usr/local/sphinx/var/data/beijing/house/ mkdir -p /usr/local/sphinx/var/data/shanghai/house/ mkdir -p /usr/local/sphinx/var/data/guangzhou/house/ mkdir -p /usr/local/sphinx/var/data/wuhan/house/ mkdir -p /usr/local/sphinx/var/data/nanjing/house/ mkdir -p /usr/local/sphinx/var/data/tianjin/house/ mkdir -p /usr/local/sphinx/var/data/shenzhen/house/ mkdir -p /usr/local/sphinx/var/data/qita/house/mkdir -p /dev/shm/sphinx/var/data/beijing/house/
mkdir -p /dev/shm/sphinx/var/data/shanghai/house/ mkdir -p /dev/shm/sphinx/var/data/guangzhou/house/ mkdir -p /dev/shm/sphinx/var/data/wuhan/house/ mkdir -p /dev/shm/sphinx/var/data/nanjing/house/ mkdir -p /dev/shm/sphinx/var/data/tianjin/house/ mkdir -p /dev/shm/sphinx/var/data/shenzhen/house/ mkdir -p /dev/shm/sphinx/var/data/qita/house//usr/sbin/groupadd mysql
/usr/sbin/useradd -g mysql mysql chmod +w /usr/local/mysql-search chown -R mysql:mysql /usr/local/mysql-search mkdir -p /mysql/3306/data chmod +w /mysql/3306/data mkdir -p /mysql/3307/data chmod +w /mysql/3307/data mkdir -p /mysql/3406/data chmod +w /mysql/3406/data chown -R mysql:mysql /mysql #cp support-files/my-medium.cnf /mysql/3306/my.cnf #cp support-files/my-medium.cnf /mysql/3307/my.cnf #cp support-files/my-medium.cnf /mysql/3406/my.cnf5、创建MySQL配置文件(以线上配置文件为准)
⑴、创建配置文件/mysql/3306/my.cnf(以db11的3306端口为例) vi /mysql/3306/my.cnf 输入以下内容: [client] #password = your_password port = 3306 socket = /mysql/3306/mysql.sock[mysqld_safe]
datadir = /mysql/3306/data log-error = /mysql/3306/mysql_error.log pid-file = /mysql/3306/mysql.pid[mysqld]
port = 3306 socket = /mysql/3306/mysql.sock skip-locking #skip-slave-start key_buffer = 2048M max_allowed_packet = 2M table_cache = 2048 sort_buffer_size = 2M read_buffer_size = 2M read_rnd_buffer_size = 16M max_length_for_sort_data = 64 myisam_sort_buffer_size = 128M thread_cache = 8 query_cache_size = 128M # Try number of CPU's*2 for thread_concurrency thread_concurrency = 8 #skip-name-resolve max_connections = 1000 max_connect_errors = 1000 open_files_limit = 51200 ft_min_word_len = 1concurrent_insert = 2
low_priority_updates = 1 slave-skip-errors = 1032,1062,126,1114,1146,1048,1396,1030 server-id = 113306 #master-host = db1 #master-user = repl #master-password = slavepass #master-port = 3306[mysqldump]
quick max_allowed_packet = 16M[mysql]
no-auto-rehash # Remove the next comment character if you are not familiar with SQL #safe-updates[isamchk]
key_buffer = 256M sort_buffer_size = 256M read_buffer = 2M write_buffer = 2M[myisamchk]
key_buffer = 256M sort_buffer_size = 256M read_buffer = 2M write_buffer = 2M[mysqlhotcopy]
interactive-timeout⑵、创建配置文件/mysql/3406/my.cnf(以db11的3406端口为例)
vi /mysql/3406/my.cnf 输入以下内容: [client] #password = your_password port = 3406 socket = /mysql/3406/mysql.sock[mysqld_safe]
datadir = /mysql/3406/data log-error = /mysql/3406/mysql_error.log pid-file = /mysql/3406/mysql.pid[mysqld]
port = 3406 socket = /mysql/3406/mysql.sock skip-locking #skip-slave-start key_buffer = 512M max_allowed_packet = 2M table_cache = 1024 sort_buffer_size = 2M read_buffer_size = 2M read_rnd_buffer_size = 8M max_length_for_sort_data = 64 myisam_sort_buffer_size = 64M thread_cache = 8 query_cache_size = 32M # Try number of CPU's*2 for thread_concurrency thread_concurrency = 8 #skip-name-resolve max_connections = 1000 max_connect_errors = 1000 open_files_limit = 51200 ft_min_word_len = 1#low_priority_updates = 1
slave-skip-errors = 1032,1062,126,1114,1146,1048,1396,1030 server-id = 113406 #master-host = db1 #master-user = repl #master-password = slavepass #master-port = 3306[mysqldump]
quick max_allowed_packet = 16M[mysql]
no-auto-rehash # Remove the next comment character if you are not familiar with SQL #safe-updates[isamchk]
key_buffer = 256M sort_buffer_size = 256M read_buffer = 2M write_buffer = 2M[myisamchk]
key_buffer = 256M sort_buffer_size = 256M read_buffer = 2M write_buffer = 2M[mysqlhotcopy]
interactive-timeout6、制作一份MySQL Slave供搜索引擎使用
⑴、找一台MySQL从库,停止同步进程(SQL语句:stop slave;); ⑵、查看同步位置(SQL语句:show slave status\G),记录以下几项值: Master_Host: db1 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000117 Read_Master_Log_Pos: 822317949 ⑶、可以使用导出、导入SQL的方法创建供搜索引擎使用的MySQL从库。对于MyISAM表,可以直接拷贝文件(此步骤略)。 ⑷、启动搜索引擎专用MySQL数据库: ulimit -SHn 500000 /bin/sh /usr/local/mysql-search/bin/mysqld_safe --defaults-file=/mysql/3406/my.cnf & /bin/sh /usr/local/mysql-search/bin/mysqld_safe --defaults-file=/mysql/3306/my.cnf & ⑸、从命令行登录MySQL服务器(此步骤略)。 ⑹、设置同步点,并启动同步(SQL语句如下): CHANGE master TO master_host="db1", master_user="repl", master_password="slavepass", master_log_file="mysql-bin.000125", master_log_pos=111145646; START SLAVE;7、创建快捷启动、停止、重启、杀死MySQL进程的脚本(以db11的3306端口为例)
vi /mysql/3306/mysql 输入以下内容: #!/bin/shmysql_port=3306
mysql_username="root" mysql_password="i0705tsstyl"function_start_mysql()
{ printf "Starting MySQL...\n" /bin/sh /usr/local/mysql-search/bin/mysqld_safe --defaults-file=/mysql/${mysql_port}/my.cnf 2>&1 > /dev/null & }function_stop_mysql()
{ printf “Stoping MySQL…\n” /usr/local/mysql-search/bin/mysqladmin -u ${mysql_username} -p${mysql_password} -S /mysql/${mysql_port}/mysql.sock shutdown }function_restart_mysql()
{ printf “Restarting MySQL…\n” function_stop_mysql function_start_mysql }function_kill_mysql()
{ kill -9 $(ps -ef | grep ‘bin/mysqld_safe’ | grep ${mysql_port} | awk ‘{printf $2}’) kill -9 $(ps -ef | grep ‘libexec/mysqld’ | grep ${mysql_port} | awk ‘{printf $2}’) }if [ "$1" = "start" ]; then
function_start_mysql elif [ "$1" = "stop" ]; then function_stop_mysql elif [ "$1" = "restart" ]; then function_restart_mysql elif [ "$1" = "kill" ]; then function_kill_mysql else printf “Usage: /mysql/${mysql_port}/mysql {start|stop|restart|kill}\n” fi 赋予脚本可执行权限: chmod +x /mysql/3306/mysql 脚本执行方法: /mysql/3306/mysql start /mysql/3306/mysql stop /mysql/3306/mysql restart /mysql/3306/mysql kill注:用同样的方法创建另一个shell脚本“/mysql/3406/mysql”,输入以上内容,将上文中用红色标注的MySQL端口3306换成3406
三、Sphinx配置:
1、生成Sphinx中文分词词库 mmseg -u unigram.txt cp unigram.txt.uni /usr/local/sphinx/etc/uni.lib ⑴、词典的构造 mmseg -u unigram.txt 该命令执行后,将会产生一个名为unigram.txt.uni的文件,将该文件改名为uni.lib,完成词典的构造。需要注意的是,unigram.txt 必须为UTF-8编码。⑵、词典文件格式
…. 河 187 x:187 造假者 1 x:1 台北队 1 x:1 湖边 1 …… 其中,每条记录分两行。其中,第一行为词项,其格式为:[词条]\t[词频率]。需要注意的是,对于单个字后面跟这个字作单字成词的频率,这个频率需要在 大量的预先切分好的语料库中进行统计,用户增加或删除词时,一般不需要修改这个数值;对于非单字词,词频率处必须为1。第二行为占位项,LibMMSeg 的用户只需要简单的在第二行处填”x:1″即可。⑶、XX网搜索引擎的中文分词词库
XX网搜索引擎使用到的中文分词词库,为本人根据“百度早期中文分词库”+“搜狗拼音输入法细胞词库”+“XX网地标词库”+“LibMMSeg高频字库”综合处理而成。(双击打开)
2、创建Sphinx主索引文件、增量索引文件存放目录
mkdir -p /usr/local/sphinx/var/data/beijing/house/ mkdir -p /usr/local/sphinx/var/data/shanghai/house/ mkdir -p /usr/local/sphinx/var/data/guangzhou/house/ mkdir -p /usr/local/sphinx/var/data/wuhan/house/ mkdir -p /usr/local/sphinx/var/data/nanjing/house/ mkdir -p /usr/local/sphinx/var/data/tianjin/house/ mkdir -p /usr/local/sphinx/var/data/shenzhen/house/ mkdir -p /usr/local/sphinx/var/data/qita/house/mkdir -p /dev/shm/sphinx/var/data/beijing/house/
mkdir -p /dev/shm/sphinx/var/data/shanghai/house/ mkdir -p /dev/shm/sphinx/var/data/guangzhou/house/ mkdir -p /dev/shm/sphinx/var/data/wuhan/house/ mkdir -p /dev/shm/sphinx/var/data/nanjing/house/ mkdir -p /dev/shm/sphinx/var/data/tianjin/house/ mkdir -p /dev/shm/sphinx/var/data/shenzhen/house/ mkdir -p /dev/shm/sphinx/var/data/qita/house/3、创建Sphinx配置文件(以db11为例)
vi /usr/local/sphinx/etc/sphinx.conf 输入以下内容(双击打开):4、初始化sphinx.conf中配置的全部索引
/usr/local/sphinx/bin/indexer –all 如果searchd处于运行状态,则执行 /usr/local/sphinx/bin/indexer –all –rotate5、创建两个shell脚本,一个用来创建主索引、一个用来创建增量索引。
⑴、主索引更新脚本 ①、创建脚本build_main_index.sh: vi /usr/local/sphinx/bin/build_main_index.sh 输入以下内容(双击打开):②、赋予主索引更新脚本可执行权限:
chmod +x /usr/local/sphinx/bin/build_main_index.sh③、每天凌晨定时重建主索引:
crontab -e 增加以下内容: #每天凌晨4点19分重建一次搜索引擎的主索引 19 4 * * * /bin/sh /usr/local/sphinx/bin/build_main_index.sh⑵、增量索引更新脚本
①、创建脚本build_delta_index.sh: vi /usr/local/sphinx/bin/build_delta_index.sh 输入以下内容(双击打开):②、赋予增量索引更新脚本可执行权限:
chmod +x /usr/local/sphinx/bin/build_delta_index.sh③、每3分钟自动重建一次搜索引擎的增量索引:
crontab -e 增加以下内容: #每3分钟自动重建一次搜索引擎的增量索引 0-57/3 * * * * /bin/sh /usr/local/sphinx/bin/build_delta_index.sh6、启动Sphinx守护进程(searchd)
ulimit -SHn 500000 /usr/local/sphinx/bin/searchd7、配置服务器开机启动时需要自动执行的命令(以db11为例)
vi /etc/rc.local 在最末尾添加以下内容: #搜索引擎开机自动执行的命令(以下语句放在rc.local文件的最后) ulimit -SHn 500000 /bin/sh /mysql/3406/mysql start /bin/sh /mysql/3306/mysql start /bin/sh /mysql/3307/mysql start mkdir -p /dev/shm/sphinx/var/data/beijing/house/ mkdir -p /dev/shm/sphinx/var/data/shanghai/house/ mkdir -p /dev/shm/sphinx/var/data/guangzhou/house/ mkdir -p /dev/shm/sphinx/var/data/wuhan/house/ mkdir -p /dev/shm/sphinx/var/data/nanjing/house/ mkdir -p /dev/shm/sphinx/var/data/tianjin/house/ mkdir -p /dev/shm/sphinx/var/data/shenzhen/house/ mkdir -p /dev/shm/sphinx/var/data/qita/house/ #/usr/bin/nohup /bin/sh /usr/local/sphinx/bin/build_delta_index.sh 2>&1 > /dev/null & #sleep 360 /bin/sh /usr/local/sphinx/bin/build_delta_index.sh 2>&1 > /dev/null /usr/local/sphinx/bin/searchd8、创建Sphinx存储引擎表:
⑴、设置/etc/hosts vi /etc/hosts 添加以下内容: 192.168.113.209 db9 192.168.113.211 db11⑵、登录运行在3306端口的MySQL服务器(提供“搜索查询服务”):
/usr/local/mysql-search/bin/mysql -u root -p -S /mysql/3306/mysql.sock⑶、创建数据库“Sphinx”和相对应的Sphinx表(SQL语句):
示例SQL: CREATE DATABASE sphinx; USE sphinx;CREATE TABLE `beijing_house_buy_list` (
`sphinx_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, `query` VARCHAR(3072) NOT NULL, INDEX(`query`) ) ENGINE=SPHINX DEFAULT CHARSET=latin1 CONNECTION=’sphinx://127.0.0.1:3312/beijing_house_buy_list’;完整SQL(双击打开):
四、如何通过SQL语句调用搜索引擎:
1、搜索应用实例 ⑴、XX网北京出租房搜索 SELECT * FROM beijing.house_rent_list JOIN sphinx.beijing_house_rent_list ON (beijing_house_rent_list.sphinx_id=house_rent_list.post_id) WHERE query=’中关村;index=beijing_house_rent_list,beijing_house_rent_list_delta; mode=boolean;sort=time_segments:date;maxmatches=3200;offset=0;limit=3200;range=price,500,1000;filter=district_id,6;’ LIMIT 0,32; 注1:“offset=0;limit=3200;”相当于“LIMIT 0,3200” 注2:“filter=district_id,6;”相当于“WHERE district_id = 6” 注3:“range=price,500,1000;”相当于“WHERE price >= 500 AND price <= 1000”,对于类似“WHERE price >= 5000”的查询,在搜索中请指定一个比较大的数来实现,比如“range=price,5000,99999999;” 注4:filter和range的条件值不能为负数。如果MySQL字段中有负数,将其转为正整数(例如在sphinx.conf中使用SELECT agent+10 AS agent FROM,在搜索时也将该项值加上10)。⑵、XX网北京小区搜索
SELECT * FROM beijing.house_source JOIN sphinx.beijing_house_source ON (beijing_house_source.sphinx_id=house_source.id) WHERE query=’中关村;index=beijing_house_source,beijing_house_source_delta; mode=boolean;sort=time_segments:post_at;maxmatches=3200;offset=0;limit=32;’; 北京小区可用的条件post_at,agent,district_id,street_id,huxing_shi,price①、普通SQL语句
SELECT title, id, huxing_shi, huxing_ting, huxing_wei,area,price,refresh_at as time, district_id, street_id, agent, xiaoqu FROM beijing.house_source WHERE district_id =’1′ AND street_id =’9′ AND agent =’0′ AND price BETWEEN 0 AND 500000 AND huxing_shi =’2′ AND ( xiaoqu LIKE ‘%金隅丽港城%’ or xiaoqu_address LIKE ‘%金隅丽港城%’ ) ORDER BY refresh_at DESC LIMIT 128,32;②、以上SQL语句对应的Sphinx搜索SQL语句(相同颜色相对应)
SELECT title, id, huxing_shi, huxing_ting, huxing_wei,area,price,refresh_at as time, district_id, street_id, agent, xiaoqu FROM beijing.house_source JOIN sphinx.beijing_house_source ON (beijing_house_source.sphinx_id=house_source.id) WHERE query=’金隅丽港城;index=beijing_house_source,beijing_house_source_delta; mode=boolean;sort=time_segments:refresh_at;maxmatches=3200;offset=128;limit=32;filter=district_id,1;filter=street_id,9;filter=agent,0;range=price,0,500000;filter=huxing_shi,2′⑶、在指定字段中搜索(例如在字段“title”中搜索关键字“中关村”)
SELECT id, user_id, title, agent, refresh_at FROM sphinx.beijing_house_source_1 JOIN beijing.house_source_1 ON (beijing_house_source_1.sphinx_id=house_source_1.id) where query=’@title 中关村;index=beijing_house_source_1,beijing_house_source_1_delta; mode=extended; sort=attr_desc:refresh_at;maxmatches=3200;offset=0;limit=32;’;2、SphinxSE存储引擎及SQL语法详细说明
SphinxSE 是一个可以编译进MySQL 5.x 版本的MySQL 存储引擎,它利用了该版本MySQL的插件式体系结构。SphinxSE 不能用于MySQL 4.x 系列,它需要MySQL 5.0.22 或更高版本;或MySQL 5.1.12 或更高版本。尽管被称作 “存储引擎”,SphinxSE 自身其实并不存储任何数据。它其实是一个允许MySQL 服务器与searchd 交互并获取搜索结果的嵌入式客户端。所有的索引和搜索都发生在MySQL 之外。
要通过SphinxSE 搜索,您需要建立特殊的ENGINE=SPHINX 的 “搜索表”,然后使用 SELECT 语句从中检索,把全文查询放在WHERE 子句中。
让我们从一个create 语句和搜索查询的例子开始:
CREATE TABLE t1 ( id INTEGER NOT NULL, weight INTEGER NOT NULL, query VARCHAR(3072) NOT NULL, group_id INTEGER, INDEX(query) ) ENGINE=SPHINX CONNECTION=”sphinx://localhost:3312/test”;SELECT * FROM t1 WHERE query=’test it;mode=any’;
搜索表前三列的类型必须是INTEGER,INTEGER 和VARCHAR,这三列分别对应文档ID,匹配权值和搜索查询。查询列必须被索引,其他列必须无索引。列的名字会被忽略,所以可以任意命名。额外的列的类型必须是INTEGER 或TIMESPTAMP 之一。它们必须与Sphinx 结果集中提供的属性按名称绑定,即它们的名字必须与sphinx.conf 中指定的属性名一一对应。如果Sphinx搜索结果中没有某个属性名,该列的值就为NULL.
特殊的 “虚拟”属性名也可以与SphinxSE 列绑定。但特殊符号@用_sph_代替。例如,要取得 和 虚属性,列名应使用_sph_group 和_sph_count 。
可以使用字符串参数CONNECTION 来指定用这个表搜索时的默认搜索主机、端口号和索引。
如果CREATE TABLE 中没有使用连接(connection)串,那么默认使用索引名 “*”(搜索所有索引)和localhost:3312。连接串的语法如下: CONNECTION=”sphinx://HOST:PORT/INDEXNAME” 默认的连接串也可以日后改变: ALTER TABLE t1 CONNECTION=”sphinx://NEWHOST:NEWPORT/NEWINDEXNAME”;也可以在查询中覆盖全部这些选项。
如例子所示,查询文本和搜索选项都应放在WHERE 子句中对query 列的限制中(即第三列),选项之间用分号分隔,选项名与选项值用等号隔开。可以指定任意数目的选项。可用的选项如下:
query —— 查询文本
mode —— 匹配模式.必须是 “all”, “any”, “phrase”, “boolean” 或 “extended”之一,默认为 “All”
sort —— 匹配项排序模式 必须是 “relevance”, “attr_desc”, “attr_asc”, “time_segments”或“extended”之一。除了“relevance”模式,其他模式中还必须在一个冒号后附上属性名(或 “extended”模式中的排序子句)。
… WHERE query=’test;sort=attr_asc:group_id’; … WHERE query=’test;sort=extended:@weight desc, group_id asc’;offset —— 结果集中的偏移量,默认是0。
limit —— 从结果集中获取的匹配项数目,默认为20。
index —— 待搜索的索引:
… WHERE query=’test;index=test1;’; … WHERE query=’test;index=test1,test2,test3;’;minid, maxid —— 匹配文档ID的最小值和最大值
weights —— 逗号分隔的列表,指定Sphinx 全文数据字段的权值
… WHERE query=’test;weights=1,2,3;’;filter, !filter —— 逗号分隔的列表,指定一个属性名和一系列可匹配的属性值:
# only include groups 1, 5 and 19 … WHERE query=’test;filter=group_id,1,5,19;’;# exclude groups 3 and 11
… WHERE query=’test;!filter=group_id,3,11;’;range, !range —— 逗号分隔的列表,指定一个属性名和该属性可匹配的最小值和最大值:
# include groups from 3 to 7, inclusive … WHERE query=’test;range=group_id,3,7;’;# exclude groups from 5 to 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;groupsort= desc;’;indexweights —— 逗号分隔的列表,指定一系列索引名和搜索时这些索引对应的权值
… WHERE query=’test;indexweights=idx_exact,2,idx_stemmed,1;’;非常重要的注意事项:让Sphinx 来对结果集执行排序、过滤和切片(slice)要比提高大匹配项数量然后在MySQL 端用WHERE、ORDER BY 和LIMIT 子句完成对应的功能来得高效得多。这有两方面的原因。首先,Sphinx 对这些操作做了一些优化,比MySQL 效率更高一些。其次,searchd 可以打包更少的数据,SphinxSE 也可以传输和解包更少的数据。
除了结果集,额外的查询信息可以用SHOW ENGINE SPHINX STATUS 语句获得:
mysql> SHOW ENGINE SPHINX STATUS; +——–+——-+————————————————-+ | Type | Name | Status | +——–+——-+————————————————-+ | SPHINX | stats | total: 25, total found: 25, time: 126, words: 2 | | SPHINX | words | sphinx:591:1256 soft:11076:15945 | +——–+——-+————————————————-+ 2 rows in set (0.00 sec)可以对SphinxSE 搜索表和其他引擎的表之间使用JOIN,以下是一个例子,例中“documents”来自example.sql:
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)关于Sphinx更多的信息请见其官方文档(英文):http://www.sphinxsearch.com/doc.html
(全文完)