Zum Hauptinhalt springen

Einführung

Laravel Scout ist eine einfache, treiber-basierte Lösung, um Eloquent-Modellen Volltextsuche hinzuzufügen. Über Modell-Observer werden Eloquent-Datensätze automatisch mit dem Suchindex synchronisiert. Scout bringt eine integrierte database-Engine mit, die Volltextindizes und LIKE-Klauseln von MySQL/PostgreSQL nutzt – ohne externen Dienst. Für große Produktivumgebungen mit Tippfehler-Toleranz, Facettensuche oder Geo-Suche sind externe Engines im Vorteil.

Übersicht der Engines

EngineMerkmaleAnwendung
databaseVolltextindex von MySQL/PostgreSQLFür die meisten Anwendungen
collectionFilterung in PHP (auch SQLite)Lokale Entwicklung / Tests
MeilisearchOpen Source, tippfehlertolerant, schnellProduktion
AlgoliaCloud-SaaS mit vielen FunktionenProduktion
TypesenseOpen Source, unterstützt VektorsucheProduktion

Installation

Installieren Sie das Paket mit Composer.
composer require laravel/scout
Veröffentlichen Sie die Konfiguration mit vendor:publish. Dabei entsteht config/scout.php.
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Ergänzen Sie schließlich das Trait Laravel\Scout\Searchable in jedem Modell, das durchsuchbar sein soll. Das Trait registriert einen Model-Observer und aktiviert die automatische Synchronisation mit dem Suchtreiber.
<?php

namespace App\Models;

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

class Post extends Model
{
    use Searchable;
}

Queues konfigurieren

Für alle Engines außer database und collection empfehlen wir dringend, Queues einzurichten. Ein Worker verlagert Index-Synchronisationen in den Hintergrund und verbessert die Reaktionszeit der Weboberfläche erheblich. Setzen Sie in config/scout.php die Option queue auf true.
'queue' => true,
Verbindung und Queue-Name lassen sich angeben.
'queue' => [
    'connection' => 'redis',
    'queue' => 'scout'
],
Starten Sie einen dedizierten Worker.
php artisan queue:work redis --queue=scout

Unique Jobs verwenden

In schreiblastigen Anwendungen möchten Sie duplizierte Index-Jobs für denselben Datensatz vermeiden. Registrieren Sie in config/scout.php – üblicherweise in der boot-Methode eines Service-Providers – die Job-Klassen MakeSearchableUniquely und RemoveFromSearchUniquely.
use Laravel\Scout\Jobs\MakeSearchableUniquely;
use Laravel\Scout\Jobs\RemoveFromSearchUniquely;
use Laravel\Scout\Scout;

Scout::makeSearchableUsing(MakeSearchableUniquely::class);
Scout::removeFromSearchUsing(RemoveFromSearchUniquely::class);
Diese Jobs nutzen Laravels Unique-Job-Locks, um doppelte Index-Operationen für denselben Datensatz zu vermeiden.

Voraussetzungen der Treiber

Algolia

Für Algolia setzen Sie in config/scout.php id und secret und installieren das Algolia-PHP-SDK.
composer require algolia/algoliasearch-client-php
In der .env:
ALGOLIA_APP_ID=your-app-id
ALGOLIA_SECRET=your-secret-key

Index-Konfiguration

Bei Algolia verwalten Sie Index-Einstellungen in config/scout.php.
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)'],
        ],
    ],
],
Synchronisieren Sie die Konfiguration mit scout:sync-index-settings.
php artisan scout:sync-index-settings

Meilisearch

Meilisearch ist eine schnelle Open-Source-Such-Engine. Am einfachsten läuft sie lokal via Laravel Sail.
# Mit Laravel Sail
./vendor/bin/sail up -d meilisearch
Ohne Sail direkt via Docker:
docker run -it --rm \
    -p 7700:7700 \
    getmeili/meilisearch:latest \
    meilisearch --master-key="masterKey"
Installieren Sie das PHP-SDK.
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
.env:
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKey
Beim Upgrade von Scout prüfen Sie stets auch die Breaking Changes von Meilisearch selbst.

Index-Konfiguration (Meilisearch)

