基于Sphinx+MySQL的千万级数据全文检索(搜索引擎)架构设计

来自: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自带的中文分词词库。



   二、MySQL+Sphinx+SphinxSE安装步骤:
   1、安装python支持 (以下针对CentOS系统,其他Linux系统请使用相应的方法安装)
yum install -y python python-devel


   2、编译安装LibMMSeg (LibMMSeg是为Sphinx全文搜索引擎设计的中文分词软件包,其在GPL协议下发行的中文分词法,采用Chih-Hao Tsai的MMSEG算法。LibMMSeg在本文中用来生成中文分词词库。)

  以下压缩包“sphinx-0.9.8-rc2-chinese.zip”中包含mmseg-0.7.3.tar.gz、sphinx-0.9.8-rc2.tar.gz以及中文分词补丁。


unzip sphinx-0.9.8-rc2-chinese.zip
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://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

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 ../

mv /usr/local/sphinx/etc/sphinx.conf /usr/local/sphinx/etc/sphinx.conf.old




   第二章第3节之后的正文内容不予公布,全文的目录如下(共24页):

   点击在新窗口中浏览此图片

   点击在新窗口中浏览此图片

  点击在新窗口中浏览此图片


 [文章作者:张宴 本文版本:v1.0 最后修改:2010.02.05 转载请注明原文链接:http://blog.zyan.cc/sphinx_search/]

  前言:

  2008年7月,我写过一篇文章《基于Sphinx+MySQL的千万级数据全文检索(搜索引擎)架构设计》。有不少网友希望阅读全文,我将该文档整理了一下,分享出来。文档解压后大小为7.33M,共19页。

  本站下载地址: http://blog.zyan.cc/book/sphinx/sphinx_mysql.zip

  新浪下载分流: http://ishare.iask.sina.com.cn/f/6728201.html

  上述文档架构存在的局限,我在2008年12月的文章《亿级数据的高并发通用搜索引擎架构设计》中已经指出:一是MySQL本身的并发能力有限,在200~300个并发连接下,查询和更新就比较慢了;二是由于MySQL表的主键与Sphinx索引的ID一一对应,从而无法跨多表建立整站查询,而且新增加类别还得修改配置文件,比较麻烦;三是因为和MySQL集成,无法发挥出Sphinx的优势。虽然如此,但对于一些写入量不大的搜索应用,已经足够了,或许对很多人会有帮助。



  正文:

  在这之后,本人基于《 亿级数据的高并发通用搜索引擎架构设计 》开发的Sphinx分布式通用站内搜索引擎平台,已经在生产环境运行9个月以上,经过运营中的不断完善与改进,目前已形成了一套可扩展的分布式通用站内搜索引擎框架。CMS、视频、论坛等产品发生的增、删、改操作,文本内容实时写入自行开发的  HTTPSQS  高性能简单消息队列服务,通过队列控制器更新索引和存储。提供支持XML、JSON的API查询接口,支持亿级数据的索引、分布式、中文分词、高亮显示、自动摘要、准实时(1分钟内)增量索引更新。

   点击在新窗口中浏览此图片

  下面是Sphinx新的搜索架构中技术关键点实现方式的一些介绍,与大家分享、交流一下:

   1、一元分词和中文分词的结合:

  ①、一元分词位于索引更新模块。Sphinx索引引擎对于CJK(中日韩)语言(必须是UTF-8编码)支持一元切分,假设【反恐行动是国产主视角射击网络游戏】这段文字,Sphinx会将其切成【反 恐 行 动 是 国 产 主 视 角 射 击 网 络 游 戏】,然后对每个字建立反向索引。如果用这句话中包含的字组成一个不存在的词语,例如【恐动】,也会被搜索到,所以搜索时,需要加引号,例如搜索【"反恐行动"】,就能完全匹配连在一起的四个字,不连续的【"恐动"】就不会被搜索到。但是,这样还有一个问题,搜索【"反恐行动游戏"】或【"国产网络游戏"】就会搜索不到。对于这个问题,采用位于搜索查询模块的中文分词来处理。

  sphinx.conf配置文件中关于UTF-8中文一元分词的配置如下:
...省略...
index t_source_main
{
        source                  = t_source_main
        path                    = /data0/search/sphinx/data/t_source_main
        docinfo                 = extern
        mlock                   = 0
        morphology              = none
        min_word_len            = 1
        charset_type            = utf-8
        min_prefix_len          = 0
        html_strip              = 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
}
...省略...


  ②、中文分词位于搜索查询模块。搜索“反恐行动游戏”、“国产网络游戏”,先调用独立的中文分词系统,分别切分为“反恐行动 游戏”、“国产 网络游戏”,这时候,再给以空格分隔的词语加上引号,去Sphinx搜索【"反恐行动" "游戏"】或【"国产" "网络游戏"】,就能搜索到这条记录了。中文分词词库发生增、删、改,无需重建整个Sphinx搜索索引。



   2、使用自行开发的HTTPSQS(http://code.google.com/p/httpsqs)开源简单队列服务程序,来缓冲高并发数据写入

  新闻、论坛帖子、客服公告、SNS社区等发生的增、删、改操作,文本内容通过更新接口实时写入HTTPSQS队列,再通过队列控制器更新到Sphinx搜索引擎索引中。



   3、Sphinx不能严格按照字段排序的小问题

  如果不想使用权重,只希望严格按照时间、主键等排序,而匹配模式(Matching modes)又为非SPH_MATCH_BOOLEAN时(比较常用的是SPH_MATCH_ALL、SPH_MATCH_EXTENDED),Sphinx搜索结果在某一页中的排序会不太准确。例如:按照UNIX时间戳倒序排序,0,20为第一页,20,40为第二页,第一页的最小时间戳一定会大于第二页的最大时间戳,但是,第一页中的0,20条记录却不会严格按照时间戳排序,第二页亦是如此。因此,如果需要精确排序,用户翻到搜索结果的某一页,就需要对Sphinx在某一搜索结果页中的记录另行再排序,在我的这套搜索架构中,这一再排序操作由search.php查询接口使用array_multisort()函数处理。一般情况下,一页只会显示5~30条记录,因此,只对几十条记录采用PHP再排序,速度也是非常快的。



   4、队列控制器中“时间控制”与“数量控制”相结合,实现搜索索引的1分钟内准实时更新:

  ①、Sphinx 0.9.9生产环境的建索引速度大约在5.5 Mbytes/秒、6400文档/秒。队列控制器可以设置10秒钟更新一次增量索引,只要Sphinx增量索引数据源的文档数在38万以内,就能保证增量索引在1~60秒内得到更新,这是从“时间”上进行控制。

  ②、为了避免增量索引数据源的文档数增长到38万,队列控制器在增量索引数据源的文档数超过1万时,还将激活增量索引合并入主索引的操作,合并完成的文档将从增量索引数据源中删除,这是从“数量”上进行控制。



   5、自行编写的“搜索引擎查询API接口”调用说明:
http://xxx.xxx.xxx.xxx/search.php?query=%E9%87%91%E5%B1%B1  (搜索关键字。程序能够识别关键字是GBK编码还是UTF-8编码,能够识别关键字是否进行了URL编码)
&output=xml  (输出类型支持:xml 或 json)
&excerpts=1  (是否开启高亮显示与文本摘要,1开启 或 0关闭)
&excerpts_before=<font color=red>  (高亮显示与文本摘要,如果为空值则不进行高亮显示与文本摘要。在匹配的关键字前面插入的字符串。)
&excerpts_after=</font>  (高亮显示与文本摘要,如果为空值则不进行高亮显示与文本摘要。在匹配的关键字之后插入的字符串。)
&excerpts_limit=256  (高亮显示与文本摘要,如果为空值则不进行高亮显示与文本摘要。摘要最多包含的符号(码点)数。)
&excerpts_field=c1,c2,c3,c4,c5  (仅对指定的字段进行高亮显示,其余字段不进行高亮显示,如果此参数为空,则默认所有的字符型字段都进行高亮显示)
&offset=0&limit=20  (相当于SQL语句中的limit 0,20)
&max_matches=30000  (最大搜索结果集数量)
&match_mode=SPH_MATCH_EXTENDED2
&ranking_mode=SPH_RANK_PROXIMITY_BM25
&sort_mode=SPH_SORT_EXTENDED&sort_by=@relevance DESC,u1 ASC,@id DESC  (排序模式:@relevance和@id是内置变量,@relevance代表相关度权值,@id等于search_id,u1为字段名)
&field_weights=c1,7;c2,1  (权重设置:字段c1的权重为7,字段c2的权重为1)
&filter=u1:0_1_6,false;u2:4,true  (整数值过滤器:匹配字段u1等于0、1或6,并且字段u2不等于4的结果集。false表示等于,true表示不等于)
&filter_range=u1:0,100,false;u2:50,90,true  (整数范围过滤器:字段u1 >= 0并且u1 <= 100,字段u2 < 50并且u2 > 90)
&filter_range=u1:1.23,99.645,false;u2:1034.3,7834.56,true  (浮点数范围过滤器:字段u1 >= 1.23并且u1 <= 99.645,字段u2 < 1034.3并且u2 > 7834.56)




   6、搜索结果前台页面示例:

   点击在新窗口中浏览此图片



   7、同一套服务器平台与API接口,通用于各类产品:

  示例:

  金山游戏文章与视频搜索: http://s.xoyo.com/result.php?w=%E5%89%91%E7%BD%913

  金山游戏论坛帖子搜索: http://jx3.bbs.xoyo.com/search2.php?srchtxt=%E4%B8%83%E7%A7%80&select=title


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值