php简单使用sphinx 以及增量索引和主索引来实现索引的实时更新

2022-09-11 11:15:14 浏览数 (2)

最近比较忙,今天抽空完善了一下。

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,操作更方便哦

0 人点赞