[ Laravel 5.5 文档 ] 官方扩展包 —— 全文搜索解决方案:Laravel Scout
简介
Laravel Scout 为 Eloquent 模型全文搜索实现提供了简单的、基于驱动的解决方案。通过使用模型观察者,Scout 会自动同步更新模型记录的索引。
目前,Scout 通过 Algolia 驱动提供搜索功能,不过,编写自定义驱动很简单,你可以很轻松地通过自己的搜索实现来扩展 Scout。
注:Algolia 是一个托管式的全文搜索引擎,我们可以通过其提供的 API 在网站和移动应用中快速实现实时搜索功能。Algolia 提供的服务是收费的,不过我们可以使用其免费版本进行测试,免费版本支持 1 万条记录/10 万次操作。
安装
首先,我们通过 Composer 包管理器来安装 Scout:
composer require laravel/scout
安装完成后,需要通过 Artisan 命令 vendor:publish
发布 Scout 配置,该命令会发布配置文件 scout.php
到 config
目录:
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
:
'queue' => env('SCOUT_QUEUE', true),
驱动预备知识
Algolia
使用 Algolia 驱动的话,需要在配置文件 config/scout.php
中设置 Algolia 的 id
和 secret
信息(这些信息可以在注册登录 Algolia 之后在用户后台找到,分别对应 API Keys 下的 Application ID 和 Admin API Key)。配置好之后,还需要通过 Composer 包管理器安装 Algolia PHP SDK:
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();
where 子句
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'),
[ Laravel 5.5 文档 ] 官方扩展包 —— 全文搜索解决方案:Laravel Scout的更多相关文章
- Laravel 5.5 文档 ] 快速入门 —— 安装配置篇
服务器要求 Laravel 框架对PHP版本和扩展有一定要求,不过这些要求 Laravel Homestead 都已经满足了,不过如果你没有使用 Homestead 的话(那真是一件很遗憾的事情),有 ...
- MFC单文档自定义扩展名及添加图标报Assertion错误
忽然无聊的想给自己写的程序保存的文件使用自己的名字简写作为后缀,于是有了下文. IDR_MAINFRAME格式介绍 IDR_MAINFRAME字符串资源中包含7个子串,分别以/n结束,即如下格式: & ...
- [ Laravel 5.5 文档 ] 处理用户请求 —— HTTP 请求的过滤器:中间件
[ Laravel 5.5 文档 ] 处理用户请求 —— HTTP 请求的过滤器:中间件 http://laravelacademy.org/post/7812.html 简介 中间件为过滤进入应用的 ...
- JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载
EasyExcel是一个基于Java的简单.省内存的读写Excel的开源项目.在尽可能节约内存的情况下支持读写百M的Excel. github地址:https://github.com/alibaba ...
- [ Laravel 5.5 文档 ] 快速入门 —— 目录结构篇
简介 Laravel 默认的目录结构试图为不管是大型应用还是小型应用提供一个良好的起点.当然,你也可以按照自己的喜好重新组织应用的目录结构,因为 Laravel 对于指定类在何处被加载没有任何限制 — ...
- [ Laravel 5.5 文档 ] 底层原理 —— 一次 Laravel 请求的生命周期
Posted on 2018年3月5日 by 学院君 简介 当我们使用现实世界中的任何工具时,如果理解了该工具的工作原理,那么用起来就会得心应手,应用开发也是如此.当你理解了开发工具如何工作,用起 ...
- Python读取word文档(python-docx包)
最近想统计word文档中的一些信息,人工统计的话...三天三夜吧 python 不愧是万能语言,发现有一个包叫做 docx,非常好用,具体查看官方文档:https://python-docx.read ...
- jdk1.6文档官方下载资源
JDK1.6官方下载_JDK6官方下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin- ...
- Dapper的封装、二次封装、官方扩展包封装,以及ADO.NET原生封装
前几天偶然看到了dapper,由于以前没有用过,只用过ef core,稍微看了一下,然后写了一些简单的可复用的封装. Dapper的用法比较接近ADO.NET所以性能也是比较快.所以我们先来看看使用A ...
随机推荐
- hdu 5762 Teacher Bo 暴力
Teacher Bo 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5762 Description Teacher BoBo is a geogra ...
- URAL 1963 Kite 计算几何
Kite 题目连接: http://acm.hust.edu.cn/vjudge/contest/123332#problem/C Description Vova bought a kite con ...
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped
节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作 ...
- Introduction to Cortex Serial Wire Debugging
Serial Wire Debug (SWD) provides a debug port for severely pin limited packages, often the case for ...
- Ubuntu 中启用 root 帐号
参考:http://linuxtoy.org/archives/howto_enable_ubuntu_root_account.html 如果你实在需要在 Ubuntu 中启用 root 帐号的话, ...
- c# SerialPort会出现“已关闭 Safe handle”的错误
c# SerialPort使用时出现“已关闭 Safe handle”的错误我在开发SerialPort程序时出现了一个问题,在一段特殊的扫描代码的时候会出现“已关闭 Safe handle”的错误, ...
- A股和B股票的区别?
一.A股和B股的区别——概念不同 (一).A股的概念A股是由中国境内的公司发行,正式名称是人民币普通股票,供境内机构.组织或个人(从4月1日起,境内港.澳.台居民可开立A股账户)以人民币认购和交易的普 ...
- C#编程(十二)----------函数
类和结构 类和结构实际上都是创建对象的模板 ,每 个对象都包含数据 ,并 提供了处理和访问数据的方法. 类定义了类的每个对象 (称 为实例 )可 以包含什么数据和功能 . 例如 ,如 果 一 个类表示 ...
- [开源]Google code Android开源项目(一)
[Android分享] [开源]Google code Android开源项目(一) [复制链接] 449122717 2 主题 2 好友 816 积分 No.4 中级开发者 升级 19.3 ...
- Netty入门实例及分析
什么是netty?以下是官方文档的简单介绍: The Netty project is an effort to provide an asynchronous event-driven netwo ...