主要目的: 打造千万级数据全文搜索的数据库, 提升查询效率
系统环境
主机名 | IP 地址 | 相关服务 | 版本 |
SQL | 172.169.18.128 | mysql5.6(主) | |
Sphinx | 172.169.18.210 | mysql5.6(从)php5.6 Apache2.4 | sphinx 版本:2.2.10 sphinx 插件:1.3.3 scws 分词版本:1.2.3 |
一, 简介
1.1, Sphinx 是什么
参考地址: http://www.sphinxsearch.org/sphinx-tutorial
Sphinx 是由俄罗斯人 Andrew Aksyonoff 开发的一个全文检索引擎. 意图为其他应用提供高速, 低空间占用, 高结果 相关度的全文搜索功能. Sphinx 可以非常容易的与 SQL 数据库和脚本语言集成. 当前系统内置 MySQL 和 PostgreSQL 数据库数据源的支持, 也支持从标准输入读取特定格式 的 xml 数据.
Sphinx 创建索引的速度为: 创建 100 万条记录的索引只需 3~4 分钟, 创建 1000 万条记录的索引可以在 50 分钟内完成, 而只包含最新 10 万条记录的增量索引, 重建一次只需几十秒.
1.2, Sphinx 的特性如下:
(1)高速的建立索引(在当代 CPU 上, 峰值性能可达到 10 MB / 秒);
(2)高性能的搜索(在 2 - 4GB 的文本数据上, 平均每次检索响应时间小于 0.1 秒);
(3)可处理海量数据(目前已知可以处理超过 100 GB 的文本数据, 在单一 CPU 的系统上可处理 100 M 文档);
(4)提供了优秀的相关度算法, 基于短语相似度和统计 (BM25) 的复合 Ranking 方法;
(5) 支持分布式搜索;
(6)支持短语搜索
(7)提供文档摘要生成
(8)可作为 MySQL 的存储引擎提供搜索服务;
(9)支持布尔, 短语, 词语相似度等多种检索模式;
(10)文档支持多个全文检索字段(最大不超过 32 个);
(11)文档支持多个额外的属性信息(例如: 分组信息, 时间戳等);
(12)支持断词;
1.3, 总结
优点: 效率较高, 具有较高的扩展性
缺点: 不负责数据存储
使用 Sphinx 搜索引擎对数据做索引, 数据一次性加载进来, 然后做了所以之后保存在内存. 这样用户进行搜索的时候就只需要在 Sphinx 服务器上检索数据即可. 而且, Sphinx 没有 MySQL 的伴随机磁盘 I/O 的缺陷, 性能更佳.
2.1,SCWS 是 Simple Chinese Word Segmentation 的首字母缩写(即: 简易中文分词系统).
参考地址: http://www.xunsearch.com/scws/index.php
这是一套基于词频词典的机械式中文分词引擎, 它能将一整段的中文文本基本正确地切分成词. 词是中文的最小语素单位, 但在书写时并不像英语会在词之间用空格分开, 所以如何准确并快速分词一直是中文分词的攻关难点.
2.2, 特性
SCWS 采用纯 C 语言开发, 不依赖任何外部库函数, 可直接使用动态链接库嵌入应用程序, 支持的中文编码包括 GBK,UTF-8 等. 此外还提供了 PHP 扩展模块, 可在 PHP 中快速而方便地使用分词功能.
分词算法上并无太多创新成分, 采用的是自己采集的词频词典, 并辅以一定的专有名称, 人名, 地名, 数字年代等规则识别来达到基本分词, 经小范围测试准确率在 90% ~ 95% 之间, 基本上能满足一些小型搜索引擎, 关键字提取等场合运用. 首次雏形版本发布于 2005 年底.
二, 环境准备
1, 暂时关闭防火墙
2, 关闭 seliunx
3, 系统环境
centos7.4 mysql5.6 php5.6
三, 搭建 Sphinx 服务
1, 安装依赖包
# yum -y install make gcc gcc-c++ libtool autoconf automake MySQL-devel
2, 安装 Sphinx
- # yum install expat expat-devel
- # wget -c
- # tar -zxvf Sphinx-2.2.10-release.tar.gz
- # cd Sphinx-2.2.10-release/
- # ./configure --prefix=/usr/local/Sphinx --with-MySQL --with-libexpat --enable-id64
- # make && make install
3, 安装 libsphinxclient,PHP 扩展用到
- # cd API/libsphinxclient/
- # ./configure --prefix=/usr/local/Sphinx/libsphinxclient
- # make && make install
安装完毕后查看一下 / usr/local/Sphinx 下是否有 三个目录 bin etc var, 如有, 则安装无误!
4, 安装 Sphinx 的 PHP 扩展: 我的是 5.6 需装 Sphinx-1.3.3.tgz, 如果是 php5.4 以下可 Sphinx-1.3.0.tgz, 如果 php7.0 需要安装 Sphinx-339e123.tar.gz(http://git.php.net/?p=pecl/search_engine/sphinx.git;a=snapshot;h=339e123acb0ce7beb2d9d4f9094d6f8bcf15fb54;sf=tgz)
- # wget -c http://pecl.php.net/get/sphinx-1.3.3.tgz
- # tar zxvf Sphinx-1.3.3.tgz
- # cd Sphinx-1.3.3/
- # phpize
- # ./configure --with-Sphinx=/usr/local/Sphinx/libsphinxclient/ --with-PHP-config=/usr/bin/PHP-config
- # make && make install
- # 成功后会提示:
- Installing shared extensions: /usr/lib64/PHP/modules/
- # 修改 PHP 配置
- # echo "[Sphinx]">> /etc/PHP.INI
- # echo "extension = sphinx.so">> /etc/PHP.INI
- # 重启 httpd 服务
- # systemctl restart httpd.service
5, 创建测试数据进行测试(db:jiangjj)
- CREATE TABLE IF NOT EXISTS `items` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `title` varchar(255) NOT NULL,
- `content` text NOT NULL,
- `created` datetime NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='全文检索测试的数据表' AUTO_INCREMENT=11 ;
- INSERT INTO `items` (`id`, `title`, `content`, `created`) VALUES
- (1, 'linux mysql 集群安装', 'MySQL Cluster 是 MySQL 适合于分布式计算环境的高实用, 可拓展, 高性能, 高冗余版本', '2016-09-07 00:00:00'),
- (2, 'mysql 主从复制', 'mysql 主从备份 (复制) 的基本原理 mysql 支持单向, 异步复制, 复制过程中一个服务器充当主服务器, 而一个或多个其它服务器充当从服务器', '2016-09-06 00:00:00'),
- (3, 'hello', 'can you search me?', '2016-09-05 00:00:00'),
- (4, 'mysql', 'mysql is the best database?', '2016-09-03 00:00:00'),
- (5, 'mysql 索引', '关于 MySQL 索引的好处, 如果正确合理设计并且使用索引的 MySQL 是一辆兰博基尼的话, 那么没有设计和使用索引的 MySQL 就是一个人力三轮车', '2016-09-01 00:00:00'),
- (6, '集群', '关于 MySQL 索引的好处, 如果正确合理设计并且使用索引的 MySQL 是一辆兰博基尼的话, 那么没有设计和使用索引的 MySQL 就是一个人力三轮车', '0000-00-00 00:00:00'),
- (9, '复制原理', 'redis 也有复制', '0000-00-00 00:00:00'),
- (10, 'redis 集群', '集群技术是构建高性能网站架构的重要手段, 试想在网站承受高并发访问压力的同时, 还需要从海量数据中查询出满足条件的数据, 并快速响应, 我们必然想到的是将数据进行切片, 把数据根据某种规则放入多个不同的服务器节点, 来降低单节点服务器的压力', '0000-00-00 00:00:00');
- CREATE TABLE IF NOT EXISTS `sph_counter` (
- `counter_id` int(11) NOT NULL,
- `max_doc_id` int(11) NOT NULL,
- PRIMARY KEY (`counter_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='增量索引标示的计数表';
6,Sphinx 配置: 注意修改数据源配置信息.
配置地址: http://www.cnblogs.com/yjf512/p/3598332.html
以下采用 "Main + Delta" ("主索引"+"增量索引")的索引策略, 使用 Sphinx 自带的一元分词.
- # VIM /usr/local/Sphinx/etc/Sphinx.conf
- source items {
- type = MySQL
- sql_host = 172.169.18.128
- sql_user = jiangjj
- sql_pass = 123456
- sql_db = jiangjj
- sql_query_pre = SET NAMES utf8
- sql_query_pre = SET SESSION query_cache_type = OFF
- sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(id) FROM items
- sql_query_range = SELECT MIN(id), MAX(id) FROM items \
- WHERE id<=(SELECT max_doc_id FROM sph_counter WHERE counter_id=1)
- sql_range_step = 1000
- sql_ranged_throttle = 1000
- sql_query = SELECT id, title, content, created, 0 as deleted FROM items \
- WHERE id<=(SELECT max_doc_id FROM sph_counter WHERE counter_id=1) \
- AND id>= $start AND id <= $end
- sql_attr_timestamp = created
- sql_attr_bool = deleted
- }
- source items_delta : items {
- sql_query_pre = SET NAMES utf8
- sql_query_range = SELECT MIN(id), MAX(id) FROM items \
- WHERE id> (SELECT max_doc_id FROM sph_counter WHERE counter_id=1)
- sql_query = SELECT id, title, content, created, 0 as deleted FROM items \
- WHERE id>( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 ) \
- AND id>= $start AND id <= $end
- sql_query_post_index = set @max_doc_id :=(SELECT max_doc_id FROM sph_counter WHERE counter_id=1)
- sql_query_post_index = REPLACE INTO sph_counter SELECT 2, IF($maxid, $maxid, @max_doc_id)
- }
- # 主索引
- index items {
- source = items
- path = /usr/local/Sphinx/var/data/items
- docinfo = extern
- morphology = none
- min_word_len = 1
- min_prefix_len = 0
- html_strip = 1
- html_remove_elements = style, script
- ngram_len = 1
- ngram_chars = U+3000..U+2FA1F
- charset_type = utf-8
- charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
- preopen = 1
- min_infix_len = 1
- }
- # 增量索引
- index items_delta : items {
- source = items_delta
- path = /usr/local/Sphinx/var/data/items_delta
- }
- # 分布式索引
- index master {
- type = distributed
- local = items
- local = items_delta
- }
- indexer {
- mem_limit = 256M
- }
- searchd {
- listen = 9312
- listen = 9306:mysql41
- log = /usr/local/Sphinx/var/log/searchd.log
- query_log = /usr/local/Sphinx/var/log/query.log
- # compat_sphinxql_magics = 0
- attr_flush_period = 600
- mva_updates_pool = 16M
- read_timeout = 5
- max_children = 0
- dist_threads = 2
- pid_file = /usr/local/Sphinx/var/log/searchd.pid
- # max_marches = 1000
- seamless_rotate = 1
- preopen_indexes = 1
- unlink_old = 1
- workers = threads
- binlog_path = /usr/local/Sphinx/var/data
- }
7,Sphinx 创建索引
- # cd /usr/local/Sphinx/bin/
- # 第一次重建索引
- # ./indexer -c /usr/local/Sphinx/etc/Sphinx.conf --all
- # 启动 Sphinx
- # ./searchd -c /usr/local/Sphinx/etc/Sphinx.conf
- # 查看进程
- # ps -ef | grep searchd
- # 查看状态
- # ./searchd -c /usr/local/Sphinx/etc/Sphinx.conf --status
- # 关闭 Sphinx
- # ./searchd -c /usr/local/Sphinx/etc/Sphinx.conf --stop
8, 索引更新及使用说明
"增量索引" 每 N 分钟更新一次. 通常在每天晚上低负载的时进行一次索引合并, 同时重新建立 "增量索引". 当然 "主索引" 数据不多的话, 也可以直接重新建立 "主索引".
API 搜索的时, 同时使用 "主索引" 和 "增量索引", 这样可以获得准实时的搜索数据. 本文的 Sphinx 配置将 "主索引" 和 "增量索引" 放到分布式索引 master 中, 因此只需查询分布式索引 "master" 即可获得全部匹配数据(包括最新数据).
索引的更新与合并的操作可以放到 cron job 完成:
8.1, 编辑
- # crontab -e
- */1 * * * * /usr/local/Sphinx/shell/index_update.sh
- 0 3 * * * /usr/local/Sphinx/shell/merge_index.sh
- // 查看
- # crontab -l
8.2, 脚本如下
- # 更新脚本
- # VIM /usr/local/Sphinx/shell/index_update.sh
- #!/bin/sh
- /usr/local/Sphinx/bin/indexer -c /usr/local/Sphinx/etc/Sphinx.conf --rotate items_delta> /dev/null 2>&1
- # 合并脚本
- [root@Sphinx shell]# VIM merge_index.sh
- #!/bin/bash
- indexer=/usr/local/Sphinx/bin/indexer
- MySQL=`which mysql`
- #host=172.169.18.128
- #mysql_user=jiangjj
- #mysql_password=123456
- QUERY="use jiangjj;select max_doc_id from sph_counter where counter_id = 2 limit 1;"
- index_counter=$($MySQL -h172.169.18.128 -ujiangjj -p123456 -sN -e "$QUERY")
- #merge "main + delta" indexes
- $indexer -c /usr/local/Sphinx/etc/Sphinx.conf --rotate --merge items items_delta --merge-dst-range deleted 0 0>> /usr/local/Sphinx/var/index_merge.log 2>&1
- if [ "$?" -eq 0 ]; then
- ##update Sphinx counter
- if [ ! -z $index_counter ]; then
- $MySQL -h172.169.18.128 -ujiangjj -p123456 -Djiangjj -e "REPLACE INTO sph_counter VALUES (1,'$index_counter')"
- fi
- ##rebuild delta index to avoid confusion with main index
- $indexer -c /usr/local/Sphinx/etc/Sphinx.conf --rotate items_delta>> /usr/local/Sphinx/var/rebuild_deltaindex.log 2>&1
- fi
- # 授权
- # chmod u+x *.sh
测试没问题后继续下一步操作
四, 搭建 scws(中文分词)服务
下载地址: http://www.xunsearch.com/scws/download.php
1,scws 下载安装: 注意扩展的版本和 PHP 的版本
- # wget -c
- # tar jxvf scws-1.2.3.tar.bz2
- # cd scws-1.2.3/
- # ./configure --prefix=/usr/local/scws
- # make && make install
2,scws 的 PHP 扩展安装
- # cd ./phpext/
- # phpize
- # ./configure
# make && make install
编译完成状态如下:
- # 修改 PHP 配置文件
- [root@Sphinx ~]# echo "[scws]">> /etc/PHP.INI
- [root@Sphinx ~]# echo "extension = scws.so">> /etc/PHP.INI
- [root@Sphinx ~]# echo "scws.default.charset = utf-8">> /etc/PHP.INI
- [root@Sphinx ~]# echo "scws.default.fpath = /usr/local/scws/etc/">> /etc/PHP.INI
3, 词库安装
下载地址:
- # wget
- # tar jxvf scws-dict-chs-utf8.tar.bz2 -C /usr/local/Sphinx/etc/
- # chown -R apache:apache /usr/local/Sphinx/etc/dict.utf8.xdb
五, PHP 使用 Sphinx+scws 测试
1, 在 Sphinx 源码 API 中, 有好几种语言的 API 调用. 其中有一个是 sphinxapi.PHP.
新建一个 Search.PHP 文件, 一个前端页面 index.PHP
代码省略
访问:
2,SphinxQL 测试
要使用 SphinxQL 需要在 Searchd 的配置里面增加相应的监听端口(参考上文配置).
- # MySQL -h127.0.0.1 -P9306 -ujiangjj -p
- MySQL> show global variables;
- MySQL> desc items;
- MySQL> select * from master where match('mysql*') limit 10;
- MySQL> show meta;
来源: http://blog.51cto.com/13941177/2311405