[ Laravel 5.4 文档 ] 官方包 —— Laravel Scout

1、简介

Laravel ScoutEloquent 模型全文搜索实现提供了简单的、基于驱动的解决方案,通过使用模型观察者,Scout 会自动同步更新模型记录的索引
目前,Scout 通过 Algolia 驱动提供搜索功能,不过,编写自定义驱动很简单,你可以很轻松地通过自己的搜索实现来扩展 Scout。

2、安装

首先,我们通过 Composer 包管理器来安装 Scout:

composer require laravel/scout

接下来,需要添加 ScoutServiceProvider到配置文件 config/app.phpproviders 数组:

Laravel\Scout\ScoutServiceProvider::class,

注册 Scout 服务提供者之后,还需要通过 Artisan 命令 vendor:publish发布Scout 配置,该命令会发布配置文件 scout.phpconfig目录:

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

最后,如果你想要模型变得可搜索,需要添加 Laravel\Scout\Searchable trait 到模型类,该 trait 会注册模型观察者来保持搜索驱动与模型记录数据的一致性:

<?php namespace App;
    use Laravel\Scout\Searchable;
    use Illuminate\Database\[Eloquent](https://laravelacademy.org/tags/eloquent)\Model;
    class Post extends Model{ 
        use Searchable;
    }

队列

尽管不强制使用 Scout,不过在使用这个库之前强烈建议考虑配置一个队列驱动。运行一个队列进程将允许 Scout 把所有同步模型信息到搜索索引的操作推送到队列中,从而为应用的 web 界面提供更快的响应时间。
配置好队列驱动后,在配置文件 config/scout.php中设置 queue选项的值为true

'queue' => true,

驱动预备知识

Algolia
使用 Algolia 驱动的话,需要在配置文件 config/scout.php中设置 Algolia 的 idsecret信息。配置好之后,还需要通过 Composer 包管理器安装 Algolia PHP SDK:

composer require algolia/algoliasearch-client-php

3、配置

配置模型索引

每个 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; 
            }
      }

4、索引

批量导入

如果你想要安装 Scout 到已存在的项目,你可能已经有了想要导入搜索驱动的数据库记录,Scout 提供了 Artisan 命令 import用于导入所有已存在的数据到搜索索引:

php artisan scout:import "App\Post"

添加记录

添加 Laravel\Scout\Searchable trait 到模型之后,剩下需要做的就是保存模型实例,然后该实例会自动被添加到模型索引,如果你配置了 Scout 使用队列,该操作会被推送到队列在后台执行:

$order = new App\Order;
// ...
$order->save();

通过查询添加
如果你想要通过 Eloquent 查询添加模型集合到搜索索引,可以在 Eloquent 查询之后追加 searchable方法调用。searchable方法会分组块进行查询并将结果添加到搜索索引。再次强调,如果你配置了 Scout 使用队列,所有的组块查询会被推送到队列在后台进行:

// 通过Eloquent查询添加...
App\Order::where('price', '>', 100)->searchable();

// 还可以通过关联关系添加记录...
$user->orders()->searchable();

// 还可以通过集合添加记录...
$orders->searchable();

searchable方法还可以进行“upsert”操作,换句话说,如果模型记录已经存在于索引,则会被更新,如果不存在,则会被添加。

更新记录

要更新可搜索的模型,需要更新模型实例的属性并保存模型到数据库。Scout 会自动持久化更新到搜索索引:

$order = App\Order::find(1);
// 更新订单...
$order->save();

还可以使用模型查询提供的 searchable方法更新模型集合,如果模型在搜索索引中不存在,则会被创建:

// 通过Eloquent查询更新...
App\Order::where('price', '>', 100)->searchable();
// 还可以通过关联关系更新...
$user->orders()->searchable();
// 还可以通过集合更新...
$orders->searchable();

移除记录

要从索引中移除记录,只需从数据库中删除记录即可,这种移除方式甚至兼容软删除模型:

$order = App\Order::find(1);$order->delete();

如果你在删除记录前不想获取模型,可以使用模型查询实例或集合上的 unsearchable
方法:

// 通过Eloquent查询移除...
App\Order::where('price', '>', 100)->unsearchable();
// 还可以通过关联关系移除...
$user->orders()->unsearchable();
// 还可以通过集合移除...
$orders->unsearchable();

暂停索引

有时候你需要在不同步模型数据到搜索索引的情况下执行批量的 Eloquent 操作,可以通过withoutSyncingToSearch方法来实现。该方法接收一个立即被执行的回调,该回调中出现的所有模型操作都不会同步到搜索索引:

App\Order::withoutSyncingToSearch(function () { 
// Perform model actions...
});

5、搜索

你可以通过 search方法来搜索一个模型,该方法接收一个用于搜索模型的字符串,然后你还需要在这个搜索查询上调用一个 get方法来获取与给定搜索查询相匹配的 Eloquent 模型:

$orders = App\Order::search('Star Trek')->get();

由于 Scout 搜索返回的是 Eloquent 模型集合,你甚至可以直接从路由或控制器中返回结果,它们将会被自动转换为 JSON 格式:

use Illuminate\Http\Request;

Route::get('/search', function (Request $request) { 
    return App\Order::search($request->search)->get();
});

where子句
Scout 允许你添加简单的 where 子句到搜索查询,目前,这些子句仅支持简单的数值相等检查,由于搜索索引不是关系型数据库,更多高级的 where 子句暂不支持:

$orders = App\Order::search('Star Trek')->where('user_id', 1)->get();

分页
除了获取模型集合之外,还可以使用 paginate 方法对搜索结果进行分页,该方法返回一个Paginator实例 —— 就像你对传统 Eloquent 查询进行分页一样:

$orders = App\Order::search('Star Trek')->paginate();

你可以通过传入数量作为paginate方法的第一个参数来指定每页显示多少个模型:

$orders = App\Order::search('Star Trek')->paginate(15);

获取结果之后,可以使用 Blade 显示结果并渲染分页链接,就像对传统 Eloquent 查询进行分页时一样:

<div class="container"> 
    @foreach ($orders as $order) 
        {{ $order->price }} 
    @endforeach

</div>{{ $orders->links() }}

6、自定义引擎

编写引擎
如果某个内置的 Scout 搜索引擎不满足你的需求,可以编写自定义的引擎并将其注册到 Scout,自定义的引擎需要继承自抽象类 Laravel\Scout\Engines\Engine,该抽象类包含了5个自定义引擎必须实现的方法:

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 map($results, $model);

这5个方法的实现可以参考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' => 'mysql',
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 143,639评论 1 302
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 61,591评论 1 258
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 95,050评论 0 213
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 41,169评论 0 180
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,976评论 1 258
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,876评论 1 178
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,476评论 2 273
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,229评论 0 167
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 29,095评论 6 234
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,579评论 0 213
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,356评论 2 215
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,698评论 1 232
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,272评论 0 32
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,168评论 2 214
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,605评论 3 210
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,645评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,035评论 0 166
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,609评论 2 232
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,698评论 2 233

推荐阅读更多精彩内容