PHP+Sphinx 实现“全文搜索 ”功能 教程

相信大家都知道PHP+Mysql是最佳的组合方式,虽然说mysql也可以做全文检索,但是效果就一般了。 如果你还想做优化,就更不能用mysql做全文检索了,为了解决这个问题,我们就需要用上:PHP+Mysql+Sphinx来实现。

 

一、sphinx 简介

 

1、什么是sphinx

Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎。意图为其他应用提供高速、低空间占用、高结果 相关度的全文搜索功能。Sphinx可以非常容易的与SQL数据库和脚本语言集成。当前系统内置MySQL和PostgreSQL 数据库数据源的支持,也支持从标准输入读取特定格式 的XML数据。通过修改源代码,用户可以自行增加新的数据源(例如:其他类型的DBMS 的原生支持)

 

2、sphinx的特性

高速的建立索引(在当代CPU上,峰值性能可达到10 MB/秒);

高性能的搜索(在2 – 4GB 的文本数据上,平均每次检索响应时间小于0.1秒);

可处理海量数据(目前已知可以处理超过100 GB的文本数据, 在单一CPU的系统上可 处理100 M 文档);

提供了优秀的相关度算法,基于短语相似度和统计(BM25)的复合Ranking方法;

支持分布式搜索;

支持短语搜索;

提供文档摘要生成;

可作为MySQL的存储引擎提供搜索服务;

支持布尔、短语、词语相似度等多种检索模式;

文档支持多个全文检索字段(最大不超过32个);

文档支持多个额外的属性信息(例如:分组信息,时间戳等);

支持断词;

 

二、sphinx 安装

 

1、系统环境

我的实战环境是centos7.2 +lnmp一键安装包;

 

2、安装sphinx

//Linux命令块:

wget http://sphinxsearch.com/files/sphinx-2.2.11-release.tar.gz ##下载sphinx

tar -zxvf sphinx-2.2.11-release.tar.gz ##解压

cd sphinx-2.2.11-release

./configure --prefix=/usr/local/sphinx/

echo $?

make

echo $?

make install ##(这里为了方便查看每一步是否执行成功以及查看错误我把散步拆开了 (echo $? 返回数字0 执行成功 返回其他失败 )

 

 

3、安装 sphinx 可能遇见的错误

//Linux命令块:
##make错误
collect2: error: ld returned 1 exit status
make[2]: *** [indexer] Error 1
make[2]: Leaving directory `/root/sphinx-2.2.11-release/src'
make[1]: *** [all] Error 2 make[1]: Leaving directory `/root/sphinx-2.2.11-release/src' make: *** [all-recursive] Error 1
##解决办法 先执行 make clean,然后修改 configure 文件,把 #define USE_LIBICONV 0 最后的数值由1改为0

 

三、sphinx的配置以及测试小demo

sphinx安装成功后我们进入sphinx目录,会发现有这几个主要目录(bin、etc、var),其中:

  • bin存放索引启动文件;
  • etc存放sphinx配置文件;
  • var存放生成的索引文件;

 

1、我们先不着急去配置sphinx,首先我们需要在mysql数据库内创建建一些数据:

