> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Scout

> 為 Eloquent model 加入全文搜尋功能的官方套件。支援 Meilisearch、Algolia、Typesense 與資料庫引擎，透過 model observer 自動同步索引。

## 前言

**Laravel Scout** 是為 [Eloquent model](/zh-TW/eloquent) 加入全文搜尋功能的簡潔 driver-based 解決方案。透過 model observer 自動同步 Eloquent 記錄與搜尋索引。

Scout 內建 `database` 引擎，使用 MySQL / PostgreSQL 的全文索引與 `LIKE` 子句直接搜尋資料庫，無需外部服務。若需要在大型正式環境中容錯拼字、多面向搜尋或地理搜尋，外部引擎會派上用場。

### 支援的引擎一覽

| 引擎           | 特徵                       | 用途      |
| ------------ | ------------------------ | ------- |
| `database`   | MySQL / PostgreSQL 的全文索引 | 大多數應用   |
| `collection` | 以 PHP 進行過濾（SQLite 也可）    | 本機開發、測試 |
| Meilisearch  | 開源、容錯拼字、高速               | 正式環境    |
| Algolia      | 雲端 SaaS、進階功能             | 正式環境    |
| Typesense    | 開源、支援向量搜尋                | 正式環境    |

```mermaid theme={null}
flowchart LR
  APP["Laravel 應用<br>(Eloquent model)"] -->|"save / delete"| SCOUT["Laravel Scout<br>(model observer)"]
  SCOUT -->|"索引同步"| ENGINE["搜尋引擎<br>Meilisearch / Algolia / Typesense"]
  USER["使用者"] -->|"Model::search()"| APP
  ENGINE -->|"搜尋結果"| APP
```

## 安裝

以 Composer 安裝套件。

```shell theme={null}
composer require laravel/scout
```

安裝後執行 `vendor:publish` 指令發布設定檔。會產生 `config/scout.php`。

```shell theme={null}
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
```

最後在欲設為可搜尋的 model 加入 `Laravel\Scout\Searchable` trait。此 trait 會登記 model observer，並啟用與搜尋 driver 的自動同步。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;
}
```

### Queue 設定

若使用 `database` 或 `collection` 以外的引擎，強烈建議在使用 Scout 前先設定 [queue driver](/zh-TW/queues)。啟動 queue worker 可讓索引同步操作在背景執行，大幅提升 Web 介面回應速度。

將 `config/scout.php` 的 `queue` 選項設為 `true`。

```php theme={null}
'queue' => true,
```

也可指定連線名稱與 queue 名稱。

```php theme={null}
'queue' => [
    'connection' => 'redis',
    'queue' => 'scout'
],
```

設定後啟動專用的 queue worker。

```shell theme={null}
php artisan queue:work redis --queue=scout
```

### 使用唯一性 Job

在寫入頻繁的應用中，可能想避免同一筆 model 有重複的 queue job 被登記。可在 `config/scout.php` 註冊 `MakeSearchableUniquely` 與 `RemoveFromSearchUniquely` job 類別以使用唯一性索引 job。通常在服務提供者的 `boot` 方法中設定。

```php theme={null}
use Laravel\Scout\Jobs\MakeSearchableUniquely;
use Laravel\Scout\Jobs\RemoveFromSearchUniquely;
use Laravel\Scout\Scout;

Scout::makeSearchableUsing(MakeSearchableUniquely::class);
Scout::removeFromSearchUsing(RemoveFromSearchUniquely::class);
```

這些 job 會使用 Laravel 的[唯一性 job lock](#使用唯一性-job)，避免重複分派針對相同 model 記錄的索引操作。

## Driver 前置條件

### Algolia

使用 Algolia driver 時，在 `config/scout.php` 設定 `id` 與 `secret` 認證資訊，並安裝 Algolia PHP SDK。

```shell theme={null}
composer require algolia/algoliasearch-client-php
```

在 `.env` 檔加入認證資訊。

```ini theme={null}
ALGOLIA_APP_ID=your-app-id
ALGOLIA_SECRET=your-secret-key
```

#### 索引設定

Algolia 可在 `config/scout.php` 管理索引設定。

```php theme={null}
use App\Models\User;