Für Filter mit where() müssen Sie die Spalten in filterableAttributes eintragen; für Sortierungen mit orderBy() in sortableAttributes.
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'],
        ],
    ],
],
Beachten Sie die Datentypen numerischer Spalten. Meilisearch führt Filteroperationen (>, < etc.) nur bei korrekt typisierten Werten aus.
public function toSearchableArray(): array
{
    return [
        'id' => (int) $this->id,
        'name' => $this->name,
        'price' => (float) $this->price,
    ];
}
Anschließend scout:sync-index-settings ausführen.
php artisan scout:sync-index-settings

Typesense

Typesense ist eine schnelle Open-Source-Such-Engine mit Keyword-, semantischer, Geo- und Vektorsuche.
composer require typesense/typesense-php
.env:
SCOUT_DRIVER=typesense
TYPESENSE_API_KEY=masterKey
TYPESENSE_HOST=localhost
TYPESENSE_PORT=8108
TYPESENSE_PATH=
TYPESENSE_PROTOCOL=http
Bei Typesense müssen Sie in toSearchableArray den Primärschlüssel als String und created_at als Unix-Timestamp casten.
public function toSearchableArray(): array
{
    return array_merge($this->toArray(), [
        'id' => (string) $this->id,
        'created_at' => $this->created_at->timestamp,
    ]);
}

Datenbank-/Collection-Engine

Ideal, wenn Sie ohne externen Dienst suchen möchten. Die Datenbank-Engine nutzt Volltextindizes und LIKE-Klauseln von MySQL/PostgreSQL und reicht für die meisten Anwendungen.
SCOUT_DRIVER=database
Die Collection-Engine filtert in PHP und funktioniert auf allen von Laravel unterstützten Datenbanken (auch SQLite). Ideal für lokale Entwicklung, Tests und kleine Datensätze.
SCOUT_DRIVER=collection
Anders als bei externen Engines müssen Sie bei der Datenbank-Engine keinen Index manuell pflegen. Es wird direkt in der Tabelle gesucht.

Das Trait Searchable

toSearchableArray() anpassen

Standardmäßig werden alle Daten aus toArray() in den Suchindex geschrieben. Um die Daten zu steuern, überschreiben Sie toSearchableArray.
<?php

namespace App\Models;

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

class Post extends Model
{
    use Searchable;

    /**
     * Gibt die für den Index vorgesehenen Daten des Modells zurück.
     *
     * @return array<string, mixed>
     */
    public function toSearchableArray(): array
    {
        $array = $this->toArray();

        // Daten anpassen...

        return $array;
    }
}

Indexnamen anpassen

Standardmäßig wird der Tabellenname (in der Pluralform) als Index verwendet. Über searchableAs passen Sie ihn an.
public function searchableAs(): string
{
    return 'posts_index';
}

Suchstrategie für die Datenbank-Engine

Bei der Datenbank-Engine legen Sie pro Spalte über PHP-Attribute eine effiziente Suchstrategie fest.
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,
    ];
}
Bevor Sie SearchUsingFullText verwenden, achten Sie darauf, dass die Zielspalte einen Volltextindex besitzt.

Bedingt durchsuchbar

Um ein Modell nur unter bestimmten Bedingungen durchsuchbar zu machen, definieren Sie shouldBeSearchable.
/**
 * Entscheidet, ob das Modell durchsuchbar sein soll.
 */
public function shouldBeSearchable(): bool
{
    return $this->isPublished();
}
shouldBeSearchable funktioniert nicht mit der Datenbank-Engine. Verwenden Sie dort where-Klauseln.

Index verwalten

Die Befehle in diesem Abschnitt sind vor allem für externe Engines (Algolia, Meilisearch, Typesense) relevant. Bei der Datenbank-Engine ist keine Index-Verwaltung nötig.

Vorhandene Datensätze importieren

Wenn Sie Scout in ein bestehendes Projekt einführen, importieren Sie vorhandene Datensätze mit scout:import.
php artisan scout:import "App\Models\Post"
Der Import kann auch als Queue-Job laufen.
php artisan scout:queue-import "App\Models\Post" --chunk=500

Index leeren

Mit scout:flush entfernen Sie alle Datensätze eines Modells aus dem Suchindex.
php artisan scout:flush "App\Models\Post"

Index-Synchronisation pausieren

Um während Eloquent-Operationen die Sync mit dem Index zu unterbrechen, nutzen Sie withoutSyncingToSearch.
use App\Models\Order;

Order::withoutSyncingToSearch(function () {
    // Die Modell-Operationen darin synchronisieren nicht in den Index.
});

Datensätze manuell hinzufügen/entfernen

