解决Nginx + PHP(FastCGI)遇到的502 Bad Gateway错误[原创]
[ 2008-7-30 07:09 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2008.07.30 转载请注明原文链接:http://blog.zyan.cc/read.php/361/]
昨日,有朋友问我,他将Web服务器换成Nginx 0.6.31 + PHP 4.4.7(FastCGI)后,有时候访问会出现“502 Bad Gateway”错误,如何解决。
我让按照以下两个步骤去解决,最后在第2步中将FastCGI的timeout时间增加为300,问题解决:
PS:比较羡慕迅雷的Web服务器,16G内存。
1、查看当前的PHP FastCGI进程数是否够用:
如果实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么,说明“FastCGI进程数”不够用,需要增大。
2、部分PHP程序的执行时间超过了Nginx的等待时间,可以适当增加nginx.conf配置文件中FastCGI的timeout时间,例如:
昨日,有朋友问我,他将Web服务器换成Nginx 0.6.31 + PHP 4.4.7(FastCGI)后,有时候访问会出现“502 Bad Gateway”错误,如何解决。
我让按照以下两个步骤去解决,最后在第2步中将FastCGI的timeout时间增加为300,问题解决:
PS:比较羡慕迅雷的Web服务器,16G内存。
1、查看当前的PHP FastCGI进程数是否够用:
netstat -anpo | grep "php-cgi" | wc -l
如果实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么,说明“FastCGI进程数”不够用,需要增大。
2、部分PHP程序的执行时间超过了Nginx的等待时间,可以适当增加nginx.conf配置文件中FastCGI的timeout时间,例如:
......
http
{
......
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
......
}
......
http
{
......
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
......
}
......
基于Sphinx+MySQL的千万级数据全文检索(搜索引擎)架构设计[原创]
[ 2008-7-27 22:29 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2008.07.27 转载请注明原文链接:http://blog.zyan.cc/post/360/]
前言:本文阐述的是一款经过生产环境检验的千万级数据全文检索(搜索引擎)架构。本文只列出前几章的内容节选,不提供全文内容。
在DELL PowerEdge 6850服务器(四颗64 位Inter Xeon MP 7110N处理器 / 8GB内存)、RedHat AS4 Linux操作系统、MySQL 5.1.26、MyISAM存储引擎、key_buffer=1024M环境下实测,单表1000万条记录的数据量(这张MySQL表拥有int、datetime、varchar、text等类型的10多个字段,只有主键,无其它索引),用主键(PRIMARY KEY)作为WHERE条件进行SQL查询,速度非常之快,只耗费0.01秒。
出自俄罗斯的开源全文搜索引擎软件Sphinx,单一索引最大可包含1亿条记录,在1千万条记录情况下的查询速度为0.x秒(毫秒级)。Sphinx创建索引的速度为:创建100万条记录的索引只需3~4分钟,创建1000万条记录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒。
基于以上几点,我设计出了这套搜索引擎架构。在生产环境运行了一周,效果非常不错。有时间我会专为配合Sphinx搜索引擎,开发一个逻辑简单、速度快、占用内存低、非表锁的MySQL存储引擎插件,用来代替MyISAM引擎,以解决MyISAM存储引擎在频繁更新操作时的锁表延迟问题。另外,分布式搜索技术上已无任何问题。
一、搜索引擎架构设计:
1、搜索引擎架构图:
2、搜索引擎架构设计思路:
(1)、调用方式最简化:
尽量方便前端Web工程师,只需要一条简单的SQL语句“SELECT ... FROM myisam_table JOIN sphinx_table ON (sphinx_table.sphinx_id=myisam_table.id) WHERE query='...';”即可实现高效搜索。
(2)、创建索引、查询速度快:
①、Sphinx Search 是由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包,在GPL与商业协议双许可协议下发行。
Sphinx的特征:
•Sphinx支持高速建立索引(可达10MB/秒,而Lucene建立索引的速度是1.8MB/秒)
•高性能搜索(在2-4 GB的文本上搜索,平均0.1秒内获得结果)
•高扩展性(实测最高可对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去处理,可以充分发挥两者的优势,实现高速搜索查询。
(3)、按服务类型进行分离:
为了保证数据的一致性,我在配置Sphinx读取索引源的MySQL数据库时,进行了锁表。Sphinx读取索引源的过程会耗费一定时间,由于MyISAM存储引擎的读锁和写锁是互斥的,为了避免写操作被长时间阻塞,导致数据库同步落后跟不上,我将提供“搜索查询服务”的和提供“索引源服务”的MySQL数据库进行了分开。监听3306端口的MySQL提供“搜索查询服务”,监听3406端口的MySQL提供“索引源服务”。
(4)、“主索引+增量索引”更新方式:
一般网站的特征:信息发布较为频繁;刚发布完的信息被编辑、修改的可能性大;两天以前的老帖变动性较小。
基于这个特征,我设计了Sphinx主索引和增量索引。对于前天17:00之前的记录建立主索引,每天凌晨自动重建一次主索引;对于前天17:00之后到当前最新的记录,间隔3分钟自动重建一次增量索引。
(5)、“Ext3文件系统+tmpfs内存文件系统”相结合:
为了避免每3分钟重建增量索引导致磁盘IO较重,从而引起系统负载上升,我将主索引文件创建在磁盘,增量索引文件创建在tmpfs内存文件系统“/dev/shm/”内。“/dev/shm/”内的文件全部驻留在内存中,读写速度非常快。但是,重启服务器会导致“/dev/shm/”内的文件丢失,针对这个问题,我会在服务器开机时自动创建“/dev/shm/”内目录结构和Sphinx增量索引。
(6)、中文分词词库:
我根据“自整理的中文分词库”+“搜狗拼音输入法细胞词库”+“LibMMSeg高频字库”+... 综合整理成一份中文分词词库,出于某些考虑暂不提供。你可以使用LibMMSeg自带的中文分词词库。
前言:本文阐述的是一款经过生产环境检验的千万级数据全文检索(搜索引擎)架构。本文只列出前几章的内容节选,不提供全文内容。
在DELL PowerEdge 6850服务器(四颗64 位Inter Xeon MP 7110N处理器 / 8GB内存)、RedHat AS4 Linux操作系统、MySQL 5.1.26、MyISAM存储引擎、key_buffer=1024M环境下实测,单表1000万条记录的数据量(这张MySQL表拥有int、datetime、varchar、text等类型的10多个字段,只有主键,无其它索引),用主键(PRIMARY KEY)作为WHERE条件进行SQL查询,速度非常之快,只耗费0.01秒。
出自俄罗斯的开源全文搜索引擎软件Sphinx,单一索引最大可包含1亿条记录,在1千万条记录情况下的查询速度为0.x秒(毫秒级)。Sphinx创建索引的速度为:创建100万条记录的索引只需3~4分钟,创建1000万条记录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒。
基于以上几点,我设计出了这套搜索引擎架构。在生产环境运行了一周,效果非常不错。有时间我会专为配合Sphinx搜索引擎,开发一个逻辑简单、速度快、占用内存低、非表锁的MySQL存储引擎插件,用来代替MyISAM引擎,以解决MyISAM存储引擎在频繁更新操作时的锁表延迟问题。另外,分布式搜索技术上已无任何问题。
一、搜索引擎架构设计:
1、搜索引擎架构图:
2、搜索引擎架构设计思路:
(1)、调用方式最简化:
尽量方便前端Web工程师,只需要一条简单的SQL语句“SELECT ... FROM myisam_table JOIN sphinx_table ON (sphinx_table.sphinx_id=myisam_table.id) WHERE query='...';”即可实现高效搜索。
(2)、创建索引、查询速度快:
①、Sphinx Search 是由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包,在GPL与商业协议双许可协议下发行。
Sphinx的特征:
•Sphinx支持高速建立索引(可达10MB/秒,而Lucene建立索引的速度是1.8MB/秒)
•高性能搜索(在2-4 GB的文本上搜索,平均0.1秒内获得结果)
•高扩展性(实测最高可对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去处理,可以充分发挥两者的优势,实现高速搜索查询。
(3)、按服务类型进行分离:
为了保证数据的一致性,我在配置Sphinx读取索引源的MySQL数据库时,进行了锁表。Sphinx读取索引源的过程会耗费一定时间,由于MyISAM存储引擎的读锁和写锁是互斥的,为了避免写操作被长时间阻塞,导致数据库同步落后跟不上,我将提供“搜索查询服务”的和提供“索引源服务”的MySQL数据库进行了分开。监听3306端口的MySQL提供“搜索查询服务”,监听3406端口的MySQL提供“索引源服务”。
(4)、“主索引+增量索引”更新方式:
一般网站的特征:信息发布较为频繁;刚发布完的信息被编辑、修改的可能性大;两天以前的老帖变动性较小。
基于这个特征,我设计了Sphinx主索引和增量索引。对于前天17:00之前的记录建立主索引,每天凌晨自动重建一次主索引;对于前天17:00之后到当前最新的记录,间隔3分钟自动重建一次增量索引。
(5)、“Ext3文件系统+tmpfs内存文件系统”相结合:
为了避免每3分钟重建增量索引导致磁盘IO较重,从而引起系统负载上升,我将主索引文件创建在磁盘,增量索引文件创建在tmpfs内存文件系统“/dev/shm/”内。“/dev/shm/”内的文件全部驻留在内存中,读写速度非常快。但是,重启服务器会导致“/dev/shm/”内的文件丢失,针对这个问题,我会在服务器开机时自动创建“/dev/shm/”内目录结构和Sphinx增量索引。
(6)、中文分词词库:
我根据“自整理的中文分词库”+“搜狗拼音输入法细胞词库”+“LibMMSeg高频字库”+... 综合整理成一份中文分词词库,出于某些考虑暂不提供。你可以使用LibMMSeg自带的中文分词词库。
快捷启动、停止、重启、杀死指定端口MySQL进程的脚本[原创]
[ 2008-7-24 08:37 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2008.07.24 转载请注明原文链接:http://blog.zyan.cc/post/359/]
写了一个shell脚本,可以在同一台Linux服务器的不同端口,运行多个MySQL服务的情况下,快捷启动、停止、重启、杀死指定端口的MySQL进程。
输入以下内容(因各服务器的MySQL配置不同,可能需要修改的部分已用红色标注):
赋予脚本可执行权限:
脚本执行方法:
写了一个shell脚本,可以在同一台Linux服务器的不同端口,运行多个MySQL服务的情况下,快捷启动、停止、重启、杀死指定端口的MySQL进程。
vi /usr/local/bin/mysql.sh
输入以下内容(因各服务器的MySQL配置不同,可能需要修改的部分已用红色标注):
#!/bin/sh
mysql_port=$2
mysql_username="root"
mysql_password="123456"
function_start_mysql()
{
printf "Starting MySQL...\n"
/bin/sh /usr/local/mysql/bin/mysqld_safe --defaults-file=/mysql/${mysql_port}/my.cnf 2>&1 > /dev/null &
}
function_stop_mysql()
{
printf "Stoping MySQL...\n"
/usr/local/mysql/bin/mysqladmin -u ${mysql_username} -p${mysql_password} -h localhost -P ${mysql_port} 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.sh {start|stop|restart|kill}\n"
fi
mysql_port=$2
mysql_username="root"
mysql_password="123456"
function_start_mysql()
{
printf "Starting MySQL...\n"
/bin/sh /usr/local/mysql/bin/mysqld_safe --defaults-file=/mysql/${mysql_port}/my.cnf 2>&1 > /dev/null &
}
function_stop_mysql()
{
printf "Stoping MySQL...\n"
/usr/local/mysql/bin/mysqladmin -u ${mysql_username} -p${mysql_password} -h localhost -P ${mysql_port} 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.sh {start|stop|restart|kill}\n"
fi
赋予脚本可执行权限:
chmod +x /usr/local/bin/mysql.sh
脚本执行方法:
mysql.sh start 3306
mysql.sh stop 3306
mysql.sh restart 3306
mysql.sh kill 3306
mysql.sh stop 3306
mysql.sh restart 3306
mysql.sh kill 3306
sourceforge.net被GFW挡住后的访问方法
[ 2008-7-23 08:32 | by 张宴 ]
1、通过镜像站
http://mirror.optus.net/sourceforge/
http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/
2、通过Google代理(虽然是针对手机上网的,但是PC上的浏览器也可以访问)
http://www.google.com/gwt/n
http://www.google.com/gwt/n?u=http%3A%2F%2Fsourceforge.net
3、找国外代理服务器
4、名称以F开头的某软件(不便公布)
http://mirror.optus.net/sourceforge/
http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/
2、通过Google代理(虽然是针对手机上网的,但是PC上的浏览器也可以访问)
http://www.google.com/gwt/n
http://www.google.com/gwt/n?u=http%3A%2F%2Fsourceforge.net
3、找国外代理服务器
4、名称以F开头的某软件(不便公布)
MySQL Memcache_engine的安装与使用[原创]
[ 2008-7-20 13:58 | by 张宴 ]
[文章作者:张宴 本文版本:v1.1 最后修改:2008.09.09 转载请注明原文链接:http://blog.zyan.cc/post/357/]
鉴于国内外还没有人撰写如何安装Memcache_engine的文章,于是,我根据自己的编译安装步骤,写下此文。
Memcache_engine是一个MySQL 5.1数据库的存储引擎,它能够让用户通过标准的SQL语句(SELECT/UPDATE/INSERTE/DELETE)访问Memcached(还支持新浪的Memcachedb、dbcached)中存放的数据。
限制:
1、Memcache表必须有主键。
2、只能使用主键去查询,即只能使用SELECT ... FROM ... WHERE id = ... 方式去查询。
3、不支持自增ID。
安装与使用:
1、编译安装memcache_engine的步骤:
注意:红色标记部分为MySQL 5.1.22以上版本的源码路径。
鉴于国内外还没有人撰写如何安装Memcache_engine的文章,于是,我根据自己的编译安装步骤,写下此文。
Memcache_engine是一个MySQL 5.1数据库的存储引擎,它能够让用户通过标准的SQL语句(SELECT/UPDATE/INSERTE/DELETE)访问Memcached(还支持新浪的Memcachedb、dbcached)中存放的数据。
限制:
1、Memcache表必须有主键。
2、只能使用主键去查询,即只能使用SELECT ... FROM ... WHERE id = ... 方式去查询。
3、不支持自增ID。
安装与使用:
1、编译安装memcache_engine的步骤:
cd /tmp
wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.26-rc.tar.gz/from/http://mirror.x10.com/mirror/mysql/
tar zxvf mysql-5.1.26-rc.tar.gz
#安装、配置MySQL的步骤省略,注意不要以静态方式编译安装。
wget http://download.tangent.org/libmemcached-0.23.tar.gz
tar zxvf libmemcached-0.23.tar.gz
cd libmemcached-0.23/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://xmlsoft.org/sources/libxml2-2.6.32.tar.gz
tar zxvf libxml2-2.6.32.tar.gz
cd libxml2-2.6.32/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://download.tangent.org/libxmlrow-0.2.tar.gz
tar zxvf libxmlrow-0.2.tar.gz
cd libxmlrow-0.2/
export PKG_CONFIG_PATH=/usr/local/memcache_engine/lib/pkgconfig/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://download.tangent.org/memcache_engine-0.7.tar.gz
tar zxvf memcache_engine-0.7.tar.gz
cd memcache_engine-0.7/
sed -i "s#uint16_t#uint32_t#g" ./src/ha_memcache.cc
export PKG_CONFIG_PATH=/usr/local/memcache_engine/lib/pkgconfig/
./configure --prefix=/usr/local/memcache_engine --with-mysql=/tmp/mysql-5.1.26-rc
make
make install
cd ../
wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.26-rc.tar.gz/from/http://mirror.x10.com/mirror/mysql/
tar zxvf mysql-5.1.26-rc.tar.gz
#安装、配置MySQL的步骤省略,注意不要以静态方式编译安装。
wget http://download.tangent.org/libmemcached-0.23.tar.gz
tar zxvf libmemcached-0.23.tar.gz
cd libmemcached-0.23/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://xmlsoft.org/sources/libxml2-2.6.32.tar.gz
tar zxvf libxml2-2.6.32.tar.gz
cd libxml2-2.6.32/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://download.tangent.org/libxmlrow-0.2.tar.gz
tar zxvf libxmlrow-0.2.tar.gz
cd libxmlrow-0.2/
export PKG_CONFIG_PATH=/usr/local/memcache_engine/lib/pkgconfig/
./configure --prefix=/usr/local/memcache_engine
make
make install
cd ../
wget http://download.tangent.org/memcache_engine-0.7.tar.gz
tar zxvf memcache_engine-0.7.tar.gz
cd memcache_engine-0.7/
sed -i "s#uint16_t#uint32_t#g" ./src/ha_memcache.cc
export PKG_CONFIG_PATH=/usr/local/memcache_engine/lib/pkgconfig/
./configure --prefix=/usr/local/memcache_engine --with-mysql=/tmp/mysql-5.1.26-rc
make
make install
cd ../
注意:红色标记部分为MySQL 5.1.22以上版本的源码路径。
MySQL中文全文索引插件 mysqlcft 1.0.0 安装使用文档[原创]
[ 2008-7-1 22:57 | by 张宴 ]
[文章+程序 作者:张宴 本文版本:v1.0 最后修改:2008.07.01 转载请注明原文链接:http://blog.zyan.cc/post/356/]
MySQL在高并发连接、数据库记录数较多的情况下,SELECT ... WHERE ... LIKE '%...%'的全文搜索方式不仅效率差,而且以通配符%和_开头作查询时,使用不到索引,需要全表扫描,对数据库的压力也很大。MySQL针对这一问题提供了一种全文索引解决方案,这不仅仅提高了性能和效率(因为MySQL对这些字段做了索引来优化搜索),而且实现了更高质量的搜索。但是,至今为止,MySQL对中文全文索引无法正确支持。
中文与西方文字如英文的一个重要区别在于,西方文字以单词为单位,单词与单词之间以空格分隔。而中文以字为单位,词由一个或多个字组成,词与词之间没有空格分隔。当试图在一个含有中文字符的字段中使用全文搜索时,不会得到正确的结果,原因在于中文中没有像英文空格那样对词定界,不能以空格作为分割,对中文词语进行索引。
引用《MySQL 5.1参考手册》中的一段话:
国内已有的MySQL中文全文索引解决方案有两个:一是海量科技的MySQL5.0.37--LinuxX86-Chinese+,二是hightman开发的mysql-5.1.11-ft-hightman,两者都是基于中文分词技术,对中文语句进行拆分。但是,两者都有弊端,一是不支持64位操作系统;二是对修改了MySQL源码,只支持某一MySQL版本,不便于跟进新版本;三是词库不能做到很大很全,对于专业性质较强的数据库内容(例如搜索“颐和园路东口”、“清华东路西口”等公交站点,“莱镇香格里”、“碧海云天”等楼盘名称),基于中文分词的全文索引经常搜索不出来任何内容,即使添加分词词库,也不会很全面。
由于精准全文查询的需要,我借鉴了二元交叉切分算法的思想,用自创的“三字节交叉切分算法”,写出了这款“MySQL中文全文索引插件──mysqlcft 1.0.0”。由于开发时间仓促,难免存在未发现的问题,这将后续的版本中不断完善。对于百万条记录的MySQL表进行全文检索,mysqlcft已经够用。
Mysqlcft 网址:http://code.google.com/p/mysqlcft/
Mysqlcft 作者:张宴
一、MySQL中文全文索引插件mysqlcft的特点:
1、优点:
①、精准度很高:采用自创的“三字节交叉切分算法”,对中文语句进行分割,无中文分词词库,搜索精准度远比中文分词算法高,能达到LIKE '%...%"的准确率。
②、查询速度快:查询速度比LIKE '%...%"搜索快3~50倍,文章末尾有测试结果;
③、标准插件式:以MySQL 5.1全文索引的标准插件形式开发,不修改MySQL源代码,不影响MySQL的其他功能,可快速跟进MySQL新版本;
④、支持版本多:支持所有的MySQL 5.1 Release Candidate版本,即MySQL 5.1.22 RC~最新的MySQL 5.1.25 RC;
⑤、支持字符集:支持包括GBK、GB2312、UTF-8、Latin1、BIG5在内的MySQL字符集(其他字符集没有测试过);
⑥、系统兼容好:具有i386和x86_64两个版本,支持32位(i386)和64位(x86_64)CPU及Linux系统;
⑦、适合分布式:非常适合MySQL Slave分布式系统架构,无词库维护成本,不存在词库同步问题。
2、缺点:
①、mysqlcft中文全文索引只适用于MyISAM表,因为MySQL只支持对MyISAM表建立FULLTEXT索引;
②、MySQL不能静态编译安装,否则无法安装mysqlcft插件;
③、基于“三字节交叉切分算法”的索引文件会比海量、ft-hightman等基于“中文分词算法”的索引文件稍大,但不是大很多。根据我的测试,mysqlcft全文索引的.MYI索引文件是.MYD数据文件的2~5倍。
二、mysqlcft的核心思想──“三字节交叉切分算法”
注:本文以0~7数字序号代表“英文”、“数字”和“半个汉字”,以便说明。
1、按三字节对中文语句进行切分,建立全文索引:
例如:“全文索引”或“1台x光机”四个字会被交叉分拆为6份,建立反向索引:
012 123 234 345 456 567
2、按三字节对搜索的关键字进行切分,在全文索引中找出对应信息:
例①:搜索关键字“文索”,用数字序号表示就是“2~5”,那么它将被切分成:
234 345
这样,就与全文索引对上了。
例②:搜索关键字“x光机”,用数字序号表示就是“3~7”,那么它将被切分成:
345 456 567
这样,也与全文索引对上了。
例③:搜索关键字“1台 光机”,用数字序号表示就是“0~2”和“4~7”,那么它将被切分成:
012 456 567
这样,多关键字搜索也与全文索引对上了。
MySQL在高并发连接、数据库记录数较多的情况下,SELECT ... WHERE ... LIKE '%...%'的全文搜索方式不仅效率差,而且以通配符%和_开头作查询时,使用不到索引,需要全表扫描,对数据库的压力也很大。MySQL针对这一问题提供了一种全文索引解决方案,这不仅仅提高了性能和效率(因为MySQL对这些字段做了索引来优化搜索),而且实现了更高质量的搜索。但是,至今为止,MySQL对中文全文索引无法正确支持。
中文与西方文字如英文的一个重要区别在于,西方文字以单词为单位,单词与单词之间以空格分隔。而中文以字为单位,词由一个或多个字组成,词与词之间没有空格分隔。当试图在一个含有中文字符的字段中使用全文搜索时,不会得到正确的结果,原因在于中文中没有像英文空格那样对词定界,不能以空格作为分割,对中文词语进行索引。
引用《MySQL 5.1参考手册》中的一段话:
引用
12.7. 全文搜索功能(http://dev.mysql.com/doc/refman/5.1/zh/functions.html)
● MySQL支持全文索引和搜索功能。MySQL中的全文索引类型FULLTEXT的索引。FULLTEXT 索引仅可用于 MyISAM 表;他们可以从CHAR、 VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或 CREATE INDEX被添加。对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引, 其速度比把资料输入现有FULLTEXT索引的速度更为快。
● FULLTEXT分析程序会通过寻找某些分隔符来确定单词的起始位置和结束位置,例如' ' (间隔符号)、 , (逗号)以及 . (句号 )。假如单词没有被分隔符分开,(例如在中文里 ), 则 FULLTEXT 分析程序不能确定一个词的起始位置和结束位置。为了能够在这样的语言中向FULLTEXT 索引添加单词或其它编入索引的术语,你必须对它们进行预处理,使其被一些诸如"之类的任意分隔符分隔开。
● 诸如汉语和日语这样的表意语言没有自定界符。因此, FULLTEXT分析程序不能确定在这些或其它的这类语言中词的起始和结束的位置。
● MySQL支持全文索引和搜索功能。MySQL中的全文索引类型FULLTEXT的索引。FULLTEXT 索引仅可用于 MyISAM 表;他们可以从CHAR、 VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或 CREATE INDEX被添加。对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引, 其速度比把资料输入现有FULLTEXT索引的速度更为快。
● FULLTEXT分析程序会通过寻找某些分隔符来确定单词的起始位置和结束位置,例如' ' (间隔符号)、 , (逗号)以及 . (句号 )。假如单词没有被分隔符分开,(例如在中文里 ), 则 FULLTEXT 分析程序不能确定一个词的起始位置和结束位置。为了能够在这样的语言中向FULLTEXT 索引添加单词或其它编入索引的术语,你必须对它们进行预处理,使其被一些诸如"之类的任意分隔符分隔开。
● 诸如汉语和日语这样的表意语言没有自定界符。因此, FULLTEXT分析程序不能确定在这些或其它的这类语言中词的起始和结束的位置。
国内已有的MySQL中文全文索引解决方案有两个:一是海量科技的MySQL5.0.37--LinuxX86-Chinese+,二是hightman开发的mysql-5.1.11-ft-hightman,两者都是基于中文分词技术,对中文语句进行拆分。但是,两者都有弊端,一是不支持64位操作系统;二是对修改了MySQL源码,只支持某一MySQL版本,不便于跟进新版本;三是词库不能做到很大很全,对于专业性质较强的数据库内容(例如搜索“颐和园路东口”、“清华东路西口”等公交站点,“莱镇香格里”、“碧海云天”等楼盘名称),基于中文分词的全文索引经常搜索不出来任何内容,即使添加分词词库,也不会很全面。
由于精准全文查询的需要,我借鉴了二元交叉切分算法的思想,用自创的“三字节交叉切分算法”,写出了这款“MySQL中文全文索引插件──mysqlcft 1.0.0”。由于开发时间仓促,难免存在未发现的问题,这将后续的版本中不断完善。对于百万条记录的MySQL表进行全文检索,mysqlcft已经够用。
Mysqlcft 网址:http://code.google.com/p/mysqlcft/
Mysqlcft 作者:张宴
一、MySQL中文全文索引插件mysqlcft的特点:
1、优点:
①、精准度很高:采用自创的“三字节交叉切分算法”,对中文语句进行分割,无中文分词词库,搜索精准度远比中文分词算法高,能达到LIKE '%...%"的准确率。
②、查询速度快:查询速度比LIKE '%...%"搜索快3~50倍,文章末尾有测试结果;
③、标准插件式:以MySQL 5.1全文索引的标准插件形式开发,不修改MySQL源代码,不影响MySQL的其他功能,可快速跟进MySQL新版本;
④、支持版本多:支持所有的MySQL 5.1 Release Candidate版本,即MySQL 5.1.22 RC~最新的MySQL 5.1.25 RC;
⑤、支持字符集:支持包括GBK、GB2312、UTF-8、Latin1、BIG5在内的MySQL字符集(其他字符集没有测试过);
⑥、系统兼容好:具有i386和x86_64两个版本,支持32位(i386)和64位(x86_64)CPU及Linux系统;
⑦、适合分布式:非常适合MySQL Slave分布式系统架构,无词库维护成本,不存在词库同步问题。
2、缺点:
①、mysqlcft中文全文索引只适用于MyISAM表,因为MySQL只支持对MyISAM表建立FULLTEXT索引;
②、MySQL不能静态编译安装,否则无法安装mysqlcft插件;
③、基于“三字节交叉切分算法”的索引文件会比海量、ft-hightman等基于“中文分词算法”的索引文件稍大,但不是大很多。根据我的测试,mysqlcft全文索引的.MYI索引文件是.MYD数据文件的2~5倍。
二、mysqlcft的核心思想──“三字节交叉切分算法”
注:本文以0~7数字序号代表“英文”、“数字”和“半个汉字”,以便说明。
1、按三字节对中文语句进行切分,建立全文索引:
例如:“全文索引”或“1台x光机”四个字会被交叉分拆为6份,建立反向索引:
012 123 234 345 456 567
2、按三字节对搜索的关键字进行切分,在全文索引中找出对应信息:
例①:搜索关键字“文索”,用数字序号表示就是“2~5”,那么它将被切分成:
234 345
这样,就与全文索引对上了。
例②:搜索关键字“x光机”,用数字序号表示就是“3~7”,那么它将被切分成:
345 456 567
这样,也与全文索引对上了。
例③:搜索关键字“1台 光机”,用数字序号表示就是“0~2”和“4~7”,那么它将被切分成:
012 456 567
这样,多关键字搜索也与全文索引对上了。