Laravel 全文检索解决方案 Laravel-Scout

其实这一篇通篇基本照搬官方文档,只是稍加整理 精简了下最必要的部分。

Posted by 昆山吴彦祖 on 2019.06.28

眼看着Blog也写了不少了,经常要翻找一些之前写的blog来学(拷)习(备)下,但是发现通过 栏目和分页去寻找,还是太累了,决定写个检索


就决定是你了 -scout

参考资料

scout 是laravel官方的一个检索拓展库,虽然现在里面的检索引擎(接口)只有 Algolia,但是也是可以自己拓展引擎的。


安装Scout

composer require laravel/scout
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"


配置需要检索的模型

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Searchable;
}


安装Algolia驱动

composer require algolia/algoliasearch-client-php:^2.2


配置Algolia

使用 Algolia 驱动的话,需要在配置文件 config/scout.php 中设置 Algolia 的 id 和 secret 信息(这些信息可以在注册登录 Algolia 之后在用户后台找到,分别对应 API Keys 下的 Application ID 和 Admin API Key)

目前Aligolia 免费版提供1w条数据和5w条操作可供使用,对于我的blog来说,应该是错错有余了,感恩Aligolia(为了表示感谢,再挂一次链接)


配置搜索数据(非必需)

因为发现我的blog内容过长,免费版的Algolia不支持我上传内容,我只能把 blog的 简介、栏目、tag一起传过去做检索了,不然光凭一个标题很难检索出我想要的内容。因为tag 、栏目我都是和blog做的多对多,无法通过默认模型监听更新到检索库。

这样的话我们就需要配置检索数据

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Searchable;

    /**
     * 获取模型的索引数据数组
     *
     * @return array
     */
    public function toSearchableArray()
    {
        $array=array();
        $array['title'] = $this->title;	$array['category'] = implode(" ",$this->category->pluck('title')->all());

$array['description'] = $this->description;

$array['tag'] = implode(" ",$this->tag->pluck('title')->all());

// 这里返回自定义数组... return $array; } }


批量导入

首次配置完成上面这些,如果数据库已有数据,这时候我们可以用指令进行批量导入

php artisan scout:import "App\Post"


ok,到这一步,如果不出意外的话,你的algolia 后台应该已经有了一批可检索的数据了。

非常智能,你每次上传、更新、删除 资源的时候,检索库也会自动更新。

but,到这一步,我遇到了一个很尴尬的问题,我更新blog的tag的时候,检索库没有进行同步更新。机制如我一猜就知道是因为 tag是关联表,当blog表更新完成,触发了提交检索数据以后,tag表才会进行更新,所以我虽然在blog模型的 toSearchableArray ​方法中提交了 tag字段,但提交的时候却是空的。


好吧,刚好官方推荐我们用 队列来进行检索库数据提交,不出意外的话,队列也刚好能解决我的这个问题。


队列的配置

还好之前已经配置过了一个 基于datebase的队列了。


配置文件 config/scout.php

'queue' => env('SCOUT_QUEUE', true),


好了,到这一步我scout的配置已经完成了,接下来就是如何使用前台检索了。


前台检索

Blog::search($key)->paginate(10);

直接通过模型的search方法就可以进行关键词的检索,而且还支持 多词组合检索、近似词容错搜索。真的是很强大很方便了。

当然了,缺点也是有的,因为Algolia并没有大陆的服务器,所以检索速度并不是很快很稳定,而且每个月$29的基础班费用也不算很美好(你有钱任性当我没说

根据我之前做过一次Algolia的经验,Algolia应该是可以设置 标题 、内容 等数据的一个检索优先级和排序规则,不过我暂时不需要这个,下次再去做


ps:使用scout 队列的时候,一定要配置队列的默认失败执行次数。scout自带的队列处理文件没有进行配置。
我就遇到这个坑了,没有配置最大失败执行次数,结果最大执行次数超过256(数据库执行次数字段为tinyint-3,队列执行记录插入数据库失败),导致队列堵塞, 队列默认执行日志没有执行记录。数据库 fail-jobs 也没用失败记录。还好最后在 laravel默认日志找到了相关记录,才排查掉问题。


全文检索 队列 scout