1醉拓、簡(jiǎn)介
Laravel Scout 為 Eloquent 模型全文搜索實(shí)現(xiàn)提供了簡(jiǎn)單的擂仍、基于驅(qū)動(dòng)的解決方案,通過(guò)使用模型觀察者粟焊,Scout 會(huì)自動(dòng)同步更新模型記錄的索引。
目前孙蒙,Scout 通過(guò) Algolia 驅(qū)動(dòng)提供搜索功能项棠,不過(guò),編寫(xiě)自定義驅(qū)動(dòng)很簡(jiǎn)單挎峦,你可以很輕松地通過(guò)自己的搜索實(shí)現(xiàn)來(lái)擴(kuò)展 Scout香追。
2、安裝
首先坦胶,我們通過(guò) Composer 包管理器來(lái)安裝 Scout:
composer require laravel/scout
接下來(lái)透典,需要添加 ScoutServiceProvider
到配置文件 config/app.php
的providers
數(shù)組:
Laravel\Scout\ScoutServiceProvider::class,
注冊(cè) Scout 服務(wù)提供者之后,還需要通過(guò) Artisan 命令 vendor:publish
發(fā)布Scout 配置顿苇,該命令會(huì)發(fā)布配置文件 scout.php
到 config
目錄:
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
最后掷匠,如果你想要模型變得可搜索,需要添加 Laravel\Scout\Searchable
trait 到模型類岖圈,該 trait 會(huì)注冊(cè)模型觀察者來(lái)保持搜索驅(qū)動(dòng)與模型記錄數(shù)據(jù)的一致性:
<?php namespace App;
use Laravel\Scout\Searchable;
use Illuminate\Database\[Eloquent](https://laravelacademy.org/tags/eloquent)\Model;
class Post extends Model{
use Searchable;
}
隊(duì)列
盡管不強(qiáng)制使用 Scout讹语,不過(guò)在使用這個(gè)庫(kù)之前強(qiáng)烈建議考慮配置一個(gè)隊(duì)列驅(qū)動(dòng)。運(yùn)行一個(gè)隊(duì)列進(jìn)程將允許 Scout 把所有同步模型信息到搜索索引的操作推送到隊(duì)列中蜂科,從而為應(yīng)用的 web 界面提供更快的響應(yīng)時(shí)間顽决。
配置好隊(duì)列驅(qū)動(dòng)后,在配置文件 config/scout.php
中設(shè)置 queue
選項(xiàng)的值為true
:
'queue' => true,
驅(qū)動(dòng)預(yù)備知識(shí)
Algolia
使用 Algolia 驅(qū)動(dòng)的話导匣,需要在配置文件 config/scout.php
中設(shè)置 Algolia 的 id
和 secret
信息才菠。配置好之后,還需要通過(guò) Composer 包管理器安裝 Algolia PHP SDK:
composer require algolia/algoliasearch-client-php
3贡定、配置
配置模型索引
每個(gè) Eloquent 模型都是通過(guò)給定的搜索“索引”進(jìn)行同步赋访,該索引包含了所有可搜索的模型記錄,換句話說(shuō),你可以將索引看作是一個(gè) MySQL 數(shù)據(jù)表蚓耽。默認(rèn)情況下渠牲,每個(gè)模型都會(huì)被持久化到與模型對(duì)應(yīng)表名(通常是模型名稱的復(fù)數(shù)形式)相匹配的索引中,不過(guò)步悠,你可以通過(guò)重寫(xiě)模型中的 searchableAs
方法來(lái)覆蓋這一默認(rèn)設(shè)置:
<?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';
}
}
配置搜索數(shù)據(jù)
默認(rèn)情況下签杈,模型以完整的 toArray格式持久化到搜索索引,如果你想要自定義被持久化到搜索索引的數(shù)據(jù)鼎兽,可以重寫(xiě)模型上的 toSearchableArray
方法:
<?php namespace App;
use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;
class Post extends Model{
use Searchable;
/**
* 獲取模型的索引數(shù)據(jù)數(shù)組
*
* @return array
*/
public function toSearchableArray() {
$array = $this->toArray(); // 自定義數(shù)組...
return $array;
}
}
4答姥、索引
批量導(dǎo)入
如果你想要安裝 Scout 到已存在的項(xiàng)目,你可能已經(jīng)有了想要導(dǎo)入搜索驅(qū)動(dòng)的數(shù)據(jù)庫(kù)記錄谚咬,Scout 提供了 Artisan 命令 import
用于導(dǎo)入所有已存在的數(shù)據(jù)到搜索索引:
php artisan scout:import "App\Post"
添加記錄
添加 Laravel\Scout\Searchable
trait 到模型之后鹦付,剩下需要做的就是保存模型實(shí)例,然后該實(shí)例會(huì)自動(dòng)被添加到模型索引择卦,如果你配置了 Scout 使用隊(duì)列敲长,該操作會(huì)被推送到隊(duì)列在后臺(tái)執(zhí)行:
$order = new App\Order;
// ...
$order->save();
通過(guò)查詢添加
如果你想要通過(guò) Eloquent 查詢添加模型集合到搜索索引,可以在 Eloquent 查詢之后追加 searchable
方法調(diào)用互捌。searchable
方法會(huì)分組塊進(jìn)行查詢并將結(jié)果添加到搜索索引潘明。再次強(qiáng)調(diào),如果你配置了 Scout 使用隊(duì)列秕噪,所有的組塊查詢會(huì)被推送到隊(duì)列在后臺(tái)進(jìn)行:
// 通過(guò)Eloquent查詢添加...
App\Order::where('price', '>', 100)->searchable();
// 還可以通過(guò)關(guān)聯(lián)關(guān)系添加記錄...
$user->orders()->searchable();
// 還可以通過(guò)集合添加記錄...
$orders->searchable();
searchable
方法還可以進(jìn)行“upsert”操作钳降,換句話說(shuō),如果模型記錄已經(jīng)存在于索引腌巾,則會(huì)被更新遂填,如果不存在,則會(huì)被添加澈蝙。
更新記錄
要更新可搜索的模型吓坚,需要更新模型實(shí)例的屬性并保存模型到數(shù)據(jù)庫(kù)。Scout 會(huì)自動(dòng)持久化更新到搜索索引:
$order = App\Order::find(1);
// 更新訂單...
$order->save();
還可以使用模型查詢提供的 searchable
方法更新模型集合灯荧,如果模型在搜索索引中不存在礁击,則會(huì)被創(chuàng)建:
// 通過(guò)Eloquent查詢更新...
App\Order::where('price', '>', 100)->searchable();
// 還可以通過(guò)關(guān)聯(lián)關(guān)系更新...
$user->orders()->searchable();
// 還可以通過(guò)集合更新...
$orders->searchable();
移除記錄
要從索引中移除記錄,只需從數(shù)據(jù)庫(kù)中刪除記錄即可逗载,這種移除方式甚至兼容軟刪除模型:
$order = App\Order::find(1);$order->delete();
如果你在刪除記錄前不想獲取模型哆窿,可以使用模型查詢實(shí)例或集合上的 unsearchable
方法:
// 通過(guò)Eloquent查詢移除...
App\Order::where('price', '>', 100)->unsearchable();
// 還可以通過(guò)關(guān)聯(lián)關(guān)系移除...
$user->orders()->unsearchable();
// 還可以通過(guò)集合移除...
$orders->unsearchable();
暫停索引
有時(shí)候你需要在不同步模型數(shù)據(jù)到搜索索引的情況下執(zhí)行批量的 Eloquent 操作,可以通過(guò)withoutSyncingToSearch
方法來(lái)實(shí)現(xiàn)厉斟。該方法接收一個(gè)立即被執(zhí)行的回調(diào)挚躯,該回調(diào)中出現(xiàn)的所有模型操作都不會(huì)同步到搜索索引:
App\Order::withoutSyncingToSearch(function () {
// Perform model actions...
});
5、搜索
你可以通過(guò) search
方法來(lái)搜索一個(gè)模型擦秽,該方法接收一個(gè)用于搜索模型的字符串码荔,然后你還需要在這個(gè)搜索查詢上調(diào)用一個(gè) get
方法來(lái)獲取與給定搜索查詢相匹配的 Eloquent 模型:
$orders = App\Order::search('Star Trek')->get();
由于 Scout 搜索返回的是 Eloquent 模型集合漩勤,你甚至可以直接從路由或控制器中返回結(jié)果,它們將會(huì)被自動(dòng)轉(zhuǎn)換為 JSON 格式:
use Illuminate\Http\Request;
Route::get('/search', function (Request $request) {
return App\Order::search($request->search)->get();
});
where子句
Scout 允許你添加簡(jiǎn)單的 where 子句到搜索查詢缩搅,目前越败,這些子句僅支持簡(jiǎn)單的數(shù)值相等檢查,由于搜索索引不是關(guān)系型數(shù)據(jù)庫(kù)誉己,更多高級(jí)的 where 子句暫不支持:
$orders = App\Order::search('Star Trek')->where('user_id', 1)->get();
分頁(yè)
除了獲取模型集合之外眉尸,還可以使用 paginate
方法對(duì)搜索結(jié)果進(jìn)行分頁(yè)域蜗,該方法返回一個(gè)Paginator
實(shí)例 —— 就像你對(duì)傳統(tǒng) Eloquent 查詢進(jìn)行分頁(yè)一樣:
$orders = App\Order::search('Star Trek')->paginate();
你可以通過(guò)傳入數(shù)量作為paginate
方法的第一個(gè)參數(shù)來(lái)指定每頁(yè)顯示多少個(gè)模型:
$orders = App\Order::search('Star Trek')->paginate(15);
獲取結(jié)果之后巨双,可以使用 Blade 顯示結(jié)果并渲染分頁(yè)鏈接,就像對(duì)傳統(tǒng) Eloquent 查詢進(jìn)行分頁(yè)時(shí)一樣:
<div class="container">
@foreach ($orders as $order)
{{ $order->price }}
@endforeach
</div>{{ $orders->links() }}
6霉祸、自定義引擎
編寫(xiě)引擎
如果某個(gè)內(nèi)置的 Scout 搜索引擎不滿足你的需求筑累,可以編寫(xiě)自定義的引擎并將其注冊(cè)到 Scout,自定義的引擎需要繼承自抽象類 Laravel\Scout\Engines\Engine
丝蹭,該抽象類包含了5個(gè)自定義引擎必須實(shí)現(xiàn)的方法:
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個(gè)方法的實(shí)現(xiàn)可以參考Laravel\Scout\Engines\AlgoliaEngine
類慢宗,這個(gè)類為我們學(xué)習(xí)如何在自定義引擎中實(shí)現(xiàn)這些方法提供了最佳范本。
注冊(cè)引擎
編寫(xiě)好自定義引擎之后奔穿,可以通過(guò) Scout 引擎管理器提供的 extend
方法將其注冊(cè)到Scout镜沽。你需要在 AppServiceProvider
(或者其他服務(wù)提供者)的boot
方法中調(diào)用這個(gè) extend
方法。例如贱田,如果你編寫(xiě)了 MySqlSearchEngine
缅茉,可以這樣注冊(cè):
use Laravel\Scout\EngineManager;
/**
* 啟動(dòng)任意應(yīng)用服務(wù).
*
* @return void
*/
public function boot(){
resolve(EngineManager::class)->extend('mysql', function () {
return new MySqlSearchEngine;
});
}
引擎被注冊(cè)之后,可以在配置文件 config/scout.php
中將其設(shè)置為 Scout 默認(rèn)的驅(qū)動(dòng):
'driver' => 'mysql',