前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2021-07-18 Laravel5.8结合MeiliSearch+Scout全文搜索

2021-07-18 Laravel5.8结合MeiliSearch+Scout全文搜索

作者头像
无道
发布2021-07-19 15:53:19
2.1K0
发布2021-07-19 15:53:19
举报
文章被收录于专栏:无道编程无道编程

有人说,折腾的最终目的地就是默认,这句话是真没错….

折腾那么久之后,还是就回归misiyu了


不管怎么说,最近以来,编程能力也是有不少提高的,虽然很久没写php了,但是编程这东西很多东西真是互通的..

再加上,最近撸了几个腾讯云轻量服务器,所以把原来运行在学生机上面的博客搬移到新机器上了,这次无论是Mysql,php,nginx都是全手动搭建,只能说,还是不少坑需要踩一下。

这次打算改造搜索能力,使用的是meilisearch,这是一个新出来的家伙,还不错!

image-20210718144952515
image-20210718144952515

前言

Laravel官方已经有scout+meilisearch 的一键扩展包

见:https://packagist.org/packages/laravel/scout

但是,肯定是不支持5.8版本的,所以需要我们自己写一个基于scout的搜索插件。

流程

先安装scout

代码语言:javascript
复制
composer require laravel/scout "v7.2.1"

laravel 5.8 最多支持 scout "v7.2.1"

发布:

代码语言:javascript
复制
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

在config/会多一个scout.php

新增:

代码语言:javascript
复制
'meilisearch' => [
    'host' => env('MEILISEARCH_HOST', '127.0.0.1:7700'),
]

增加个配置:

代码语言:javascript
复制
SCOUT_DRIVER=meilisearch
MEILISEARCH_MASTER_KEY=xxx
MEILISEARCH_HOST=http://xxxx:7700

首先我们写个帮助类:

代码语言:javascript
复制
<?php


namespace App\Helper;

use MeiliSearch\Client;

class MeiliSearch
{
    protected $client;

    /**
     * MeiliSearch constructor.
     */
    public function __construct()
    {
        $this->client = new Client(env('MEILISEARCH_HOST'), env('MEILISEARCH_MASTER_KEY'));
    }

    public function add(string $indexName, array $docs)
    {
        $index = $this->client->index($indexName);
        $index->addDocuments($docs);
    }


    public function update(string $indexName, array $docs)
    {
        $index = $this->client->index($indexName);
        $index->updateDocuments($docs);
    }


    public function delete(string $indexName, int $id)
    {
        $index = $this->client->index($indexName);
        $index->deleteDocument($id);
    }


    public function search(string $indexName, string $key, int $size, int $page)
    {
        $offset = $page * $size - $size;
        $index = $this->client->index($indexName);
        return $index->search($key, [
            'offset' => $offset,
            'limit' => $size,
        ]);
    }


}

上面就是个帮助函数,只是进行了再封装。 所以你需要安装 meilisearch 官方提供的php开发包:https://packagist.org/packages/meilisearch/meilisearch-php


下面这个就是核心,也是scout的扩展类:

App\Services\AppSearch

代码语言:javascript
复制
<?php


namespace App\Services;


use App\Helper\MeiliSearch;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Laravel\Scout\Builder;
use MeiliSearch\Search\SearchResult;

class AppSearch
{
    protected $ml;
    protected $indexName = 'blog_article';

    /**
     * AppSearch constructor.
     * @param MeiliSearch $ml
     */
    public function __construct(MeiliSearch $ml)
    {
        $this->ml = $ml;
    }