'algolia' => [
    'id' => env('ALGOLIA_APP_ID', ''),
    'secret' => env('ALGOLIA_SECRET', ''),
    'index-settings' => [
        User::class => [
            'searchableAttributes' => ['id', 'name', 'email'],
            'attributesForFaceting' => ['filterOnly(email)'],
        ],
    ],
],
```

設定後執行 `scout:sync-index-settings` 指令將設定同步到 Algolia。

```shell theme={null}
php artisan scout:sync-index-settings
```

### Meilisearch

[Meilisearch](https://www.meilisearch.com) 是高速的開源搜尋引擎。本機開發最簡單的方式是使用 [Laravel Sail](https://laravel.com/docs/sail#meilisearch) 的 Docker。

```shell theme={null}
# 使用 Laravel Sail 時
./vendor/bin/sail up -d meilisearch
```

若不用 Sail，也可用 Docker 直接啟動。

```shell theme={null}
docker run -it --rm \
    -p 7700:7700 \
    getmeili/meilisearch:latest \
    meilisearch --master-key="masterKey"
```

安裝 Meilisearch PHP SDK。

```shell theme={null}
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
```

在 `.env` 檔設定 driver 與 host。

```ini theme={null}
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKey
```

<Warning>
  升級 Scout 時，也務必確認 Meilisearch 服務本身的[破壞性變更](https://github.com/meilisearch/Meilisearch/releases)。
</Warning>

#### 索引設定（Meilisearch）

Meilisearch 需將以 `where()` 過濾的欄位事先登記在 `filterableAttributes`，以 `orderBy()` 排序的欄位登記在 `sortableAttributes`。

```php theme={null}
use App\Models\User;

'meilisearch' => [
    'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
    'key' => env('MEILISEARCH_KEY', null),
    'index-settings' => [
        User::class => [
            'filterableAttributes' => ['id', 'name', 'email'],
            'sortableAttributes' => ['created_at'],
        ],
    ],
],
```

請注意數值欄位的資料型別。Meilisearch 只能對型別正確的資料執行過濾操作（如 `>`、`<`）。

```php theme={null}
public function toSearchableArray(): array
{
    return [
        'id' => (int) $this->id,
        'name' => $this->name,
        'price' => (float) $this->price,
    ];
}
```

設定後執行 `scout:sync-index-settings` 指令。

```shell theme={null}
php artisan scout:sync-index-settings
```

### Typesense

[Typesense](https://typesense.org) 是高速的開源搜尋引擎，支援關鍵字搜尋、語意搜尋、地理搜尋與向量搜尋。

```shell theme={null}
composer require typesense/typesense-php
```

在 `.env` 檔設定連線資訊。

```ini theme={null}
SCOUT_DRIVER=typesense
TYPESENSE_API_KEY=masterKey
TYPESENSE_HOST=localhost
TYPESENSE_PORT=8108
TYPESENSE_PATH=
TYPESENSE_PROTOCOL=http
```

使用 Typesense 時，需在 `toSearchableArray` 方法將 model 的主鍵轉為字串、將建立時間轉為 UNIX timestamp。

```php theme={null}
public function toSearchableArray(): array
{
    return array_merge($this->toArray(), [
        'id' => (string) $this->id,
        'created_at' => $this->created_at->timestamp,
    ]);
}
```

### 資料庫／集合引擎

不需外部服務就想加入搜尋時的最佳選項。

**資料庫引擎**使用 MySQL / PostgreSQL 的全文索引與 `LIKE` 子句。對多數應用來說已足夠。

```ini theme={null}
SCOUT_DRIVER=database
```

**集合引擎**在 PHP 內過濾，能在包括 SQLite 在內的所有 Laravel 支援的資料庫上運作。適合本機開發、測試、小資料集。

```ini theme={null}
SCOUT_DRIVER=collection
```

<Info>
  資料庫引擎與外部引擎不同，不需手動管理索引。直接搜尋資料庫資料表。
</Info>

## Searchable trait

### 自訂 toSearchableArray()

預設會把 model 的 `toArray()` 全部資料存入搜尋索引。要自訂同步到索引的資料，覆寫 `toSearchableArray` 方法。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;

    /**
     * 取得 model 可索引的資料陣列。
     *
     * @return array<string, mixed>
     */
    public function toSearchableArray(): array
    {
        $array = $this->toArray();

        // 自訂資料...

        return $array;
    }
}
```

