Scout 全文搜尋
Laravel Scout
#Laravel Scout 為Eloquent 模型的全文搜尋提供了基於驅動的簡單的解決方案。透過使用模型觀察者, Scout 會自動同步 Eloquent 記錄的搜尋索引。 目前, Scout 自帶一個Algolia 驅動程式。不過,寫自訂驅動也很簡單,你可以輕鬆的透過自己的搜尋實作來擴展 Scout。
#安裝#首先,透過Composer 套件管理器來安裝Scout:composer require laravel/scoutScout安裝完成後,使用
vendor:publish Artisan 指令來產生Scout 設定檔。這個指令將會在你的
config 目錄下產生一個
scout.php 設定檔。
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"最後,在你要做搜尋的模型中加入
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' => true,
驅動必要條件
Algolia
使用Algolia 驅動程式時,需要在config/scout.php
設定檔設定你的Algolia id
和secret
憑證。配置好憑證之後,還需要使用Composer 套件管理器安裝Algolia PHP SDK:
composer require algolia/algoliasearch-client-php:^2.2##設定
<?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'; } }
格式持久化到搜尋索引。如果要自訂同步到搜尋索引的數據,可以覆寫模型上的
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();
// Customize array...
return $array;
}
}
配置模型ID預設情況下,Scout 將使用模型的主鍵作為搜尋索引中儲存的唯一ID 。可以透過模型上的
getScoutKey<?php namespace App; use Laravel\Scout\Searchable; use Illuminate\Database\Eloquent\Model; class User extends Model{ use Searchable; /** * 获取模型主键 * * @return mixed */ public function getScoutKey() { return $this->email; } }#批次匯入######如果你想安裝Scout 到已存在的專案中,你可能已經有了想要匯入搜尋驅動程式的資料庫記錄。 Scout 提供了Artisan 指令###import### 用來匯入所有已存在的記錄到搜尋索引:###
php artisan scout:import "App\Post"######flush### 指令可用於從搜尋索引中刪除所有模型的記錄:###
php artisan scout:flush "App\Post"#####################新增記錄######當你將###Laravel\Scout\Searchable trait#### 加到模型中,你需要做的就是###save### 一個模型實例,它將自動被加入到搜尋索引。如果你已經將 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
方法可以被看做是「更新插入”的操作。換句話說,如果模型記錄已經在你的索引裡了,它就會被更新。如果搜尋索引中不存在,則將其新增至索引。
#更新記錄
#要更新可搜尋的模型,只需要更新模型實例的屬性並將模型save
到資料庫。 Scout 會自動將更新同步到你的搜尋索引中:
$order = App\Order::find(1); // 更新订单... $order->save();
你也可以在 Eloquent 查詢語句上使用 searchable
方法來更新一個模型的集合。如果這個模型不存在你檢索的索引裡,就會被建立:
// 通过 Eloquent 查询更新... App\Order::where('price', '>', 100)->searchable(); // 你也可以通过数据间的关联进行更新... $user->orders()->searchable(); // 你也可以通过数据集合进行更新... $orders->searchable();
#刪除記錄
使用delete
從資料庫中刪除該模型就可以移除索引裡的記錄。這種刪除形式甚至與軟刪除的模型相容:
$order = App\Order::find(1); $order->delete();
如果你不希望記錄在刪除之前被檢索到,可以在Eloquent 查詢實例或集合上使用unsearchable
方法:
// 通过 Eloquent 查询删除... App\Order::where('price', '>', 100)->unsearchable(); // 你可以通过数据间的关系进行删除... $user->orders()->unsearchable(); // 你可以通过数据集合进行删除... $orders->unsearchable();
暫停索引
#你可能需要在執行一批Eloquent 操作的時候,不同步模型資料到搜索索引。此時你可以使用 withoutSyncingToSearch
方法來執行此操作。這個方法接受一個立即執行的回調。此回呼中所有的操作都不會同步到模型的索引:
App\Order::withoutSyncingToSearch(function () { // 执行模型操作... });
#有條件的搜尋模型實例
有時候你可能需要在某些條件下模型是可搜尋的。例如,假設你有 App\Post
模型可能兩種狀態之一:「草稿」和「發布」。你可能只允許搜尋 「發布」過的貼文。為了實現這一點,你需要在模型中定義一個shouldBeSearchable
方法:
public function shouldBeSearchable(){ return $this->isPublished(); }
只有在透過save
方法、查詢或關聯模型操作時,才應使用shouldBeSearchable
方法。直接使用searchable
方法將使模型或集合的可搜尋結果覆寫shouldBeSearchable
方法的結果:
// 此处将遵循 "shouldBeSearchable" 结果... App\Order::where('price', '>', 100)->searchable(); $user->orders()->searchable();$order->save(); // 此处将覆盖 "shouldBeSearchable" 结果... $orders->searchable(); $order->searchable();
搜尋
你可以使用 search
方法來搜尋模型。 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(); });
如果你想在它們返回Eloquent 模型前得到原始結果,你應該使用raw
#方法:
$orders = App\Order::search('Star Trek')->raw();
搜尋查詢通常會在模型的searchableAs
方法指定的索引上執行。當然,你也可以使用within
方法來指定應該搜尋的自訂索引:
$orders = App\Order::search('Star Trek') ->within('tv_shows_popularity_desc') ->get();##Where 語句允許你在搜尋查詢中增加簡單的"where" 語句。目前,這些語句只支援基本的數值等式檢查,並且主要用於根據租用戶 ID 進行的範圍搜尋查詢。由於搜尋索引不是關係型資料庫,因此目前不支援更進階的"where" 語句:
$orders = App\Order::search('Star Trek')->where('user_id', 1)->get();
#除了檢索模型的集合,你也可以使用
paginate 方法來分頁搜尋結果。這個方法會傳回一個就像傳統的Eloquent 查詢分頁一樣的Paginator
實例:
你可以透過將數量作為第一個參數傳遞給$orders = App\Order::search('Star Trek')->paginate();
方法來指定每頁檢索多少個模型:
取得到檢索結果後,就可以使用Blade 來渲染分頁連結和顯示檢索結果,就像傳統的Eloquent 查詢分頁一樣:$orders = App\Order::search('Star Trek')->paginate(15);
<div class="container"> @foreach ($orders as $order) {{ $order->price }} @endforeach </div> {{ $orders->links() }}
如果你的索引模型是軟體刪除,而你需要搜尋軟刪除的模型,設定
config /scout.php 設定檔的soft_delete
選項的值為true
:
當這個設定選項是'soft_delete' => true,
的時候, Scout 不會從搜尋索引中移除軟刪除模型。相反,它會在索引記錄中設定一個隱藏 __soft_deleted
屬性。然後,在搜尋的時候,你可以使用withTrashed
或onlyTrashed
方法來擷取軟刪除記錄:// 搜索结果包括已删除的记录...
$orders = App\Order::withTrashed()->search('Star Trek')->get();
// 搜索结果只含已删除的记录...
$orders = App\Order::onlyTrashed()->search('Star Trek')->get();
forceDelete#來刪除,Scout 將自動的從搜尋索引移除模型。
自訂搜尋引擎
如果需要自訂引擎的搜尋行為,可以將回呼作為第二個參數傳遞給 search
方法。例如,在將搜尋查詢傳遞給Algolia 之前,可以使用這個回呼將地理位置資料新增至搜尋請求:
use Algolia\AlgoliaSearch\SearchIndex; App\Order::search('Star Trek', function (SearchIndex $algolia, string $query, array $options) { $options['body']['query']['bool']['filter']['geo_distance'] = [ 'distance' => '1000km', 'location' => ['lat' => 36, 'lon' => 111], ]; return $algolia->search($query, $options); })->get();
自訂引擎
寫入引擎
如果內建的Scout 搜尋引擎不能滿足你的需求,你可以寫一個自訂的引擎並且將它註冊到Scout。你的引擎需要繼承Laravel\Scout\Engines\Engine
抽象類,這個抽象類別包含了你自訂的引擎必須要實現的七個方法:
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); abstract public function flush($model);
在 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
:
'driver' => 'mysql',
#產生巨集指令
如果你想要自訂產生器方法,你可以使用 Laravel\Scout\Builder
類別下的macro
方法。通常,定義"macros" 時, 需要實作service provider's boot
方法:
<?php namespace App\Providers; use Laravel\Scout\Builder; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Response; class ScoutMacroServiceProvider extends ServiceProvider{ /** * 注册应用的Scout 宏命令. * * @return void */ public function boot() { Builder::macro('count', function () { return $this->engine->getTotalCount( $this->engine()->search($this) ); }); } }
macro
函數接受一個名字作為第一個參數,第二個參數為一個閉包函數。當
呼叫 Laravel\Scout\Builder
巨集指令時,呼叫這個函數.
App\Order::search('Star Trek')->count();