    /**
     * 更新给定模型索引
     *
     * @param Collection $models
     * @return void
     */
    public function update(Collection $models)
    {
        // dd($models);
        if ($models->isEmpty()) {
            return;
        }

        // if ($this->usesSoftDelete($models->first()) && config('scout.soft_delete', false)) {
        //     $models->each->pushSoftDeleteMetadata();
        // }
        Log::info('Update Index');
        $docs = [];
        $models->map(function ($model) use (&$docs) {
            $array = $model->toSearchableArray();
            if (empty($array)) {
                return;
            }
            $data = [
                'id' => $model->id,
                'title' => $model->title,
                'author_id' => $model->author_id,
                'category_id' => $model->category_id,
                'tags' => $model->tags,
                'content' => $model->content,
            ];
            $docs[] = $data;
        });
        // dd($docs);
        $this->ml->update($this->indexName, $docs);
    }

    /**
     * 从索引中移除给定模型
     *
     * @param Collection $models
     * @return void
     */
    public function delete(Collection $models)
    {
        Log::info('-------------delete-----------');
        $models->map(function ($model) {
            Log::info('Deleted:' . $model->getKey());
            $this->ml->delete($this->indexName, $model->getKey());
        });
    }

    /**
     * 通过迅搜引擎执行搜索
     *
     * @param Builder $builder
     * @return mixed
     */
    public function search(Builder $builder, $size, $page)
    {
        Log::info('search');
        return $this->ml->search($this->indexName, $builder->query, $size, $page);
    }

    /**
     * 返回给定搜索结果的主键
     *
     * @param mixed $results
     * @return \Illuminate\Support\Collection
     */
    public function mapIds($results)
    {
        return collect($results)
            ->pluck('id')->values();
    }

    /**
     * 分页实现
     *
     * @param Builder $builder
     * @param int $size
     * @param int $page
     * @return mixed
     */
    public function paginate(Builder $builder, int $size, int $page)
    {
        Log::info('paginate');
        return $this->search($builder, $size, $page);
    }

    /**
     * 返回搜索结果总数
     *
     * @param mixed $results
     * @return int
     */
    public function getTotalCount(SearchResult $results): int
    {
        return $results->getNbHits();
    }

    /**
     * 将搜索结果和模型实例映射起来
     *
     * @param Builder $builder
     * @param Model $model
     * @param mixed $results
     * @return Collection
     */
    public function map(Builder $builder, $results, Model $model): Collection
    {
        if (count($results) === 0) {
            return Collection::make();
        }

        $keys = collect($results)
            ->pluck('id')->values()->unique()->all();
        $models = $model->getScoutModelsByIds($builder, $keys)->keyBy($model->getKeyName());
        return Collection::make($results)->map(function ($hit) use ($model, $models) {
            $key = $hit['id'];
            if (isset($models[$key])) {
                return $models[$key];
            }
            return null;
        })->filter();
    }
}

当然,其实就是调用方法,在模型进行增删改查时,也对meilisearch中索引数据同步进行增删改查。


上面完成之后,你需要:

在模型Model.php中,增加use Searchable;

如:

代码语言:javascript
复制
class Article extends Model
{
    use Searchable;
    //....
}

接下来需要做的就是将其绑定到 Scout 扩展中,我们可以通过在 AppServiceProviderboot 方法中添加以下代码来实现:

代码语言:javascript
复制
// 注册新的搜索引擎
resolve(EngineManager::class)->extend('meilisearch', function ($app) {
    $ml = new MeiliSearch();
    return new AppSearch($ml);
});

最后,可以使用了:

代码语言:javascript
复制
$articles = Article::search($keyword)->paginate(15);

最后

怎么将以前的文章导入到meilisearch呢?

代码语言:javascript
复制
php artisan scout:import "App\Model\Admin\Article"

使用artisan命令就行,自带的哟!

参考

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 流程
  • 最后
  • 参考
相关产品与服务
轻量应用服务器
轻量应用服务器(TencentCloud Lighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、Web应用、小程序/小游戏、游戏服、电商应用、云盘/图床和开发测试环境,相比普通云服务器更加简单易用且更贴近应用,以套餐形式整体售卖云资源并提供高带宽流量包,将热门开源软件打包实现一键构建应用,提供极简上云体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档