Introduzione
Laravel Scout è una soluzione driver-based che aggiunge la ricerca full-text ai modelli Eloquent . Sincronizza automaticamente record Eloquent e indici di ricerca tramite osservatori del modello.
Scout include il motore integrato database che sfrutta il full-text di MySQL/PostgreSQL e la clausola LIKE senza servizi esterni. In produzione, per tolleranza ai typo, ricerche facettate e geospaziali, i motori esterni sono utili.
Motori supportati
Motore Caratteristiche Uso databaseFull-text di MySQL/PostgreSQL La maggior parte delle app collectionFiltro in PHP (anche SQLite) Sviluppo/test Meilisearch Open source, tollerante ai typo, veloce Produzione Algolia SaaS cloud, funzionalità avanzate Produzione Typesense Open source, supporta vettori Produzione
Installazione
composer require laravel/scout
php artisan vendor:publish --provider= "Laravel\Scout\ScoutServiceProvider"
Aggiungi il trait Laravel\Scout\Searchable al modello.
<? php
namespace App\Models ;
use Illuminate\Database\Eloquent\ Model ;
use Laravel\Scout\ Searchable ;
class Post extends Model
{
use Searchable ;
}
Code
Con motori esterni si consiglia di attivare le code per la sincronizzazione in background.
Oppure:
'queue' => [
'connection' => 'redis' ,
'queue' => 'scout'
],
Avvia un worker dedicato:
php artisan queue:work redis --queue=scout
Job univoci
Per applicazioni molto scritte, evita job duplicati sullo stesso record.
use Laravel\Scout\Jobs\ MakeSearchableUniquely ;
use Laravel\Scout\Jobs\ RemoveFromSearchUniquely ;
use Laravel\Scout\ Scout ;
Scout :: makeSearchableUsing ( MakeSearchableUniquely :: class );
Scout :: removeFromSearchUsing ( RemoveFromSearchUniquely :: class );
Prerequisiti dei driver
Algolia
composer require algolia/algoliasearch-client-php
ALGOLIA_APP_ID =your-app-id
ALGOLIA_SECRET =your-secret-key
Impostazioni indice
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)' ],
],
],
],
Sincronizza:
php artisan scout:sync-index-settings
Meilisearch
Meilisearch è veloce e open source. In locale è comodo con Laravel Sail .
./vendor/bin/sail up -d meilisearch
Docker diretto:
docker run -it --rm \
-p 7700:7700 \
getmeili/meilisearch:latest \
meilisearch --master-key= "masterKey"
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
SCOUT_DRIVER =meilisearch
MEILISEARCH_HOST =http://127.0.0.1:7700
MEILISEARCH_KEY =masterKey
Impostazioni indice (Meilisearch)
Registra filterableAttributes per where() e sortableAttributes per orderBy().
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' ],
],
],
],
Attenzione ai tipi:
public function toSearchableArray () : array
{
return [
'id' => ( int ) $this -> id ,
'name' => $this -> name ,
'price' => ( float ) $this -> price ,
];
}
php artisan scout:sync-index-settings
Typesense
Typesense è open source, supporta keyword, semantica, geo e vettori.
composer require typesense/typesense-php
SCOUT_DRIVER =typesense
TYPESENSE_API_KEY =masterKey
TYPESENSE_HOST =localhost
TYPESENSE_PORT =8108
TYPESENSE_PATH =
TYPESENSE_PROTOCOL =http
Casta la primary key a stringa e la data creazione a timestamp UNIX:
public function toSearchableArray () : array
{
return array_merge ( $this -> toArray (), [
'id' => ( string ) $this -> id ,
'created_at' => $this -> created_at -> timestamp ,
]);
}
Motore database / collection
Senza servizi esterni.
database : full-text MySQL/PostgreSQL e LIKE.
collection : filtro in PHP (anche SQLite), per dev/test.
Con database engine gli indici non vanno gestiti a parte.
Trait Searchable
toSearchableArray()
<? php
namespace App\Models ;
use Illuminate\Database\Eloquent\ Model ;
use Laravel\Scout\ Searchable ;
class Post extends Model
{
use Searchable ;
public function toSearchableArray () : array
{
$array = $this -> toArray ();
// Personalizza...
return $array ;
}
}
Nome dell’indice
public function searchableAs () : string
{
return 'posts_index' ;
}
Strategie di ricerca (database engine)
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 ,
];
}
Condizionale
public function shouldBeSearchable () : bool
{
return $this -> isPublished ();
}
Non funziona con database engine. Usa clausole where.
Gestione degli indici
Sezione rilevante con Algolia/Meilisearch/Typesense. Con database engine non serve.
Import di record esistenti
php artisan scout:import "App\Models\Post"
Con coda:
php artisan scout:queue-import "App\Models\Post" --chunk=500
Flush
php artisan scout:flush "App\Models\Post"
Pausa della sincronizzazione
use App\Models\ Order ;
Order :: withoutSyncingToSearch ( function () {
// Operazioni non sincronizzate
});
Aggiungi/rimuovi manualmente
Order :: where ( 'price' , '>' , 100 ) -> searchable ();
$user -> orders () -> searchable ();
Order :: where ( 'price' , '>' , 100 ) -> unsearchable ();
Con delete() la rimozione è automatica.
Ricerca
use App\Models\ Order ;
$orders = Order :: search ( 'Star Trek' ) -> get ();
Da route o controller:
use Illuminate\Http\ Request ;
Route :: get ( '/search' , function ( Request $request ) {
return Order :: search ( $request -> search ) -> get ();
});
Grezzo:
$orders = Order :: search ( 'Star Trek' ) -> raw ();
Paginazione
$orders = Order :: search ( 'Star Trek' ) -> paginate ();
$orders = Order :: search ( 'Star Trek' ) -> paginate ( 15 );
Con database engine anche simplePaginate:
$orders = Order :: search ( 'Star Trek' ) -> simplePaginate ( 15 );
< div class = "container" >
@foreach ($orders as $order)
{{ $order->price }}
@endforeach
</ div >
{{ $orders->links() }}
Filtri e ordinamento
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 ();
Personalizza la query Eloquent:
use Illuminate\Database\Eloquent\ Builder ;
$orders = Order :: search ( 'Star Trek' )
-> query ( fn ( Builder $query ) => $query -> with ( 'invoices' ))
-> get ();
Eager loading
use App\Models\ Order ;
use Illuminate\Database\Eloquent\ Builder ;
$orders = Order :: search ( 'Star Trek' )
-> query ( fn ( Builder $query ) => $query -> with ([ 'invoices' , 'user' ]))
-> get ();
In batch import:
use Illuminate\Database\Eloquent\ Builder ;
protected function makeAllSearchableUsing ( Builder $query ) : Builder
{
return $query -> with ( 'author' );
}
Nelle code non è sempre possibile.
Soft delete
$orders = Order :: search ( 'Star Trek' ) -> withTrashed () -> get ();
$orders = Order :: search ( 'Star Trek' ) -> onlyTrashed () -> get ();
Motori personalizzati
Estendi Laravel\Scout\Engines\Engine e implementa 8 metodi:
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 );
Registra in AppServiceProvider::boot():
use App\ScoutExtensions\ MySqlSearchEngine ;
use Laravel\Scout\ EngineManager ;
public function boot () : void
{
resolve ( EngineManager :: class ) -> extend ( 'mysql' , function () {
return new MySqlSearchEngine ;
});
}
Pagine correlate
Eloquent ORM Basi dei modelli Eloquent.
Relazioni Eloquent Definizione delle relazioni e eager loading.
Code Scout aggiorna gli indici in background via code.