Scout 全文搜尋


#######

Laravel Scout

  • 簡介
  • #安裝
    • ##佇列
    • 驅動必要條件
  • #配置
    • 配置模型索引
    • 配置可搜尋資料
    • 配置模型ID
  • 索引
    • 批次匯入
    • 新增記錄
    • 更新記錄
    • #刪除記錄
    • 暫停索引
    • #有條件的可搜尋模型實例
  • 搜尋
    • Where 條件
    • #分頁
    • 軟體刪除
    • 自訂引擎的搜尋
  • #自訂引擎
  • 。巨集

#Laravel Scout 為Eloquent 模型的全文搜尋提供了基於驅動的簡單的解決方案。透過使用模型觀察者, Scout 會自動同步 Eloquent 記錄的搜尋索引。

目前, Scout 自帶一個

Algolia 驅動程式。不過,寫自訂驅動也很簡單,你可以輕鬆的透過自己的搜尋實作來擴展 Scout。

#安裝

#首先,透過Composer 套件管理器來安裝Scout:

composer require laravel/scout

Scout安裝完成後,使用 

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 idsecret 憑證。配置好憑證之後,還需要使用Composer 套件管理器安裝Algolia PHP SDK:

composer require algolia/algoliasearch-client-php:^2.2

##設定

#配置模型索引

每個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();       
           // 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();
你可以透過將數量作為第一個參數傳遞給

paginate

方法來指定每頁檢索多少個模型:

$orders = App\Order::search('Star Trek')->paginate(15);
取得到檢索結果後,就可以使用Blade 來渲染分頁連結和顯示檢索結果,就像傳統的Eloquent 查詢分頁一樣:

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

軟體刪除

如果你的索引模型是軟體刪除,而你需要搜尋軟刪除的模型,設定

config /scout.php

設定檔的soft_delete 選項的值為true

'soft_delete' => true,
當這個設定選項是

true

的時候, Scout 不會從搜尋索引中移除軟刪除模型。相反,它會在索引記錄中設定一個隱藏 __soft_deleted 屬性。然後,在搜尋的時候,你可以使用withTrashedonlyTrashed 方法來擷取軟刪除記錄:

// 搜索结果包括已删除的记录...
$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();
這篇文章首發在 LearnKu.com 網站上。