Laravel Scout 为 Eloquent 模型全文搜索实现提供了简单的、基于驱动的解决方案。经过使用模型观察者,Scout 会自动同步更新模型记录的索引。php
目前,Scout 经过 Algolia 驱动提供搜索功能,不过,编写自定义驱动很简单,你能够很轻松地经过本身的搜索实现来扩展 Scout。html
注:Algolia 是一个托管式的全文搜索引擎,咱们能够经过其提供的 API 在网站和移动应用中快速实现实时搜索功能。Algolia 提供的服务是收费的,不过咱们可使用其免费版本进行测试,免费版本支持 1 万条记录/10 万次操做。mysql
首先,咱们经过 Composer 包管理器来安装 Scout:laravel
composer require laravel/scout
安装完成后,须要经过 Artisan 命令 vendor:publish
发布 Scout 配置,该命令会发布配置文件 scout.php
到 config
目录:sql
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
最后,若是你想要某个模型支持 Scout 搜索,须要添加 Laravel\Scout\Searchable
trait 到对应模型类,该 trait 会注册模型观察者来保持搜索驱动与模型记录数据的一致性:数据库
<?php namespace App; use Laravel\Scout\Searchable; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Searchable; }
虽然不强制,可是在使用 Scout 以前强烈建议配置一个队列驱动。运行一个队列进程将容许 Scout 把全部同步模型信息到搜索索引的操做推送到队列中,从而为应用的 Web 接口提供更快的响应时间。数组
配置好队列驱动后,在配置文件 config/scout.php
中设置 queue
选项的值为true
:composer
'queue' => env('SCOUT_QUEUE', true),
Algoliaide
使用 Algolia 驱动的话,须要在配置文件 config/scout.php
中设置 Algolia 的 id
和 secret
信息(这些信息能够在注册登陆 Algolia 以后在用户后台找到,分别对应 API Keys 下的 Application ID 和 Admin API Key)。配置好以后,还须要经过 Composer 包管理器安装 Algolia PHP SDK:post
composer require algolia/algoliasearch-client-php
每一个 Eloquent 模型都是经过给定的搜索“索引”进行同步,该索引包含了全部可搜索的模型记录,换句话说,你能够将索引看做是一个 MySQL 数据表。默认状况下,每一个模型都会被持久化到与模型对应表名(一般是模型名称的复数形式)相匹配的索引中,不过,你能够经过重写模型中的 searchableAs
方法来覆盖这一默认设置:
<?php namespace App; use Laravel\Scout\Searchable; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Searchable; /** * 获取模型的索引名称. * * @return string */ public function searchableAs() { return 'posts_index'; } }
默认状况下,模型以完整的 toArray
格式持久化到搜索索引,若是你想要自定义被持久化到搜索索引的数据,能够重写模型上的 toSearchableArray
方法:
<?php namespace App; use Laravel\Scout\Searchable; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Searchable; /** * 获取模型的索引数据数组 * * @return array */ public function toSearchableArray() { $array = $this->toArray(); // 自定义数组... return $array; } }
若是将 Scout 安装到了已存在的项目,可能该项目以前已经有了能够导入搜索驱动的数据库记录,Scout 提供了 Artisan 命令 import
用于导入全部已存在的数据到搜索索引:
php artisan scout:import "App\Post"

导入成功后,咱们在 Algolia 后台就能够看到导入成功的索引数据:
添加 Laravel\Scout\Searchable
trait 到模型以后,剩下须要作的就是保存模型实例,而后该实例会自动被添加到模型索引,若是你配置了 Scout 使用队列,该操做会被推送到队列在后台执行:
$post = new App\Post; $post->title = 'Scout是什么'; $post->content = 'Scout是Laravel官方提供的全文搜索解决方案'; $post->user_id = 1; $post->save();
模型数据保存以后,也会经过 Scout 同步到 Algolia:

经过查询添加
若是你想要经过 Eloquent 查询添加模型集合到搜索索引,能够在 Eloquent 查询以后追加 searchable
方法调用。searchable
方法会分组块进行查询并将结果添加到搜索索引。再次强调,若是你配置了 Scout 使用队列,全部的组块查询会被推送到队列在后台进行:
// 经过 Eloquent 查询添加... App\Post::where('user_id', '>', 10)->searchable(); // 还能够经过关联关系添加记录... $user->posts()->searchable(); // 还能够经过集合添加记录... $posts->searchable();
searchable
方法会进行“upsert”操做,换句话说,若是模型记录已经存在于索引,则会被更新,若是不存在,才会被添加。
要更新支持搜索的模型,只需更新模型实例的属性并保存模型到数据库。Scout 会自动持久化更新到搜索索引:
$post = App\Post::find(2); $post->title = '学院君是谁'; $post->content = '学院君建立了Laravel学院,故而得名'; $post->save();
去 Algolia 查看索引数据,已更新:
还可使用模型查询提供的 searchable
方法更新模型集合,若是模型在搜索索引中不存在,则会被建立:
// 经过 Eloquent 查询更新... App\Post::where('user_id', '>', 10)->searchable(); // 还能够经过关联关系更新... $user->posts()->searchable(); // 还能够经过集合更新... $posts->searchable();
要从索引中删除记录,只需从数据库中删除对应记录便可,这种删除方式甚至兼容软删除模型:
$post = App\Post::find(1); $post->delete();
若是你在删除记录前不想获取模型,可使用模型查询实例或集合上的 unsearchable
方法:
// 经过 Eloquent 查询移除... App\Post::where('user_id', '>', 10)->unsearchable(); // 还能够经过关联关系移除... $user->posts()->unsearchable(); // 还能够经过集合移除... $posts->unsearchable();
有时候你须要在不一样步模型数据到搜索索引的状况下执行批量的 Eloquent 操做,能够经过 withoutSyncingToSearch
方法来实现。该方法接收一个当即被执行的回调,该回调中出现的全部模型操做都不会同步到搜索索引:
App\Post::withoutSyncingToSearch(function () { // Perform model actions... });
你能够经过 search
方法来搜索一个模型,该方法接收一个用于搜索模型的字符串,而后你还须要在这个搜索查询上调用一个 get
方法来获取与给定搜索查询相匹配的 Eloquent 模型:
$posts = App\Post::search('学院')->get();
因为 Scout 搜索返回的是 Eloquent 模型集合,你甚至能够直接从路由或控制器中返回结果,它们将会被自动转换为 JSON 格式:
use Illuminate\Http\Request; Route::get('/search', function (Request $request) { return App\Post::search($request->search)->get(); });
搜索「学院」的话,返回两条搜索结果:

若是你想要获取原生搜索结果而不是转化后的 Eloquent 模型,可使用 raw
方法:
$posts = App\Post::search('学院')->raw();
返回数据以下:

搜索查询使用模型类的 searchAs
方法指定的索引进行查询。不过,你也可使用 within 方法指定一个自定义的索引进行搜索:
$posts = App\Post::search('学院') ->within('users_index') ->get();
Scout 容许你添加简单的 where 子句到搜索查询,目前,这些子句仅支持简单的数值相等检查,因为搜索索引不是关系型数据库,更多高级的 where 子句暂不支持:
$posts = App\Post::search('学院')->where('user_id', 1)->get();
除了获取模型集合以外,还可使用 paginate
方法对搜索结果进行分页,该方法返回一个 Paginator
实例 —— 就像你对传统 Eloquent 查询进行分页同样:
$posts = App\Post::search('学院')->paginate();
返回结果以下:

你能够经过传入数量做为 paginate
方法的第一个参数来指定每页显示多少个模型:
$posts = App\Post::search('学院')->paginate(15);
获取结果以后,可使用 Blade 显示结果并渲染分页连接,就像对传统 Eloquent 查询进行分页时同样:
<div class="container"> @foreach ($orders as $order) {{ $order->price }} @endforeach </div> {{ $orders->links() }}
编写引擎
若是某个内置的 Scout 搜索引擎不知足你的需求,能够编写自定义的引擎并将其注册到 Scout,自定义的引擎须要继承自抽象类 Laravel\Scout\Engines\Engine
,该抽象类包含了 7 个自定义引擎必须实现的方法:
use Laravel\Scout\Builder; abstract public function update($models); abstract public function delete($models); abstract public function search(Builder $builder); abstract public function paginate(Builder $builder, $perPage, $page); abstract public function mapIds($results); abstract public function map($results, $model); abstract public function getTotalCount($results);
这些方法的实现能够参考 Laravel\Scout\Engines\AlgoliaEngine
类,这个类为咱们学习如何在自定义引擎中实现这些方法提供了最佳范本。
注册引擎
编写好自定义引擎以后,能够经过 Scout 引擎管理器提供的 extend
方法将其注册到 Scout。你须要在 AppServiceProvider
(或者其余服务提供者)的 boot
方法中调用这个 extend
方法。例如,若是你编写了 MySqlSearchEngine
,能够这样注册:
use Laravel\Scout\EngineManager; /** * 启动任意应用服务. * * @return void */ public function boot() { resolve(EngineManager::class)->extend('mysql', function () { return new MySqlSearchEngine; }); }
引擎被注册以后,能够在配置文件 config/scout.php
中将其设置为 Scout 默认的驱动:
'driver' => env('SCOUT_DRIVER', 'mysql'),