使用Laravel Scout來實現全文搜尋

使用Laravel Scout來實現全文搜尋

Laravel框架已經成為開發人員構建網路服務的首選資源。

作為一個開源的工具, Laravel提供了無數的開箱即用的功能, 使開發者能夠建立強大的和功能性的應用程式.

在它的產品中,Laravel Scout是一個用於管理你的應用程式的搜尋索引的庫。它的靈活性讓開發者可以微調配置,並選擇Algolia, Meilisearch, MySQL, 或Postgres驅動來儲存索引。

在這裡,我們將深入探討這個工具,教你如何通過驅動為Laravel應用程式新增全文字搜尋支援。你將模擬一個Laravel應用程式,用於儲存模擬列車的名稱,然後使用Laravel Scout為應用程式新增一個搜尋。

  1. 前提條件
  2. 如何在一個Laravel專案中安裝Scout
  3. 如何新增Laravel Scout到應用程式中
  4. 如何標記一個模型和配置索引
  5. 如何使用Algolia和Scout
  6. 如何建立應用程式的控制器
  7. 如何建立應用程式的路由
  8. 如何建立應用程式的檢視
  9. 如何使用Algolia搜尋
  10. 使用Laravel Scout的Meilisearch
  11. Laravel Scout與資料庫引擎
  12. Collection引擎與Laravel Scout

前提條件

要跟上進度,你應該具備以下條件

  • 在你的電腦上安裝了 PHP 編譯器。本教程使用PHP 8.1版本。
  • 在你的電腦上安裝了Docker引擎或Docker桌面。
  • 一個Algolia雲賬戶,你可以免費建立一個賬戶。

如何在一個Laravel專案中安裝Scout

要使用Scout, 你必須首先建立一個Laravel應用程式,在那裡你打算新增搜尋功能。Laravel-Scout Bash指令碼包含了在Docker容器中生成一個Laravel應用程式的命令。使用Docker意味著你不需要安裝額外的支援軟體, 如MySQL資料庫.

Laravel-scout指令碼使用Bash指令碼語言, 所以你必須在Linux環境下執行它. 如果你執行的是Windows,確保你配置了Windows Subsystem for Linux(WSL)。

如果使用WSL,在你的終端中執行以下命令來設定你喜歡的Linux發行版。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
wsl -s ubuntu
wsl -s ubuntu
wsl -s ubuntu

接下來, 導航到你的電腦上你想放置專案的位置. Laravel-Scout指令碼會在這裡生成一個專案目錄。在下面的例子中, Laravel-Scout指令碼會在desktop目錄下建立一個目錄.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
cd /desktop
cd /desktop
cd /desktop

執行下面的命令來執行Laravel-Scout指令碼。它將用必要的模板程式碼搭建一個Docker化的應用程式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
curl -s https://laravel.build/laravel-scout-app | bash
curl -s https://laravel.build/laravel-scout-app | bash
curl -s https://laravel.build/laravel-scout-app | bash

執行完畢後,用 cd laravel-scout-app 改變你的目錄。然後,在專案資料夾中執行 sail-up 命令,為你的應用程式啟動Docker容器。

Note:在許多Linux發行版上,你可能需要用 sudo 命令執行下面的命令來啟動高許可權。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
./vendor/bin/sail up
./vendor/bin/sail up
./vendor/bin/sail up

你可能會遇到一個錯誤:

錯誤說明埠已被分配

錯誤說明埠已被分配

要解決這個問題,請使用APP_PORT變數,在 sail up 命令中指定一個埠:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
APP_PORT=3001 ./vendor/bin/sail up
APP_PORT=3001 ./vendor/bin/sail up
APP_PORT=3001 ./vendor/bin/sail up

接下來,執行下面的命令,通過Artisan在PHP伺服器上執行該應用程式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan serve
php artisan serve
php artisan serve

用Artisan為Laravel應用程式提供服務

用Artisan為Laravel應用程式提供服務

從你的網路瀏覽器, 導航到正在執行的應用程式,http://127.0.0.1:8000. 該應用程式將顯示Laravel歡迎頁面的預設路徑。

Laravel應用程式的歡迎頁面

Laravel應用程式的歡迎頁面

如何新增Laravel Scout到應用程式中

在你的終端,輸入命令來啟用Composer PHP包管理器來新增Laravel Scout到專案中。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
composer require laravel/scout
composer require laravel/scout
composer require laravel/scout

接下來,使用vendor:publish命令釋出Scout配置檔案。該命令將釋出 scout.php 配置檔案到你的應用程式的config目錄。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
 php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

現在,修改模板.env檔案,使其包含一個 SCOUT_QUEUE 的布林值。

SCOUT_QUEUE 值將允許Scout排隊操作,提供更好的響應時間。沒有它,像Meilisearch這樣的Scout驅動不會立即反映新記錄。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_QUEUE=true
SCOUT_QUEUE=true
SCOUT_QUEUE=true

此外,修改.env檔案中的 DB_HOST 變數,使其指向你的本地主機,以便在Docker容器中使用MySQL資料庫

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DB_HOST=127.0.0.1
DB_HOST=127.0.0.1
DB_HOST=127.0.0.1

如何標記一個模型和配置索引

Scout預設不會啟用可搜尋的資料模型。你必須使用 Laravel/Scout/Searchable 特性將模型明確標記為可搜尋。

你將從為一個演示的 Train 應用程式建立一個資料模型開始,並將其標記為可搜尋。

如何建立一個模型

對於 Train 應用程式,你要儲存每個可用的火車的佔位符名稱。

執行下面的Artisan命令來生成遷移,並將其命名為 create_trains_table

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan make:migration create_trains_table
php artisan make:migration create_trains_table
php artisan make:migration create_trains_table

製作一個名為create_trains_table的遷移檔案

製作一個名為create_trains_table的遷移檔案

遷移將在一個檔案中生成,該檔案的名稱結合了指定的名稱和當前的時間戳。

開啟位於database/migrations/目錄中的遷移檔案。

要新增一個標題列,請在第17行的 id() 列後面新增以下程式碼。該程式碼將新增一個標題列。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$table->string('title');
$table->string('title');
$table->string('title');

要應用遷移,請執行以下命令。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan migrate
php artisan migrate
php artisan migrate

應用Artisan遷移

應用Artisan遷移

執行資料庫遷移後, 在app/Models/目錄下建立一個名為Train.php的檔案.

如何新增LaravelScoutSearchable特性

通過新增 Laravel/Scout/Searchable 特性來標記 Train 模型的搜尋功能,如下圖所示。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Train extends Model
{
use Searchable;
public $fillable = ['title'];
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Train extends Model { use Searchable; public $fillable = ['title'];
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Train extends Model
{
use Searchable;
public $fillable = ['title'];

另外,你需要通過覆蓋 searchable 方法來配置搜尋索引。Scout的預設行為將持久化模型以匹配模型表的名稱。

因此,在Train.php檔案中,在上一個區塊的程式碼下面新增以下程式碼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/**
* Retrieve the index name for the model.
*
* @return string
*/
public function searchableAs()
{
return 'trains_index';
}
}
/** * Retrieve the index name for the model. * * @return string */ public function searchableAs() { return 'trains_index'; } }
/**
* Retrieve the index name for the model.
*
* @return string
*/
public function searchableAs()
{
return 'trains_index';
}
}

如何使用Algolia和Scout

對於Laravel Scout的第一次全文搜尋,你將使用Algolia驅動。Algolia是一個軟體即服務(SaaS)平臺,用於搜尋大量的資料。它為開發人員提供了一個網路儀表板來管理他們的搜尋索引,以及一個強大的API,你可以通過你喜歡的程式語言的軟體開發工具包(SDK)來訪問。

在Laravel應用程式中,你將使用PHP的Algolia客戶端包

如何設定Algolia

首先, 你必須為你的應用程式安裝Algolia PHP搜尋客戶端包.

執行下面的命令.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
composer require algolia/algoliasearch-client-php
composer require algolia/algoliasearch-client-php
composer require algolia/algoliasearch-client-php

接下來,你必須在.env檔案中設定你的應用ID和Algolia的Secret API Key憑證。

使用你的網路瀏覽器,導航到你的Algolia儀表板,以獲得應用ID和祕密API Key憑證。

點選左側邊欄底部的 “Settings“,進入Settings頁面。

接下來,在Team and Access部分點選API Keys,檢視你的Algolia賬戶的金鑰。

Algolia Cloud上的API Keys頁面

Algolia Cloud上的API Keys頁面

在API Keys頁面, 注意Application IDAdmin API Key值. 你將使用這些憑證來驗證Laravel應用程式和Algolia之間的連線。

應用程式ID和管理員API金鑰

應用程式ID和管理員API金鑰

使用你的程式碼編輯器將下面的程式碼新增到你的.env檔案中,並將佔位符替換為相應的Algolia API祕密。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ALGOLIA_APP_ID=APPLICATION_ID
ALGOLIA_SECRET=ADMIN_API_KEY
ALGOLIA_APP_ID=APPLICATION_ID ALGOLIA_SECRET=ADMIN_API_KEY
ALGOLIA_APP_ID=APPLICATION_ID
ALGOLIA_SECRET=ADMIN_API_KEY

另外,用下面的程式碼替換 SCOUT_DRIVER 變數,將其值從 meilisearch 改為 algolia 。改變這個值將指示Scout使用Algolia驅動。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_DRIVER=algolia
SCOUT_DRIVER=algolia
SCOUT_DRIVER=algolia

如何建立應用程式的控制器

app/Http/Controllers/目錄下,建立一個TrainSearchController.php檔案,為應用程式儲存一個控制器。該控制器將列出並新增資料到 Train 模型中。

TrainSearchController.php檔案中新增以下程式碼塊來建立控制器。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Train;
class TrainSearchController extends Controller
{
/**
* Get the index name for the model.
*
* @return string
*/
public function index(Request $request)
{
if($request->has('titlesearch')){
$trains = Train::search($request->titlesearch)
->paginate(6);
}else{
$trains = Train::paginate(6);
}
return view('Train-search',compact('trains'));
}
/**
* Get the index name for the model.
*
* @return string
*/
public function create(Request $request)
{
$this->validate($request,['title'=>'required']);
$trains = Train::create($request->all());
return back();
}
}
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Models\Train; class TrainSearchController extends Controller { /** * Get the index name for the model. * * @return string */ public function index(Request $request) { if($request->has('titlesearch')){ $trains = Train::search($request->titlesearch) ->paginate(6); }else{ $trains = Train::paginate(6); } return view('Train-search',compact('trains')); } /** * Get the index name for the model. * * @return string */ public function create(Request $request) { $this->validate($request,['title'=>'required']); $trains = Train::create($request->all()); return back(); } }
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Train;
class TrainSearchController extends Controller
{
/**
* Get the index name for the model.
*
* @return string
*/
public function index(Request $request)
{
if($request->has('titlesearch')){
$trains = Train::search($request->titlesearch)
->paginate(6);
}else{
$trains = Train::paginate(6);
}
return view('Train-search',compact('trains'));
}
/**
* Get the index name for the model.
*
* @return string
*/
public function create(Request $request)
{
$this->validate($request,['title'=>'required']);
$trains = Train::create($request->all());
return back();
}
}

如何建立應用程式的路由

在這一步,你將建立列出和新增新列車到資料庫的路線。

開啟你的routes/web.php檔案,用下面的程式碼塊替換現有程式碼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TrainSearchController;
Route::get('/', function () {
return view('welcome');
});
Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists');
Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TrainSearchController; Route::get('/', function () { return view('welcome'); }); Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists'); Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TrainSearchController;
Route::get('/', function () {
return view('welcome');
});
Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists');
Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');

上面的程式碼在應用程式中定義了兩條路線。 /trains-lists 路由的 GET 請求列出所有儲存的火車資料。 /create-item 路由的 POST 請求建立新的列車資料。

如何建立應用程式的檢視

resources/views/目錄下建立一個檔案,命名為Train-search.blade.php。該檔案將顯示搜尋功能的使用者介面。

將下面的程式碼塊內容新增到Train-search.blade.php檔案中,為搜尋功能建立一個單頁。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!DOCTYPE html>
<html>
<head>
<title>Laravel - Laravel Scout Algolia Search Example</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/>
<form method="POST" action="{{ route('create-item') }}" autocomplete="off">
@if(count($errors))
<div class="alert alert-danger">
<strong>Whoops!</strong> There is an error with your input.
<br/>
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="row">
<div class="col-md-6">
<div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
<input type="text" id="title" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}">
<span class="text-danger">{{ $errors->first('title') }}</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Create New Train</button>
</div>
</div>
</div>
</form>
<div class="panel panel-primary">
<div class="panel-heading">Train Management</div>
<div class="panel-body">
<form method="GET" action="{{ route('trains-lists') }}">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Search</button>
</div>
</div>
</div>
</form>
<table class="table">
<thead>
<th>Id</th>
<th>Train Title</th>
<th>Creation Date</th>
<th>Updated Date</th>
</thead>
<tbody>
@if($trains->count())
@foreach($trains as $key => $item)
<tr>
<td>{{ ++$key }}</td>
<td>{{ $item->title }}</td>
<td>{{ $item->created_at }}</td>
<td>{{ $item->updated_at }}</td>
</tr>
@endforeach
@else
<tr>
<td colspan="4">No train data available</td>
</tr>
@endif
</tbody>
</table>
{{ $trains->links() }}
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html> <html> <head> <title>Laravel - Laravel Scout Algolia Search Example</title> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> <h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/> <form method="POST" action="{{ route('create-item') }}" autocomplete="off"> @if(count($errors)) <div class="alert alert-danger"> <strong>Whoops!</strong> There is an error with your input. <br/> <ul> @foreach($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <input type="hidden" name="_token" value="{{ csrf_token() }}"> <div class="row"> <div class="col-md-6"> <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}"> <input type="text" id="title" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}"> <span class="text-danger">{{ $errors->first('title') }}</span> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Create New Train</button> </div> </div> </div> </form> <div class="panel panel-primary"> <div class="panel-heading">Train Management</div> <div class="panel-body"> <form method="GET" action="{{ route('trains-lists') }}"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}"> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Search</button> </div> </div> </div> </form> <table class="table"> <thead> <th>Id</th> <th>Train Title</th> <th>Creation Date</th> <th>Updated Date</th> </thead> <tbody> @if($trains->count()) @foreach($trains as $key => $item) <tr> <td>{{ ++$key }}</td> <td>{{ $item->title }}</td> <td>{{ $item->created_at }}</td> <td>{{ $item->updated_at }}</td> </tr> @endforeach @else <tr> <td colspan="4">No train data available</td> </tr> @endif </tbody> </table> {{ $trains->links() }} </div> </div> </div> </body> </html>
<!DOCTYPE html>
<html>
<head>
<title>Laravel - Laravel Scout Algolia Search Example</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/>
<form method="POST" action="{{ route('create-item') }}" autocomplete="off">
@if(count($errors))
<div class="alert alert-danger">
<strong>Whoops!</strong> There is an error with your input.
<br/>
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="row">
<div class="col-md-6">
<div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
<input type="text" id="title" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}">
<span class="text-danger">{{ $errors->first('title') }}</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Create New Train</button>
</div>
</div>
</div>
</form>
<div class="panel panel-primary">
<div class="panel-heading">Train Management</div>
<div class="panel-body">
<form method="GET" action="{{ route('trains-lists') }}">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Search</button>
</div>
</div>
</div>
</form>
<table class="table">
<thead>
<th>Id</th>
<th>Train Title</th>
<th>Creation Date</th>
<th>Updated Date</th>
</thead>
<tbody>
@if($trains->count())
@foreach($trains as $key => $item)
<tr>
<td>{{ ++$key }}</td>
<td>{{ $item->title }}</td>
<td>{{ $item->created_at }}</td>
<td>{{ $item->updated_at }}</td>
</tr>
@endforeach
@else
<tr>
<td colspan="4">No train data available</td>
</tr>
@endif
</tbody>
</table>
{{ $trains->links() }}
</div>
</div>
</div>
</body>
</html>

上面的HTML程式碼包含一個表單元素,其中有一個輸入欄位和一個按鈕,用於在將列車儲存到資料庫之前輸入列車的標題。該程式碼還包含一個HTML表格,顯示資料庫中的列車條目的idtitlecreated_at, 和 updated_at等詳細資訊。

要檢視該頁面,請從你的網路瀏覽器中導航到http://127.0.0.1:8000/trains-lists。

Train模型資料

Train模型資料

目前資料庫是空的,所以您需要在輸入欄中輸入一個演示train的標題,然後點選Create New Train來儲存。

插入一個新的train條目

插入一個新的train條目

要使用搜尋功能,從任何已儲存的列車標題中鍵入一個關鍵詞到Enter Title For Search的輸入欄位中,然後點選Search

如下圖所示,只有標題中包含關鍵詞的搜尋條目才會顯示。

使用搜尋功能查詢train條目

使用搜尋功能查詢train條目

使用Laravel Scout的Meilisearch

Meilisearch是一個開源的搜尋引擎,專注於速度、效能和改進的開發者體驗。它與Algolia共享一些功能,使用相同的演算法、資料結構和研究 – 但使用不同的程式語言

開發人員可以在他們的企業內部或雲基礎設施中建立和自我託管Meilisearch例項。Meilisearch也有一個類似於Algolia的測試版雲產品,供那些想使用該產品而不管理其基礎設施的開發者使用。

在本教程中, 你已經有一個本地的Meilisearch例項在你的Docker容器中執行. 現在你將擴充套件Laravel Scout的功能來使用Meilisearch例項.

要新增Meilisearch到Laravel應用程式, 在你的專案終端執行以下命令.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
composer require meilisearch/meilisearch-php
composer require meilisearch/meilisearch-php
composer require meilisearch/meilisearch-php

接下來, 你需要修改.env檔案中的Meilisearch變數來配置它.

將.env檔案中的 SCOUT_DRIVERMEILISEARCH_HOST, 和 MEILISEARCH_KEY 變數替換為以下內容。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=LockKey
SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://127.0.0.1:7700 MEILISEARCH_KEY=LockKey
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=LockKey

SCOUT_DRIVER 鍵指定Scout應該使用的驅動程式,而 MEILISEARCH_HOST 代表你的Meilisearch例項執行的域。儘管在開發過程中不需要,但建議在生產中新增 MEILISEARCH_KEY

注意:當使用Meilisearch作為你的首選驅動時,註釋掉Algolia ID和Secret。

在完成了.env的配置後,你應該使用下面的Artisan命令來索引你先前存在的記錄。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan scout:import "App\Models\Train"
php artisan scout:import "App\Models\Train"
php artisan scout:import "App\Models\Train"

Laravel Scout與資料庫引擎

Scout的資料庫引擎可能最適合於使用較小的資料庫或管理不密集的工作負載的應用程式。目前, 該資料庫引擎支援PostgreSQL和MySQL.

這個引擎使用 “where-like” 條款和針對你現有資料庫的全文索引,使它能夠找到最相關的搜尋結果。在使用資料庫引擎時,你不需要對你的記錄進行索引。

要使用資料庫引擎,你必須將你的 SCOUT_DRIVER .env變數設定為資料庫。

開啟Laravel應用程式中的.env檔案,改變SCOUT_DRIVER變數的值。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_DRIVER = database
SCOUT_DRIVER = database
SCOUT_DRIVER = database

將你的驅動程式改為資料庫後, Scout將切換到使用資料庫引擎進行全文搜尋.

Collection引擎與Laravel Scout

除了資料庫引擎之外,Scout還提供了一個集合引擎。這個引擎使用 “where” 條款和集合過濾來提取最相關的搜尋結果。

與資料庫引擎不同, 收集引擎支援所有Laravel也支援的關係型資料庫.

你可以通過將 SCOUT_DRIVER 環境變數設定為 collection ,或者在Scout配置檔案中手動指定集合驅動來使用集合引擎。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_DRIVER = collection
SCOUT_DRIVER = collection
SCOUT_DRIVER = collection

使用Elasticsearch進行資源管理

憑藉Elasticsearch查詢的優勢,Explorer是Laravel Scout的一個現代Elasticsearch驅動。它提供了一個相容的Scout驅動和好處,如實時儲存,搜尋和分析大量的資料。使用Laravel的Elasticsearch可以在幾毫秒內提供結果。

要在你的Laravel應用程式中使用Elasticsearch Explorer驅動,你需要配置Laravel-Scout指令碼生成的boilerplate模板docker-compose.yml檔案。你將新增Elasticsearch的額外配置,並重新啟動容器。

開啟你的docker-compose.yml檔案,將其內容替換為以下內容。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.1/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
- meilisearch
- mailhog
- selenium
- pgsql
- elasticsearch
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
elasticsearch:
image: 'elasticsearch:7.13.4'
environment:
- discovery.type=single-node
ports:
- '9200:9200'
- '9300:9300'
volumes:
- 'sailelasticsearch:/usr/share/elasticsearch/data'
networks:
- sail
kibana:
image: 'kibana:7.13.4'
environment:
- elasticsearch.hosts=http://elasticsearch:9200
ports:
- '5601:5601'
networks:
- sail
depends_on:
- elasticsearch
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
pgsql:
image: 'postgres:13'
ports:
- '${FORWARD_DB_PORT:-5432}:5432'
environment:
PGPASSWORD: '${DB_PASSWORD:-secret}'
POSTGRES_DB: '${DB_DATABASE}'
POSTGRES_USER: '${DB_USERNAME}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- 'sailpgsql:/var/lib/postgresql/data'
networks:
- sail
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"]
retries: 3
timeout: 5s
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
volumes:
- 'sail-meilisearch:/meili_data'
networks:
- sail
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
selenium:
image: 'selenium/standalone-chrome'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
- '/dev/shm:/dev/shm'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
sail-meilisearch:
driver: local
sailpgsql:
driver: local
sailelasticsearch:
driver: local
# For more information: https://laravel.com/docs/sail version: '3' services: laravel.test: build: context: ./vendor/laravel/sail/runtimes/8.1 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.1/app extra_hosts: - 'host.docker.internal:host-gateway' ports: - '${APP_PORT:-80}:80' - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql - redis - meilisearch - mailhog - selenium - pgsql - elasticsearch mysql: image: 'mysql/mysql-server:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: - 'sail-mysql:/var/lib/mysql' - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] retries: 3 timeout: 5s elasticsearch: image: 'elasticsearch:7.13.4' environment: - discovery.type=single-node ports: - '9200:9200' - '9300:9300' volumes: - 'sailelasticsearch:/usr/share/elasticsearch/data' networks: - sail kibana: image: 'kibana:7.13.4' environment: - elasticsearch.hosts=http://elasticsearch:9200 ports: - '5601:5601' networks: - sail depends_on: - elasticsearch redis: image: 'redis:alpine' ports: - '${FORWARD_REDIS_PORT:-6379}:6379' volumes: - 'sail-redis:/data' networks: - sail healthcheck: test: ["CMD", "redis-cli", "ping"] retries: 3 timeout: 5s pgsql: image: 'postgres:13' ports: - '${FORWARD_DB_PORT:-5432}:5432' environment: PGPASSWORD: '${DB_PASSWORD:-secret}' POSTGRES_DB: '${DB_DATABASE}' POSTGRES_USER: '${DB_USERNAME}' POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' volumes: - 'sailpgsql:/var/lib/postgresql/data' networks: - sail healthcheck: test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] retries: 3 timeout: 5s meilisearch: image: 'getmeili/meilisearch:latest' ports: - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' volumes: - 'sail-meilisearch:/meili_data' networks: - sail healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"] retries: 3 timeout: 5s mailhog: image: 'mailhog/mailhog:latest' ports: - '${FORWARD_MAILHOG_PORT:-1025}:1025' - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' networks: - sail selenium: image: 'selenium/standalone-chrome' extra_hosts: - 'host.docker.internal:host-gateway' volumes: - '/dev/shm:/dev/shm' networks: - sail networks: sail: driver: bridge volumes: sail-mysql: driver: local sail-redis: driver: local sail-meilisearch: driver: local sailpgsql: driver: local sailelasticsearch: driver: local
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.1/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
- meilisearch
- mailhog
- selenium
- pgsql
- elasticsearch
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
elasticsearch:
image: 'elasticsearch:7.13.4'
environment:
- discovery.type=single-node
ports:
- '9200:9200'
- '9300:9300'
volumes:
- 'sailelasticsearch:/usr/share/elasticsearch/data'
networks:
- sail
kibana:
image: 'kibana:7.13.4'
environment:
- elasticsearch.hosts=http://elasticsearch:9200
ports:
- '5601:5601'
networks:
- sail
depends_on:
- elasticsearch
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
pgsql:
image: 'postgres:13'
ports:
- '${FORWARD_DB_PORT:-5432}:5432'
environment:
PGPASSWORD: '${DB_PASSWORD:-secret}'
POSTGRES_DB: '${DB_DATABASE}'
POSTGRES_USER: '${DB_USERNAME}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- 'sailpgsql:/var/lib/postgresql/data'
networks:
- sail
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"]
retries: 3
timeout: 5s
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
volumes:
- 'sail-meilisearch:/meili_data'
networks:
- sail
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider",  "http://localhost:7700/health"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
selenium:
image: 'selenium/standalone-chrome'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
- '/dev/shm:/dev/shm'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
sail-meilisearch:
driver: local
sailpgsql:
driver: local
sailelasticsearch:
driver: local

接下來,執行下面的命令,提取你新增到docker-compose.yml檔案中的新Elasticsearch映象。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker-compose up
docker-compose up
docker-compose up

然後,執行下面的Composer命令,將資源管理器安裝到專案中。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
composer require jeroen-g/explorer
composer require jeroen-g/explorer
composer require jeroen-g/explorer

你還需要為資源管理器驅動程式建立一個配置檔案。

執行下面的Artisan命令,生成一個explorer.config檔案用於儲存配置。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php artisan vendor:publish --tag=explorer.config
php artisan vendor:publish --tag=explorer.config
php artisan vendor:publish --tag=explorer.config

上面生成的配置檔案將在/config目錄下可用。

在你的config/explorer.php檔案中,你可以使用 indexes 鍵引用你的模型。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
'indexes' => [
\App\Models\Train::class
],
'indexes' => [ \App\Models\Train::class ],
'indexes' => [
\App\Models\Train::class
],

.env檔案中的 SCOUT_DRIVER 變數的值改為 elastic ,以配置Scout使用資源管理器驅動程式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SCOUT_DRIVER = elastic
SCOUT_DRIVER = elastic
SCOUT_DRIVER = elastic

在這一點上,你將通過實現Explorer介面和重寫 mappableAs() 方法在 Train 模型中使用Explorer。

開啟App > Models目錄下的Train.php檔案,用下面的程式碼替換現有程式碼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;
class Train extends Model implements Explored
{
use HasFactory;
use Searchable;
protected $fillable = ['title'];
public function mappableAs(): array
{
return [
'id'=>$this->Id,
'title' => $this->title,
];
}
}
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use JeroenG\Explorer\Application\Explored; use Laravel\Scout\Searchable; class Train extends Model implements Explored { use HasFactory; use Searchable; protected $fillable = ['title']; public function mappableAs(): array { return [ 'id'=>$this->Id, 'title' => $this->title, ]; } }
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;
class Train extends Model implements Explored
{
use HasFactory;
use Searchable;
protected $fillable = ['title'];
public function mappableAs(): array
{
return [
'id'=>$this->Id,
'title' => $this->title,
];
}
}

有了上面新增的程式碼,你現在可以使用資源管理器來搜尋 Train 模型中的文字。

小結

對於PHP開發者來說, Laravel和像Scout這樣的附加元件使得整合快速,強大的全文搜尋功能變得輕而易舉。有了資料庫引擎, 採集引擎, 以及Meilisearch和Elasticsearch的功能, 你可以與你的應用程式的資料庫互動, 並在幾毫秒內實現高階搜尋機制.

無縫地管理和更新你的資料庫意味著你的使用者獲得最佳的體驗,同時你的程式碼保持乾淨和高效。

評論留言