//mysql语句块:
CREATE TABLE IF NOT EXISTS `node` (
  `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 `node` (`id`, `title`, `content`, `created`) VALUES
(1, '三月醉一场青春的流年', '三月,醉一场青春的流年。慢步在三月的春光里,走走停停,看花开嫣然,看春雨绵绵,感受春风拂面,春天,就是青春的流年。青春,是人生中最美的风景。青春,是一场花开的遇见', '2018-07-17 11:12:00'),
(2, '在爱的岁月山河里思念', '夜色如梦,没有人陪,坐在沙发里,一杯红酒配电影,似乎看透红尘,实际上钻心的孤独。远在他方的你,是否也一样在深夜里买醉?谁在爱的国度里,想念着谁?谁在梦里,与谁不醉不休?谁在寂寞的夜晚,想象着与谁缠绵悱恻?在爱的幸福国度,你就是我的唯一。', '2018-07-17 11:12:00'),
(3, 'php是世界上最好的语言', '女神:你能让这个知乎程序员板块的人都吵起来,我今晚就跟你走,但是提问不能问xx是不是最好的语言。程序员提问:“PHP是最好的语言”这个梗是怎么来的?女神:这能吵起来?程序员:走着瞧半小时后,知乎炸开了锅,数百回答讨论PHP的是是非非。女神:我了个去,这特么都行。服了,跟你回去就是了。程序员:不行,我一定要说服他们,PHP是最好的语言', '2018-07-17 11:12:00'),
(4, 'mysql', 'mysql is the best database?', '2018-07-17 11:12:00'),
(5, '夏色斑斓,夏意阑珊', '岁月,在风声里歌唱,一如往昔,撩起时光的衣裙。慢步在光阴的旷野,走走停停,看人来人往,看花开花谢,看日出日落。风景如画,往事如诗。那段凯歌,奏响风中的依恋,为你,为我,祭奠旧时的风景。相思豆,将你我的思念串成一个圆圈,你在地球的那头,我在地球的这头。', '2018-07-17 11:12:00'),
(6, '笔墨流芬芳,醉爱文字情', '文字,是一米阳光,温暖着我的心。阳光明媚,我在阳光里享受着它的融融暖意。文字,发着光,发着热,让我的灵魂不再四处漂游。文字,好暖,让我结冰的心湖慢慢融化。阳光,让早已心如死灰的心感受到从未有过的温暖。只要抓住那一米阳光,就等于抓住了一颗救命稻草', '2018-07-17 11:12:00'),
(7, '冬风中一朵紫罗兰', '当时我在窗前。窗里光线幽暗,冷冷清清,窗玻璃紧紧地闭着,木头的窗棂子似乎不堪冷风的肆虐有些瑟瑟发抖,这一切让我原本晦暗的心情更加晦暗,失落的灵魂更加无着无落了。', '2018-07-17 11:12:00'),
(8, '我在红尘中等你', '在这红尘里,我渴望陪你变老,不求一路轰轰烈烈,只愿一世倾心,像山野花儿把最后的生命情葬在秋天,因为你为梦想去漂泊,去了遥远的他乡,我后悔没有与你同行,致使离我而去,你知道我喜欢家乡的宁静,喜欢云的淡然恬静,喜欢山色的空蒙幽深,我喜欢握那一只短笛,诉说心中忧郁,想想走过的人生路,曾经说过相伴一生的你,如今去了南方,那些曾经许下的诺言,早已风吹云散。曾经的温暖,美好的记忆,也许只是一个转身的距离,让我在红尘中等你,今生是如何的结局。', '2018-07-17 11:12:00'),
(9, '阳光的滋味', '明眸善睐,云袖轻舒,花影婆娑,夜鸟伏声。望月,终团圆。融化一季相思苦楚,泪凝妙目。开襟解怀,邀月畅饮。一季愁情尽遣。蘸墨狂书,满腹恩爱无度。羞愧了月里仙子,忧郁了河汉星辰。明月缱惓,夜色飘香。尝遍了相思苦涩,领略这相聚欢欣。', '2018-07-17 11:12:00'),
(10, '走在迷途的拾荒人', '时光就像一个美少女,在低眉浅笑中,就将有些人一些事隔到了光阴的对面。其实光阴从不曾厚过谁也不曾薄过谁,生活就是一种积累,你若储存的温暖多,你的生活就会阳光明媚,你若储存太多寒凉,你的生活就会阴云密布。放下烦恼与忧愁,带着最美的微笑出发,脚下路在,前方希望在,回眸处爱与温暖一直都在。', '2018-07-17 11:12:00');

 

2、打开sphinxd的配置文件:

#Linux命令块:
cd etc 
vim sphinx.conf.dist

 

3、接下来开始我们对sphinxd做一些配置设置:

由于配置比较多,我就以图片的方式来展示出来吧!具体的配置如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

4、配置完后保存并退出:

 

5、运行Linux命令,此命令意思是“将上面配置中注释代码去除并生成新文件 sphinx.conf”;

egrep -v '#|^$' sphinx.conf.dist >sphinx.conf

 

6、现在我们打开sphinx.conf,内容如下所示:

source node { 
type = mysql 
sql_host = localhost 
sql_user = root 
sql_pass = 123456 
sql_db = test 
sql_sock = /tmp/mysql.sock 
sql_query_pre = SET NAMES utf8 
sql_query_pre = SET SESSION 
query_cache_type=OFF 
sql_query = SELECT ,id, title, content ,created FROM node 
sql_field_string = title 
sql_field_string = content 
sql_field_string = created 
sql_ranged_throttle = 0
 }
 index attr_node {
 source = node 
path = /usr/local/sphinx/var/data/attr_node 
docinfo = extern 
dict = keywords 
mlock = 0
morphology = none 
min_word_len = 1 
ngram_len = 1 
ngram_chars = U+3000..U+2FA1F 
html_strip = 0 
}
indexer {
 mem_limit = 128M 
} 
searchd {
listen = 9312 
listen = 9306:mysql41 
log = /usr/local/sphinx/var/log/searchd.log 
query_log = /usr/local/sphinx/var/log/query.log 
read_timeout = 5 
client_timeout = 300 
max_children = 30 
persistent_connections_limit = 30 
pid_file = /usr/local/sphinx/var/log/searchd.pid 
seamless_rotate = 1
preopen_indexes = 1 
unlink_old = 1 
mva_updates_pool = 1M 
max_packet_size = 8M
 max_filters = 256 
max_filter_values = 4096 
max_batch_queries = 32
 }

 

7、接下来我们创建并启动索引:

#Linux命令块:
cd ../bin

#创建索引 
./indexer --config /usr/local/sphinx/etc/sphinx.conf --all 

## --all创建全部索引 -- + 索引名 例如:--attr_node 创建attr_node索引 #启动索引
./searchd --config /usr/local/sphinx/etc/sphinx.conf

#####其他命令######
./indexer --config /usr/local/sphinx/etc/sphinx.conf --rotate --all ##重建索引

 

8、接下来我们开始demo(示例)的编写:

cd /home/wwwroot/default 
mkdir test //创建一个文件夹 
cd /sphinx-2.2.11-release/api 
cp sphinxapi.php /home/wwwroot/default/test/ 
cd /home/wwwroot/default/test/

##创建并编辑 index.html 
vim index.html 

##写入以下代码 
<!DOCTYPE html> 
<html>
 <head>
 <title>欢迎使用sphinx!</title> 
<meta charset="utf-8">
 </head> 
<body>
 <h1>欢迎使用sphinx搜索</h1> 
<form method="post" action="sphinxtest.php" > 
<input type="text" name="centent"/> <input type="submit" vlaue="搜索"> 
</form>
 </body> 
</html>

 ##然后保存退出,再然后我们 新建并编辑一个 sphinxtest.php
 vim sphinxtest.php
 
##写入以下代码 
<?php
 require('sphinxapi.php'); 
$cl = new SphinxClient (); 
$q = $_POST['centent'];
 $host = "localhost"; 
$port = 9312;
 $index = "attr_node"; $cl->SetServer ( $host, $port );
 $cl->SetConnectTimeout ( 1 ); 
$cl->SetArrayResult ( true ); 
//匹配查询词中的任意一个 
$cl->SetMatchMode(SPH_MATCH_ANY); $res = $cl->Query ( $q, $index ); echo '<pre>'; var_dump($res); echo '</pre>'; ?>
 ##保存并退出

 

9、接下来我们通过网页访问index.html,输入”岁月”二字就会打印出如下所示:

array(10) {
  ["error"]=>
  string(0) ""
  ["warning"]=>
  string(0) ""
  ["status"]=>
  int(0)
  ["fields"]=>
  array(3) {
    [0]=>
    string(5) "title"
    [1]=>
    string(7) "content"
    [2]=>
    string(7) "created"
  }
  ["attrs"]=>
  array(3) {
    ["title"]=>
    int(7)
    ["content"]=>
    int(7)
    ["created"]=>
    int(7)
  }
  ["matches"]=>
  array(4) {
    [0]=>
    array(3) {
      ["id"]=>
      int(2)
      ["weight"]=>
      string(1) "8"
      ["attrs"]=>
      array(3) {
        ["title"]=>
        string(30) "在爱的岁月山河里思念"
        ["content"]=>
        string(354) "夜色如梦,没有人陪,坐在沙发里,一杯红酒配电影,似乎看透红尘,实际上钻心的孤独。远在他方的你,是否也一样在深夜里买醉?谁在爱的国度里,想念着谁?谁在梦里,与谁不醉不休?谁在寂寞的夜晚,想象着与谁缠绵悱恻?在爱的幸福国度,你就是我的唯一。"
        ["created"]=>
        string(19) "2018-07-17 11:12:00"
      }
    }
    [1]=>
    array(3) {
      ["id"]=>
      int(5)
      ["weight"]=>
      string(1) "8"
      ["attrs"]=>
      array(3) {
        ["title"]=>
        string(27) "夏色斑斓,夏意阑珊"
        ["content"]=>
        string(375) "岁月,在风声里歌唱,一如往昔,撩起时光的衣裙。慢步在光阴的旷野,走走停停,看人来人往,看花开花谢,看日出日落。风景如画,往事如诗。那段凯歌,奏响风中的依恋,为你,为我,祭奠旧时的风景。相思豆,将你我的思念串成一个圆圈,你在地球的那头,我在地球的这头。"
        ["created"]=>
        string(19) "2018-07-17 11:12:00"
      }
    }
    [2]=>
    array(3) {
      ["id"]=>
      int(1)
      ["weight"]=>
      string(1) "2"
      ["attrs"]=>
      array(3) {
        ["title"]=>
        string(30) "三月醉一场青春的流年"
        ["content"]=>
        string(243) "三月,醉一场青春的流年。慢步在三月的春光里,走走停停,看花开嫣然,看春雨绵绵,感受春风拂面,春天,就是青春的流年。青春,是人生中最美的风景。青春,是一场花开的遇见"
        ["created"]=>
        string(19) "2018-07-17 11:12:00"
      }
    }
    [3]=>
    array(3) {
      ["id"]=>
      int(9)
      ["weight"]=>
      string(1) "1"
      ["attrs"]=>
      array(3) {
        ["title"]=>
        string(15) "阳光的滋味"
        ["content"]=>
        string(336) "明眸善睐,云袖轻舒,花影婆娑,夜鸟伏声。望月,终团圆。融化一季相思苦楚,泪凝妙目。开襟解怀,邀月畅饮。一季愁情尽遣。蘸墨狂书,满腹恩爱无度。羞愧了月里仙子,忧郁了河汉星辰。明月缱惓,夜色飘香。尝遍了相思苦涩,领略这相聚欢欣。"
        ["created"]=>
        string(19) "2018-07-17 11:12:00"
      }
    }
  }
  ["total"]=>
  string(1) "4"
  ["total_found"]=>
  string(1) "4"
  ["time"]=>
  string(5) "0.000"
  ["words"]=>
  array(2) {
    ["岁"]=>
    array(2) {
      ["docs"]=>
      string(1) "2"
      ["hits"]=>
      string(1) "2"
    }
    ["月"]=>
    array(2) {
      ["docs"]=>
      string(1) "4"
      ["hits"]=>
      string(1) "9"
    }
  }
}

以上打印结果中,matches   里边是我们想要的数据,total 是数据总数 。

因为我们设置的中文切割为 长度1 ,所以 他也搜索了包含”岁”字的,和包含”月”字的数据 。

words为切割的词,岁月本身也是一个词组 在words并没有显示而是拆分为了岁和月,中文分词并不是特别的智能 。

 

总结:本文章就到此结束,由于本文测试的数据量有限也无法让大家感受到sphinx查询的速度之快,感兴趣的小伙伴,有条件的话可以自己分别使用mysql语句 like/match 和 sphinx 来做下测试,sphinx更多的对英文进行搜索,对中文的支持并不是特别的智能,所以在下篇文章我将教大家使用PHP+Sphinx+Coreseek实现“全文搜索+中文分词 ”功能 教程

    A+
发布日期:2018年11月13日 20:11:14  所属分类:PHP
最后更新时间:2018-11-14 20:41:02
头像
  • ¥ 98.0元
  • 市场价:198.0元
  • ¥ 199.0元
  • 市场价:499.0元
  • ¥ 59.0元
  • 市场价:99.0元
  • ¥ 1999.9元
  • 市场价:8999元

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: