Laravel Scout

번역일: 2026년 6월 25일

Laravel Scout

소개

Laravel ScoutEloquent 모델에 전문 검색(full-text search) 기능을 추가하는 드라이버 기반의 간결한 솔루션입니다. 모델 옵저버를 활용하여 Eloquent 레코드가 변경될 때 검색 인덱스를 자동으로 동기화합니다.

현재 Scout는 Algolia, Meilisearch, Typesense, MySQL / PostgreSQL (database) 드라이버를 기본 제공합니다. 외부 서비스 없이 로컬 개발에 바로 사용할 수 있는 "collection" 드라이버도 포함되어 있으며, 커스텀 드라이버를 직접 작성하는 것도 간단합니다.

설치

먼저 Composer로 Scout 패키지를 설치합니다.

composer require laravel/scout

설치 후, vendor:publish Artisan 명령어로 Scout 설정 파일을 애플리케이션의 config 디렉터리에 게시합니다.

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

마지막으로, 검색 대상으로 만들 모델에 Laravel\Scout\Searchable 트레이트를 추가합니다. 이 트레이트가 모델 옵저버를 등록하여 검색 드라이버와 자동으로 동기화합니다.

<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; }

큐 설정

Scout를 사용할 때 반드시 큐가 필요한 것은 아니지만, 사용 전에 큐 드라이버를 설정하는 것을 강력히 권장합니다. 큐 워커를 실행하면 인덱스 동기화 작업이 백그라운드에서 처리되므로 웹 인터페이스의 응답 속도가 크게 향상됩니다.

큐 드라이버를 설정한 후, config/scout.phpqueue 옵션을 true로 설정합니다.

'queue' => true,

queue 옵션이 false로 설정되어 있더라도, Algolia나 Meilisearch 같은 일부 드라이버는 내부적으로 비동기로 레코드를 인덱싱합니다. 즉, Laravel 애플리케이션에서 인덱싱 작업이 완료된 것처럼 보여도, 검색 엔진에서 새 데이터가 즉시 반영되지 않을 수 있습니다.

Scout Job이 사용할 큐 커넥션과 큐 이름을 별도로 지정하려면 queue 옵션을 배열로 정의합니다.

'queue' => [
    'connection' => 'redis',
    'queue' => 'scout'
],

이 경우 해당 커넥션과 큐를 처리하는 큐 워커를 별도로 실행해야 합니다.

php artisan queue:work redis --queue=scout

드라이버 사전 요구사항

Algolia

Algolia 드라이버를 사용하려면 config/scout.php에 Algolia의 idsecret 자격 증명을 설정한 후, Algolia PHP SDK를 설치합니다.

composer require algolia/algoliasearch-client-php

Meilisearch

Meilisearch는 빠르고 오픈 소스인 검색 엔진입니다. 로컬 머신에 설치하는 방법이 익숙하지 않다면 Laravel의 공식 Docker 개발 환경인 Laravel Sail을 활용할 수 있습니다.

Meilisearch 드라이버를 사용하려면 PHP SDK를 설치합니다.

composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle

그런 다음 .env 파일에 SCOUT_DRIVER와 Meilisearch 접속 정보를 설정합니다.

SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://127.0.0.1:7700 MEILISEARCH_KEY=masterKey

Meilisearch에 대한 자세한 내용은 Meilisearch 공식 문서를 참고하세요.

설치 시, 사용 중인 Meilisearch 바이너리 버전과 호환되는 meilisearch/meilisearch-php 버전을 선택해야 합니다. 바이너리 호환성 문서를 반드시 확인하세요.

WARNING

Meilisearch를 사용하는 애플리케이션에서 Scout를 업그레이드할 때는 Meilisearch 서비스 자체의 추가 변경 사항도 반드시 검토해야 합니다.

Typesense

Typesense는 매우 빠른 오픈 소스 검색 엔진으로, 키워드 검색, 시맨틱 검색, 지역 검색, 벡터 검색을 지원합니다.

직접 설치하거나 Typesense Cloud를 사용할 수 있습니다.

Typesense PHP SDK를 설치합니다.

composer require typesense/typesense-php

그런 다음 .env 파일에 드라이버와 접속 정보를 설정합니다.

SCOUT_DRIVER=typesense TYPESENSE_API_KEY=masterKey TYPESENSE_HOST=localhost

필요에 따라 포트, 경로, 프로토콜도 설정할 수 있습니다.

TYPESENSE_PORT=8108 TYPESENSE_PATH= TYPESENSE_PROTOCOL=http

컬렉션의 추가 설정과 스키마 정의는 config/scout.php에서 관리합니다. 자세한 내용은 Typesense 공식 문서를 참고하세요.

Typesense 저장을 위한 데이터 준비

Typesense를 사용할 때는 모델의 toSearchableArray 메서드에서 기본 키를 문자열로, 생성일을 UNIX 타임스탬프로 캐스팅해야 합니다.

/** * 모델의 인덱싱 데이터 배열을 반환합니다. * * @return array<string, mixed> */ public function toSearchableArray() { return array_merge($this->toArray(), [ 'id' => (string) $this->id, 'created_at' => $this->created_at->timestamp, ]); }

Typesense 컬렉션 스키마도 config/scout.php에 정의해야 합니다. 스키마는 Typesense에서 검색할 각 필드의 데이터 타입을 명시합니다. 사용 가능한 스키마 옵션은 Typesense 문서를 확인하세요.

스키마를 변경해야 할 경우, scout:flushscout:import를 순서대로 실행해 인덱스 데이터를 삭제하고 스키마를 재생성하거나, Typesense API를 통해 기존 인덱스 데이터를 유지하면서 스키마를 수정할 수 있습니다.

소프트 삭제를 사용하는 모델이라면 config/scout.php의 Typesense 스키마 정의에 __soft_deleted 필드를 추가해야 합니다.

User::class => [ 'collection-schema' => [ 'fields' => [ // ... [ 'name' => '__soft_deleted', 'type' => 'int32', 'optional' => true, ], ], ], ],

동적 검색 파라미터

Typesense는 options 메서드를 통해 검색 실행 시 검색 파라미터를 동적으로 변경할 수 있습니다.

use App\Models\Todo; Todo::search('장보기')->options([ 'query_by' => 'title, description' ])->get();

설정

모델 인덱스 설정

각 Eloquent 모델은 특정 검색 "인덱스"와 동기화됩니다. 인덱스는 MySQL 테이블과 유사한 개념으로, 해당 모델의 모든 검색 가능한 레코드를 포함합니다. 기본적으로 모델 이름의 복수형(테이블명)이 인덱스 이름으로 사용됩니다. searchableAs 메서드를 오버라이드하면 인덱스 이름을 직접 지정할 수 있습니다.

<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; /** * 모델과 연결된 인덱스 이름을 반환합니다. */ public function searchableAs(): string { return 'posts_index'; } }

검색 데이터 설정

기본적으로 모델의 toArray 결과 전체가 검색 인덱스에 저장됩니다. 인덱스에 저장할 데이터를 직접 제어하려면 toSearchableArray 메서드를 오버라이드하세요.

<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; /** * 모델의 인덱싱 데이터 배열을 반환합니다. * * @return array<string, mixed> */ public function toSearchableArray(): array { $array = $this->toArray(); // 데이터 배열 커스터마이징... return $array; } }

Meilisearch 같은 일부 검색 엔진은 필터 연산(>, < 등)을 수행할 때 데이터 타입이 정확해야 합니다. 따라서 검색 데이터를 커스터마이징할 때는 숫자 값의 타입을 명시적으로 캐스팅해야 합니다.

public function toSearchableArray() { return [ 'id' => (int) $this->id, 'name' => $this->name, 'price' => (float) $this->price, ]; }

필터링 데이터 및 인덱스 설정 (Meilisearch)

다른 드라이버와 달리 Meilisearch는 필터링 가능한 속성(filterable attributes), 정렬 가능한 속성(sortable attributes) 등을 미리 정의해야 합니다.

필터링 가능한 속성은 Scout의 where 메서드에서 사용할 속성이고, 정렬 가능한 속성은 orderBy 메서드에서 사용할 속성입니다. config/scout.phpmeilisearch 설정에서 index-settings를 통해 정의합니다.

use App\Models\User; use App\Models\Flight; 'meilisearch' => [ 'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'), 'key' => env('MEILISEARCH_KEY', null), 'index-settings' => [ User::class => [ 'filterableAttributes' => ['id', 'name', 'email'], 'sortableAttributes' => ['created_at'], // 기타 설정 필드... ], Flight::class => [ 'filterableAttributes' => ['id', 'destination'], 'sortableAttributes' => ['updated_at'], ], ], ],

소프트 삭제를 사용하는 모델이 index-settings 배열에 포함되어 있으면, Scout가 자동으로 소프트 삭제 필터링 지원을 추가합니다. 필터링/정렬 속성을 별도로 정의할 필요가 없는 소프트 삭제 모델은 빈 항목으로 추가하면 됩니다.

'index-settings' => [ Flight::class => [] ],

설정 후 반드시 아래 명령어를 실행해 Meilisearch에 인덱스 설정을 적용하세요. 이 명령어는 배포 프로세스에 포함시키는 것을 권장합니다.

php artisan scout:sync-index-settings

모델 ID 설정

기본적으로 Scout는 모델의 기본 키를 검색 인덱스의 고유 ID로 사용합니다. 이를 변경하려면 getScoutKeygetScoutKeyName 메서드를 오버라이드하세요.

<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class User extends Model { use Searchable; /** * 모델 인덱싱에 사용할 값을 반환합니다. */ public function getScoutKey(): mixed { return $this->email; } /** * 모델 인덱싱에 사용할 키 이름을 반환합니다. */ public function getScoutKeyName(): mixed { return 'email'; } }

모델별 검색 엔진 설정

Scout는 기본적으로 scout 설정 파일에 지정된 기본 검색 엔진을 사용합니다. 특정 모델에 다른 엔진을 사용하고 싶다면 searchableUsing 메서드를 오버라이드하세요.

<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Engines\Engine; use Laravel\Scout\EngineManager; use Laravel\Scout\Searchable; class User extends Model { use Searchable; /** * 모델 인덱싱에 사용할 엔진을 반환합니다. */ public function searchableUsing(): Engine { return app(EngineManager::class)->engine('meilisearch'); } }

사용자 식별

Algolia를 사용할 때 검색 요청에 인증된 사용자 정보를 자동으로 연결할 수 있습니다. 이를 통해 Algolia 대시보드에서 사용자별 검색 분석을 확인할 수 있습니다. .env 파일에서 SCOUT_IDENTIFYtrue로 설정하면 활성화됩니다.

SCOUT_IDENTIFY=true

이 기능을 활성화하면 요청의 IP 주소와 인증된 사용자의 기본 키가 Algolia로 전달되어 각 검색 요청과 연결됩니다.

Database / Collection 엔진

Database 엔진

WARNING

Database 엔진은 현재 MySQL과 PostgreSQL만 지원합니다.

소규모 또는 중간 규모의 데이터베이스를 사용하거나 검색 부하가 크지 않은 경우, Scout의 "database" 엔진이 간편한 선택입니다. 이 엔진은 기존 데이터베이스에서 WHERE LIKE 절과 전문 검색 인덱스를 활용해 검색 결과를 필터링합니다.

SCOUT_DRIVER 환경 변수를 database로 설정하거나 config/scout.php에서 직접 지정합니다.

SCOUT_DRIVER=database

Database 엔진을 선택했다면 검색 데이터 설정을 마친 후 바로 검색 쿼리를 실행할 수 있습니다. Algolia, Meilisearch, Typesense처럼 별도의 인덱스 구축 과정이 필요하지 않습니다.

데이터베이스 검색 전략 커스터마이징

기본적으로 database 엔진은 검색 가능한 모든 모델 속성에 WHERE LIKE 쿼리를 실행합니다. 경우에 따라 성능이 저하될 수 있으므로, 특정 컬럼에 전문 검색(full text)을 사용하거나 전체 문자열 대신 접두사(example%)만 검색하도록 전략을 지정할 수 있습니다.

toSearchableArray 메서드에 PHP 속성(attribute)을 붙여 컬럼별 검색 전략을 지정합니다. 별도로 지정하지 않은 컬럼은 기본 WHERE LIKE 전략을 사용합니다.

use Laravel\Scout\Attributes\SearchUsingFullText; use Laravel\Scout\Attributes\SearchUsingPrefix; /** * 모델의 인덱싱 데이터 배열을 반환합니다. * * @return array<string, mixed> */ #[SearchUsingPrefix(['id', 'email'])] #[SearchUsingFullText(['bio'])] public function toSearchableArray(): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'bio' => $this->bio, ]; }

WARNING

컬럼에 전문 검색 쿼리를 사용하려면 먼저 해당 컬럼에 전문 검색 인덱스가 생성되어 있어야 합니다.

Collection 엔진

로컬 개발 환경에서 외부 검색 서비스 없이 빠르게 시작하고 싶다면 "collection" 엔진이 편리합니다. 이 엔진은 데이터베이스에서 레코드를 가져온 후 Laravel의 컬렉션 필터링으로 검색 결과를 결정합니다. 별도의 인덱싱이 필요하지 않습니다.

SCOUT_DRIVER=collection

Collection 드라이버를 지정한 후 바로 검색 쿼리를 실행할 수 있습니다.

Database 엔진과의 차이점

언뜻 보면 database 엔진과 collection 엔진은 비슷해 보이지만, 동작 방식에 차이가 있습니다. database 엔진은 LIKE 절과 전문 검색 인덱스를 활용해 데이터베이스 수준에서 필터링합니다. 반면 collection 엔진은 가능한 모든 레코드를 먼저 가져온 후 Laravel의 Str::is 헬퍼로 검색어가 속성값에 포함되는지 확인합니다.

Collection 엔진은 Laravel이 지원하는 모든 관계형 데이터베이스(SQLite, SQL Server 포함)에서 동작하는 가장 범용적인 엔진이지만, database 엔진보다 효율이 낮습니다.

인덱싱

일괄 가져오기

기존 프로젝트에 Scout를 도입하는 경우, 이미 존재하는 데이터베이스 레코드를 인덱스에 일괄 가져와야 합니다. scout:import Artisan 명령어를 사용하세요.

php artisan scout:import "App\Models\Post"

인덱스에서 모델의 모든 레코드를 삭제하려면 flush 명령어를 사용합니다.

php artisan scout:flush "App\Models\Post"

가져오기 쿼리 수정

일괄 가져오기 시 사용되는 쿼리를 수정하려면 모델에 makeAllSearchableUsing 메서드를 정의합니다. 가져오기 전에 관계를 이거 로딩(eager loading)하기에 적합한 위치입니다.

use Illuminate\Database\Eloquent\Builder; /** * 모든 모델을 검색 가능하게 만들 때 사용할 쿼리를 수정합니다. */ protected function makeAllSearchableUsing(Builder $query): Builder { return $query->with('author'); }

WARNING

큐를 사용해 모델을 일괄 가져올 때는 makeAllSearchableUsing 메서드가 적용되지 않을 수 있습니다. Job이 모델 컬렉션을 처리할 때 관계가 복원되지 않습니다.

레코드 추가

모델에 Laravel\Scout\Searchable 트레이트를 추가하면, 모델 인스턴스를 save하거나 create할 때 자동으로 검색 인덱스에 추가됩니다. Scout에 큐 설정이 되어 있다면 이 작업은 큐 워커가 백그라운드에서 처리합니다.

use App\Models\Order; $order = new Order; // ... $order->save();

쿼리로 레코드 추가

Eloquent 쿼리에 searchable 메서드를 체이닝하면 쿼리 결과를 검색 인덱스에 추가할 수 있습니다. searchable 메서드는 결과를 청크 단위로 나눠 인덱스에 추가합니다. 큐가 설정되어 있으면 모든 청크가 백그라운드에서 처리됩니다.

use App\Models\Order; Order::where('price', '>', 100)->searchable();

Eloquent 관계 인스턴스에서도 searchable을 호출할 수 있습니다.

$user->orders()->searchable();

이미 메모리에 Eloquent 컬렉션이 있는 경우 컬렉션 인스턴스에서 직접 호출할 수도 있습니다.

$orders->searchable();

NOTE

searchable 메서드는 "upsert" 방식으로 동작합니다. 인덱스에 이미 레코드가 있으면 업데이트하고, 없으면 새로 추가합니다.

레코드 업데이트

검색 가능한 모델을 업데이트하려면 모델 인스턴스의 속성을 변경하고 save하면 됩니다. Scout가 검색 인덱스에 변경 사항을 자동으로 반영합니다.

use App\Models\Order; $order = Order::find(1); // 주문 정보 수정... $order->save();

Eloquent 쿼리 인스턴스에서 searchable 메서드를 호출해

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 25일