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'),