最近比较忙,今天抽空完善了一下。
What/Sphinx是什么?
定义:Sphinx是一个全文检索引擎。
Why/为什么使用Sphinx?
遇到一个类似这样的需求:用户可以通过文章标题和文章搜索到一片文章的内容,而文章的标题和文章的内容分别保存在不同的库,而且是跨机房的这种类似的例子。
sphinx 官网下载地址(这里根据自己的情况选择相应的版本下载即可)
这里我下载的是sphinx-3.1.1-release-win64.zip,将下载的文件解压,解压后将文件夹重命名为sphinx(方便后续操作,目录结构如下图所示) sphinx 目录结构
如果没有data和log目录自己创建一下即可。
将上一步得到的sphinx文件夹剪切或复制到某个磁盘下,这里我放到E:\PRO\2\下
将E:\PRO\2\sphinx\etc\sphinx-min.conf.dist复制到E:\PRO\2\sphinx\bin\下,并重命名为sphinx.conf;
修改E:\PRO\2\sphinx\bin\sphinx.conf文件的数据库配置,这里根据自己的情况进行配置即可(如下图) bin 目录
Minimal Sphinx configuration sample (clean, simple, functional)
主索引数据原定义
source article_main
{
type = mysql #数据库类型
sql_host = localhost #数据库地址
sql_user = root #用户名
sql_pass = 123456 #密码
sql_db = test #数据库名
sql_port = 3306 #端口
sql_query_pre = SET NAMES utf8 #编码
sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(id) FROM sphinx_article #获取数据源表最大的主键id 插入到sph_counter表做标记
#使用多次查询,那么这个多次查询就需要有个范围和步长,sql_query_range和sql_range_step就是做这个使用的。
sql_query_range =
sql_range_step = 10000
sql_query = SELECT * FROM sphinx_article WHERE id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1)
#sql_attr_uint = cat_id
#sql_attr_uint = member_id
sql_attr_timestamp = created #从SQL读取到的值必须为整数,作为时间属性
#sql_query_info_pre = SET NAMES utf8 #命令行查询时,设置正确的字符集
#sql_query_post = SELECT * FROM sphinx_article WHERE id=$id #命令行查询时,从数据库读取原始数据信息
}
# 增量索引数据原定义
source article_delta :article_main
{
sql_query_pre = SET NAMES utf8
sql_query_range =
sql_range_step = 10000
sql_query = select * from sphinx_article where id > (select max_doc_id from sph_counter where counter_id = 1)
sql_attr_timestamp = created
sql_query_post = UPDATE sph_counter SET max_doc_id=(SELECT MAX(id) FROM sphinx_article) where counter_id=1
#sql_query_info_pre = SET NAMES utf8
#sql_query = SELECT * FROM article_info WHERE id=$id
}
# 主索引index定义
index article_main
{
source = article_main #对应的source名称
path = E:/PRO/2/sphinx/data/article_main
mlock = 0
morphology = none
min_word_len = 1
html_strip = 0
ngram_len = 1
ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6
}
# 增量索引index定义
index article_delta:article_main
{
source = article_delta
path = E:/PRO/2/sphinx/data/article_delta
mlock = 0
morphology = none
min_word_len = 1
html_strip = 0
ngram_len = 1
ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6
}
indexer
{
mem_limit = 128M
}
searchd
{
listen = 9312
listen = 9306:mysql41
log = E:/PRO/2/sphinx/log/searchd.log
query_log = E:/PRO/2/sphinx/log/query.log
read_timeout = 5
max_children = 30
pid_file = E:/PRO/2/sphinx/log/searchd.pid
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
workers = threads # for RT to work
binlog_path = E:/PRO/2/sphinx/log
}
然后建立数据主表,并插入一些数据作为搜索
CREATE TABLE sphinx_article
(
id
int(11) NOT NULL AUTO_INCREMENT,
title
varchar(255) CHARACTER SET utf8 DEFAULT '',
cat_id
tinyint(1) unsigned zerofill NOT NULL DEFAULT '0',
member_id
int(11) unsigned NOT NULL,
content
longtext CHARACTER SET utf8 NOT NULL,
created
int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (id
)
) ENGINE=MyISAM AUTO_INCREMENT=139 DEFAULT CHARSET=latin1;
插入的数据如图: 主表数据如图
建立存储主表的最大id表,用于添加数据时sphinx的更新索引文件
CREATE TABLE sph_counter
(
counter_id
int(11) NOT NULL COMMENT '标识不同的数据表',
max_doc_id
int(11) NOT NULL COMMENT '每个索引表的最大ID,会实时更新',
PRIMARY KEY (counter_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
接下来我们打开cmd窗口,进入目录E:\PRO\2\sphinx\bin 建立主索引,执行
E:\PRO\2\sphinx\bin\indexer.exe -c E:\PRO\2\sphinx\bin\sphinx.conf article_main
建立增量索引
E:\PRO\2\sphinx\bin\indexer.exe -c E:\PRO\2\sphinx\bin\sphinx.conf article_delta
如果运行上述命令行有错误,则根据错误提示去改动配置文件即可。
这时候你可以去看一下E:\PRO\2\sphinx\bin\data目录里面已经生成了索引文件(如下图所示,索引文件的名字对应你sphinx.conf中主索引index定义path的article_main)
索引文件生成
现在启动表示sphinx服务
E:/PRO/2/sphinx/bin/searchd.exe --config E:/PRO/2/sphinx/bin/sphinx.conf
启动成功如图所示(有错误就根据错误提示去更改配置文件): sphinx 启动成功如图
下面我们去完善搜索界面,前端代码
test.php
<?php
header('Content-type:text/html;charset=utf-8');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>sphinx test</title>
</head>
<body>
<form name="form" method="get" action="index.php">
<label>
<input style="width: 400px;" type="text" name="keyword">
</label>
<label>
<input type="submit" name="Submit" value="sphinx搜索">
</label>
</form>
</body>
</html>
前端界面如下:
index.php文件
<?php
/**
* Created by ZhengNiu.
* User: 77103
* Date: 2019/7/4
* Time: 16:32
*/
header("Content-type:text/html;charset=utf-8;");
if (empty($_GET)) {
header("Location:test.php");
}
$keyword = $_GET['keyword'];
if (trim($keyword) == '') {
exit('请输入关键词');
}
require_once './sphinx/api/sphinxapi.php';
$cl = new SphinxClient();
$cl->SetServer('localhost',9312);
$res = $cl->Query($keyword, 'article_main');
$data = [];
if (isset($res['matches']) && !empty($res['matches'])) {
$ids = implode(',', array_keys($res['matches']));
$m = new Mysqli('localhost','root','123456','test');
if ($m->connect_errno) {
exit($m->connect_error);
}
$dt = $m->query("SELECT id,title,cat_id,member_id,content,created FROM sphinx_article WHERE id IN" .'('. $ids .')');
while ($row = $dt->fetch_assoc()) {
$data[] = $row;
}
}
echo "<pre>";
print_r($data);
搜索结果:
还有一个问题未解决,如果我更新了或者添加了数据库记录,我每次都要运行一下重新生成索引文件???这样是不是太不灵活了。我们可以写一个sphinx.bat脚本,加入到windows 的计划任务中,这样就可以了。
添加数据库内容时更新索引文件原理:
1.新建一张表,记录一下上一次已经创建好索引的最后一条记录的ID
2.当索引时,然后从数据库中取出所有ID大于上面那个sphinx中的那个ID的数据, 这些就是新的数据,然后创建一个小的索引文件
3.把上边我们创建的增量索引文件合并到主索引文件上去
4.把最后一条记录的ID更新到第一步创建的表中
sphinx.bat 脚本内容
E:\PRO\2\sphinx\bin\indexer.exe -c E:\PRO\2\sphinx\bin\sphinx.conf article_main
E:\PRO\2\sphinx\bin\indexer.exe -c E:\PRO\2\sphinx\bin\sphinx.conf --merge article_main article_delta --rotate
加入到windows 任务计划启动即可(需要优化bat脚本隐藏执行)
加入计划任务的步骤:
计划任务
创建任务
为任务填写一个名称 任务名称
触发任务的条件
选择你要执行的bat脚本
完成查看列表
现在我们向数据库添加一些数据,再添加之前,我们先去看一下数据库的数据
sphinx_article 表 最大的id是138
sph_counter 表 记录的max_doc_id也是138
如图: sphinx_article
sph_counter表
下面我们运行插入一些数据
$m = new Mysqli('localhost','root','123456','test');
for ($i = 138; $i <= 140; $i++) {
$add = [
'id' => $i,
'title' => "我爱吃肉肉$i",
'cat_id' => rand(1, 99),
'member_id' => rand(1, 999),
'content' => uniqid(),
'created' => time()
];
$key = implode(",", array_keys($add));
$val = "'" . implode("','", array_values($add)) . "'";
$sql = "INSERT INTO `sphinx_article` ({$key}) VALUES ({$val})";
$m->query($sql);
}
$m->close();die;
这时候查看
sphinx_article 表 最大的id是140
sph_counter 表 记录的max_doc_id是138
我们的任务任务是每分钟一次。一分钟后我们去检索一下数据,看看可以查到我们新插入的两条数据不。
结果: 完成
到这里也就结束了。
源码地址: 链接:https://pan.baidu.com/s/1ai5Xlze98FX3RQefbcLspg 提取码:s6zy 复制这段内容后打开百度网盘手机App,操作更方便哦
One comment
哔,萌新卡!上车的旅客请系好安全带!现在是:Fri Aug 02 2019 20:27:49 GMT+0800 (中国标准时间)