Sie können anhand einer Abfrage Modelle in den Index aufnehmen.
// Ergebnisse einer Abfrage
Order::where('price', '>', 100)->searchable();

// Über eine Beziehung
$user->orders()->searchable();
Mit unsearchable entfernen Sie Datensätze wieder.
Order::where('price', '>', 100)->unsearchable();
Beim Aufruf von delete wird der Datensatz automatisch aus dem Index entfernt.

Suche

Mit search durchsuchen Sie Modelle. Hängen Sie get an, um eine Eloquent-Collection zu erhalten.
use App\Models\Order;

$orders = Order::search('Star Trek')->get();
Aus Controllern oder Routen direkt zurückgegeben, wird das Ergebnis automatisch als JSON serialisiert.
use Illuminate\Http\Request;

Route::get('/search', function (Request $request) {
    return Order::search($request->search)->get();
});
Für die Rohdaten der Suche verwenden Sie raw.
$orders = Order::search('Star Trek')->raw();

Pagination

Mit paginate paginieren Sie Ergebnisse wie sonst auch.
$orders = Order::search('Star Trek')->paginate();

// Datensätze pro Seite
$orders = Order::search('Star Trek')->paginate(15);
Mit der Datenbank-Engine ist auch simplePaginate verfügbar. Da keine Gesamtzahl ermittelt wird, ist das bei großen Datenmengen effizienter.
$orders = Order::search('Star Trek')->simplePaginate(15);
Anzeige in Blade:
<div class="container">
    @foreach ($orders as $order)
        {{ $order->price }}
    @endforeach
</div>

{{ $orders->links() }}

Filtern und sortieren

Mit where schränken Sie die Suche ein.
use App\Models\Order;

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

// In einer Menge
$orders = Order::search('Star Trek')->whereIn('status', ['open', 'paid'])->get();

// Nicht in einer Menge
$orders = Order::search('Star Trek')->whereNotIn('status', ['closed'])->get();
Bei Meilisearch müssen Sie vor dem Einsatz von where die filterbaren Attribute definieren.
Mit query passen Sie die Eloquent-Abfrage an.
use Illuminate\Database\Eloquent\Builder;

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

Eager Loading

Scout holt zunächst die IDs aus der Such-Engine und dann die Modelle über Eloquent. Um N+1-Probleme zu vermeiden, geben Sie in query mit with() Eager Loading an.
use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;

$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with(['invoices', 'user']))
    ->get();
Für Eager Loading bei Batch-Imports definieren Sie makeAllSearchableUsing.
use Illuminate\Database\Eloquent\Builder;

protected function makeAllSearchableUsing(Builder $query): Builder
{
    return $query->with('author');
}
Bei queue-basierten Batch-Imports kann makeAllSearchableUsing nicht immer verwendet werden. Beziehungen werden im Queue-Job für eine Modell-Collection ggf. nicht wiederhergestellt.

Soft Deletes

Verwendet Ihr indiziertes Modell Soft Deletes und wollen Sie auch gelöschte Datensätze suchen, setzen Sie in config/scout.php soft_delete auf true.
'soft_delete' => true,
Danach nutzen Sie withTrashed bzw. onlyTrashed.
// Auch gelöschte
$orders = Order::search('Star Trek')->withTrashed()->get();

// Nur gelöschte
$orders = Order::search('Star Trek')->onlyTrashed()->get();

Eigene Engines

Reichen die eingebauten Engines nicht aus, implementieren Sie eine eigene. Erben Sie von der abstrakten Klasse Laravel\Scout\Engines\Engine und implementieren Sie folgende Methoden:
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);
Als Vorlage können Sie sich die Klasse Laravel\Scout\Engines\AlgoliaEngine ansehen. Registrieren Sie die Engine in der boot-Methode Ihres AppServiceProvider.
use App\ScoutExtensions\MySqlSearchEngine;
use Laravel\Scout\EngineManager;

public function boot(): void
{
    resolve(EngineManager::class)->extend('mysql', function () {
        return new MySqlSearchEngine;
    });
}
Nach der Registrierung wählen Sie sie in config/scout.php als Treiber aus.
'driver' => 'mysql',

Verwandte Seiten

Eloquent ORM

Grundlagen der Eloquent-Modelle.

Eloquent-Beziehungen

Definition von Beziehungen und Eager Loading.

Queues

Scout kann Indizes zusammen mit Queues im Hintergrund aktualisieren.
Zuletzt geändert am 13. Juli 2026