laravel 5.3 에 도입된 scout 패키지를 사용하여 full text search engine 연계하는 방법
사전 준비
설치
scout elastic search 패키지 설치
laravel 6.x$ composer require babenkoivan/scout-elasticsearch-driver
laravel 5.8$ composer require babenkoivan/scout-elasticsearch-driver "^3.0"
3.12 버전은 Elastic 6.x 필요
config/app.php 의 providers 에 아래 내용 추가 (No Package Discovery !)
'providers' => [ Laravel\Scout\ScoutServiceProvider::class, ScoutElastic\ScoutElasticServiceProvider::class, ]
config에 설정 파일을 생성하기 위해 vendor publish 수행
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" php artisan vendor:publish --provider="ScoutElastic\ScoutElasticServiceProvider"
- 컨피그 파일(config/scout_elastic.php) 설정
.env 에 다음 내용을 추가하고 설정
SCOUT_DRIVER=elasticsearch # This prefix may be useful if you have multiple| "tenants" or applications sharing the same search infrastructure. SCOUT_PREFIX='' ELASTICSEARCH_INDEX=laravel ##ELASTICSEARCH_HOST=localhost:9200 ## laravel scout host SCOUT_ELASTIC_HOST=http://my-elastic.site:80
- nginx 를 붙여서 사용할 경우 SCOUT_ELASTIC_HOST 에 포트를 명시해야 함.(기본 9200)
- URL 뒤에 trailing slash(Ex: my.site:80/) 를 붙이면 오작동하므로 주의!
Queue 를 사용하여 인덱싱할 경우 config/scout.php 의 다음 항목을 true 로 설정
'queue' => true,
Index configurator
php artisan make:index-configurator MyIndexConfigurator
MyIndexConfigurator
<?php namespace App; use ScoutElastic\IndexConfigurator; use ScoutElastic\Migratable; class MyIndexConfigurator extends IndexConfigurator { use Migratable; // It's not obligatory to determine name. By default it'll be a snaked class name without `IndexConfigurator` part. protected $name = 'my_index'; // You can specify any settings you want, for example, analyzers. protected $settings = [ 'analysis' => [ 'analyzer' => [ 'korean' => [ 'type' => 'standard', 'stopwords' => '_korean_' ] ] ] ]; }
$ art elastic:create-index "App\MyIndexConfigurator" The my_index index was created! The my_index_write alias for the my_index index was created!
Searchable Data
기본적으로 모델의 toArray() 를 호출한 결과를 인덱싱하므로 커스터마이징할 경우 toSearchableArray() 메서드 구현
class User extends Model { use Searchable; /** * Get the indexable data array for the model. * * @return array */ public function toSearchableArray() { $array = $this->toArray(); // Customize array... return $array; } }
indexing
Batch indexing
scout:import artisan 명령으로 현재 모델을 배치로 인덱싱할 수 있음
$ php artisan scout:import "App\User"
Record 추가
Laravel\Scout\Searchable 트레이트를 추가한 모델은 save() 메서드 호출시 자동으로 인덱싱
$order = new App\Order; // ... $order->save();
또는 명시적으로 searchable() 메서드를 호출하면 인덱싱됨.
// Adding via Eloquent query... App\Order::where('price', '>', 100)->searchable(); // You may also add records via relationships... $user->orders()->searchable(); // You may also add records via collections... $orders->searchable();
elastic search 새로운 indexing 생성
$ curl -XPUT 'localhost:9200/laravel?pretty'
2번째
$ curl 'localhost:9200/_cat/indices?v'
Faker로 테스트 데이타 생성
새로운 migration 생성
$ php artisan make:migration --table=users add_company_on_users_table
User 테이블에 컬럼 추가
public function up() { Schema::table('users', function (Blueprint $table) { $table->string('company', 50); $table->string('address', 100); $table->string('phoneNumber', 50); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('company'); $table->dropColumn('address'); $table->dropColumn('phoneNumber'); }); }
migration 실행
$ php artisan migrate
database/factories/ModelFactory.php 수정
$factory->define(App\User::class, function (Faker\Generator $faker) { static $password; // 한글 로캘 적용된 Faker 팩토리 생성 $koFaker = \Faker\Factory::create('ko_KR'); return [ 'name' => $koFaker->name, 'company' => $koFaker->company, 'address' => $koFaker->address, 'phoneNumber' => $koFaker->phoneNumber, 'email' => $faker->unique()->companyEmail, 'password' => $password ?: $password = bcrypt('secret'), 'remember_token' => str_random(10), ]; });
팅커 구동
$ php artisan tinker
테스트용 모델 팩토리 생성
>>> factory('App\User', 300)->create();
검색
>>> $us = App\User::search('민')->get();
검색(Searching)
기본 검색
모델의 search() 메소드 사용
>>> $us = App\User::search('민형')->get();
Where 구문 사용
>>> $us = App\User::search('민형')->where('name', '용훈')->get();