PHP 运用 Redis 构建高性能的实时搜索

15 篇文章 0 订阅

需求

  • 能够在键盘输入的瞬间响应搜索结果;
  • 不需要太复杂的查询,单个字段作为搜索条件;
  • 分词、模糊匹配;
  • 实时更新;

一、安装Redis

wget http://dl.fedoraproject.org/pub/epel/7/x86_64/r/redis-3.2.3-1.el7.x86_64.rpm
rpm -ivh redis-3.2.3-1.el7.x86_64.rpm
systemctl start redis

出现 libjemalloc.so.1()(64bit) 被 redis-3.2.3-1.el7.x86_64 需要, 默认用jemalloc管理内存

wget http://dl.fedoraproject.org/pub/epel/7/x86_64/j/jemalloc-3.6.0-1.el7.x86_64.rpm
rpm -ivh jemalloc-3.6.0-1.el7.x86_64.rpm

外网访问

vim /etc/redis.conf # 取消 bind 127.0.0.1  修改 protected-mode no

二、PHP程序实现(基于laravel5.1)

1. 基础表数据
CREATE TABLE `article` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(100) DEFAULT NULL,
  `score` int(10) unsigned DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2. PHP 分词程序 SCWS
wget http://www.xunsearch.com/scws/down/scws-1.2.3.tar.bz2
tar xvjf scws-1.2.3.tar.bz2    # 如果缺少bzip2 请 yum install bzip2
cd scws-1.2.3
./configure --prefix=/usr/local/scws
make
make install

# 下载字典
cd /usr/local/scws/etc
wget http://www.xunsearch.com/scws/down/scws-dict-chs-gbk.tar.bz2
wget http://www.xunsearch.com/scws/down/scws-dict-chs-utf8.tar.bz2
tar xvjf scws-dict-chs-gbk.tar.bz2
tar xvjf scws-dict-chs-utf8.tar.bz2

# 安装PHP扩展
cd scws-1.2.3  # 下载目录打开
phpize
./configure --with-scws=/usr/local/scws  # 若 PHP 安装在特殊目录, 则请在 configure 后加上 --with-php-config=$php_prefix/bin/php-config
make
make install

# php.ini 配置
[scws]
extension = scws.so
scws.default.charset = utf8
scws.default.fpath = /usr/local/scws/etc

# 注意请检查 php.ini 中的 extension_dir 的设定值是否正确, 否则请将 extension_dir 设为空,
# 再把 extension = scws.so 指定绝对路径。
3. laravel 安装 predis 包
composer require "predis/predis:1.0.*"
4. 基础 models
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $table = 'article';

    public $timestamps = false;
}
5. 数据添加时建立索引
use App\Models\Article;

$server = [
    'scheme' => 'tcp',
    'host'   => '127.0.0.1',
    'port'   => 6379,
];
$redisClient = new \Predis\Client($server);

Article::created(function ($article) use ($redisClient) {
    $so = scws_new();
    $so->send_text($article->title);
    while ($tmp = $so->get_result()) {
        foreach ($tmp as $value) {
            $redisClient->sadd('search:key:'.$value['word'], $article->id);
            $redisClient->set('search:score:'.$article->id, $article->score);
            $redisClient->hmset('search:data', [$article->id => $article->title]);
        }
    }
    $so->close();
});
6. 数据删除时删除索引
Article::deleted(function ($article) use ($redisClient) {
    $so = scws_new();
    $so->send_text($article->title);
    while ($tmp = $so->get_result()) {
        foreach ($tmp as $value) {
            $redisClient->srem('search:key:'.$value['word'], $article->id);
            $redisClient->del('search:score:'.$article->id);
            $redisClient->hdel('search:data', $article->id); 
        }
    }
    $so->close();
});
7. 数据修改时自己改吧!!!
8. 数据搜索实现
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function index(Request $request)
    {
        $server = [
            'scheme' => 'tcp',
            'host'   => '127.0.0.1',
            'port'   => 6379,
        ];
        $redisClient = new \Predis\Client($server);
        $key = 'search:key:';

        $title = $request->input('title'); 
        $so = scws_new();
        $so->send_text($title);
        while ($tmp = $so->get_result()) {
            foreach ($tmp as $value) {
                $aTitle[] = $key . $value['word'];
                $aTitleVal[] = $value['word'];
            }
        }
        $so->close();

        if (isset($aTitle)) {
            $mergeKey = 'search:key:' . implode('+', $aTitleVal);
            $redisClient->sinterstore($mergeKey, $aTitle);
            $interstore = $redisClient->sort($mergeKey, ['BY' => 'search:score:*', 'sort' => 'desc']);
            $result = $redisClient->hmget('search:data', $interstore);
            print_r($result);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值