### 自訂索引名稱

預設使用 model 的資料表名稱（複數）作為索引名稱。可覆寫 `searchableAs` 方法自訂。

```php theme={null}
public function searchableAs(): string
{
    return 'posts_index';
}
```

### 資料庫引擎的搜尋策略

資料庫引擎可以用 PHP 屬性為每個欄位指定高效的搜尋策略。

```php theme={null}
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;

#[SearchUsingPrefix(['id', 'email'])]
#[SearchUsingFullText(['bio'])]
public function toSearchableArray(): array
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'bio' => $this->bio,
    ];
}
```

<Warning>
  使用 `SearchUsingFullText` 前，請確認目標欄位已設定[全文索引](/zh-TW/migrations)。
</Warning>

### 條件性設為可搜尋

若只想在特定條件下讓 model 可搜尋，定義 `shouldBeSearchable` 方法。

```php theme={null}
/**
 * 決定是否要將此 model 設為可搜尋。
 */
public function shouldBeSearchable(): bool
{
    return $this->isPublished();
}
```

<Warning>
  `shouldBeSearchable` 在資料庫引擎下無效。若要在資料庫引擎下達到相同行為，請使用[where 子句](#過濾與排序)。
</Warning>

## 索引管理

<Info>
  本節指令主要適用於使用 Algolia、Meilisearch、Typesense 等第三方引擎時。資料庫引擎不需管理索引。
</Info>

### 匯入既有記錄

在既有專案導入 Scout 時，可用 `scout:import` 指令將既有記錄匯入索引。

```shell theme={null}
php artisan scout:import "App\Models\Post"
```

也可用 queue 在背景匯入。

```shell theme={null}
php artisan scout:queue-import "App\Models\Post" --chunk=500
```

### 清空索引

要從搜尋索引移除 model 的所有記錄，使用 `scout:flush`。

```shell theme={null}
php artisan scout:flush "App\Models\Post"
```

### 暫停索引

在 Eloquent 操作中若想暫時停止與搜尋索引的同步，使用 `withoutSyncingToSearch`。

```php theme={null}
use App\Models\Order;

Order::withoutSyncingToSearch(function () {
    // 此區塊內的 model 操作不會同步到搜尋索引
});
```

### 手動新增、移除記錄

可用查詢將 model 集合加到索引。

```php theme={null}
// 加入查詢結果
Order::where('price', '>', 100)->searchable();

// 透過 relation 加入
$user->orders()->searchable();
```

要從索引移除記錄，使用 `unsearchable`。

```php theme={null}
Order::where('price', '>', 100)->unsearchable();
```

`delete` model 時會自動從索引中移除。

## 搜尋

用 `search` 方法搜尋 model。連結 `get` 取得 Eloquent model 的 collection。

```php theme={null}
use App\Models\Order;

$orders = Order::search('Star Trek')->get();
```

直接從控制器或路由回傳會自動轉為 JSON。

```php theme={null}
use Illuminate\Http\Request;

Route::get('/search', function (Request $request) {
    return Order::search($request->search)->get();
});
```

若需要原始搜尋結果，可用 `raw` 方法。

```php theme={null}
$orders = Order::search('Star Trek')->raw();
```

### 分頁

可用 `paginate` 方法對搜尋結果分頁。與一般 Eloquent 查詢的分頁機制相同。

```php theme={null}
$orders = Order::search('Star Trek')->paginate();

// 指定每頁筆數
$orders = Order::search('Star Trek')->paginate(15);
```

資料庫引擎也可使用 `simplePaginate`。由於不取得總筆數，適合大型資料集。

```php theme={null}
$orders = Order::search('Star Trek')->simplePaginate(15);
```

Blade 樣板顯示範例：

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

{{ $orders->links() }}
```

## 過濾與排序

用 `where` 方法可在搜尋查詢加入過濾條件。

```php theme={null}
use App\Models\Order;

// 等值過濾
$orders = Order::search('Star Trek')->where('user_id', 1)->get();

// 陣列中任一相符
$orders = Order::search('Star Trek')->whereIn('status', ['open', 'paid'])->get();

// 陣列中皆不相符
$orders = Order::search('Star Trek')->whereNotIn('status', ['closed'])->get();
```

<Warning>
  使用 Meilisearch 時，使用 `where` 前需先設定[可過濾屬性](#索引設定meilisearch)。
</Warning>

也能用 `query` 方法自訂 Eloquent 查詢。

```php theme={null}
use Illuminate\Database\Eloquent\Builder;

$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with('invoices'))
    ->get();
