最近比较忙,今天抽空完善了一下。
What/Sphinx是什么? 定义:Sphinx是一个全文检索引擎。
Why/为什么使用Sphinx? 遇到一个类似这样的需求:用户可以通过文章标题和文章搜索到一片文章的内容,而文章的标题和文章的内容分别保存在不同的库,而且是跨机房的这种类似的例子。 sphinx 官网下载地址(这里根据自己的情况选择相应的版本下载即可) 这里我下载的是sphinx-3.1.1-release-win64.zip,将下载的文件解压,解压后将文件夹重命名为sphinx(方便后续操作,目录结构如下图所示) sphinx 目录结构
代码语言:javascript复制如果没有data和log目录自己创建一下即可。
将上一步得到的sphinx文件夹剪切或复制到某个磁盘下,这里我放到E:PRO2下
将E:PRO2sphinxetcsphinx-min.conf.dist复制到E:PRO2sphinxbin下,并重命名为sphinx.conf;
修改E:PRO2sphinxbinsphinx.conf文件的数据库配置,这里根据自己的情况进行配置即可(如下图) bin 目录
Minimal Sphinx configuration sample (clean, simple, functional)
主索引数据原定义
代码语言:javascript复制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:PRO2sphinxbin 建立主索引,执行
E:PRO2sphinxbinindexer.exe -c E:PRO2sphinxbinsphinx.conf article_main 建立增量索引
E:PRO2sphinxbinindexer.exe -c E:PRO2sphinxbinsphinx.conf article_delta 如果运行上述命令行有错误,则根据错误提示去改动配置文件即可。
这时候你可以去看一下E:PRO2sphinxbindata目录里面已经生成了索引文件(如下图所示,索引文件的名字对应你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
代码语言:javascript复制<?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文件
代码语言:javascript复制<?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:PRO2sphinxbinindexer.exe -c E:PRO2sphinxbinsphinx.conf article_main
E:PRO2sphinxbinindexer.exe -c E:PRO2sphinxbinsphinx.conf --merge article_main article_delta --rotate 加入到windows 任务计划启动即可(需要优化bat脚本隐藏执行) 加入计划任务的步骤: 计划任务
创建任务
为任务填写一个名称 任务名称
触发任务的条件
选择你要执行的bat脚本
完成查看列表
现在我们向数据库添加一些数据,再添加之前,我们先去看一下数据库的数据 sphinx_article 表 最大的id是138 sph_counter 表 记录的max_doc_id也是138 如图: sphinx_article
sph_counter表
下面我们运行插入一些数据
代码语言:javascript复制$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,操作更方便哦