```

## Eager Loading

使用 Scout 時，會先從搜尋引擎取得 ID 清單，再以 Eloquent 取得 model。為避免 N+1 問題，可在 `query` 方法中用 `with()` 指定 eager loading。

```php theme={null}
use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;

$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with(['invoices', 'user']))
    ->get();
```

批次匯入時要 eager load 關聯，可定義 `makeAllSearchableUsing` 方法。

```php theme={null}
use Illuminate\Database\Eloquent\Builder;

protected function makeAllSearchableUsing(Builder $query): Builder
{
    return $query->with('author');
}
```

<Warning>
  `makeAllSearchableUsing` 有時無法用於使用 queue 的批次匯入。當 queue job 處理 model collection 時，關聯不會被還原。
</Warning>

## 軟刪除

若被索引的 model 使用[軟刪除](/zh-TW/eloquent)，且想同時搜尋已刪除的 model，將 `config/scout.php` 的 `soft_delete` 選項設為 `true`。

```php theme={null}
'soft_delete' => true,
```

啟用後可用 `withTrashed` 或 `onlyTrashed` 搜尋已刪除記錄。

```php theme={null}
// 包含已刪除
$orders = Order::search('Star Trek')->withTrashed()->get();

// 只搜尋已刪除
$orders = Order::search('Star Trek')->onlyTrashed()->get();
```

## 自訂引擎

若內建搜尋引擎不符需求，可實作自訂引擎。自訂引擎需繼承 `Laravel\Scout\Engines\Engine` 抽象類別，並實作以下 8 個方法。

```php theme={null}
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(Builder $builder, $results, $model);
abstract public function getTotalCount($results);
abstract public function flush($model);
```

可參考 `Laravel\Scout\Engines\AlgoliaEngine` 類別作為實作參考。

建立好的自訂引擎，在 `App\Providers\AppServiceProvider` 的 `boot` 方法中註冊到 Scout。

```php theme={null}
use App\ScoutExtensions\MySqlSearchEngine;
use Laravel\Scout\EngineManager;

public function boot(): void
{
    resolve(EngineManager::class)->extend('mysql', function () {
        return new MySqlSearchEngine;
    });
}
```

註冊後，在 `config/scout.php` 指定為 driver。

```php theme={null}
'driver' => 'mysql',
```

## 相關頁面

<Card title="Eloquent ORM" icon="database" href="/zh-TW/eloquent">
  複習 Eloquent model 的基本用法。
</Card>

<Card title="Eloquent Relationships" icon="link" href="/zh-TW/eloquent-relationships">
  確認 relationship 的定義與 eager loading。
</Card>

<Card title="Queue" icon="clock" href="/zh-TW/queues">
  Scout 可搭配 queue 在背景更新索引。
</Card>


## Related topics

- [搜尋](/zh-TW/search.md)
- [MongoDB](/zh-TW/mongodb.md)
- [Laravel Sail](/zh-TW/sail.md)
- [2026 年 3 月 Laravel 更新](/zh-TW/blog/changelog/202603.md)
- [Laravel Telescope](/zh-TW/telescope.md)
