Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Note

laravel 5.3 에 도입된 scout 패키지를 사용하여 full text search engine 연계하는 방법에 대해 설명합니다.

...

  1. scout elastic search 패키지를 설치합니다.

    Code Block
    languagebash
    titlelaravel 6.x
    $ composer require babenkoivan/scout-elasticsearch-driver
    Code Block
    languagebash
    titlelaravel 5.8
    $ composer require babenkoivan/scout-elasticsearch-driver "^3.0"
    Note

    만약 ES 6을 사용한다면 3.12 버전을 설치해 줍니다.

  2. config/app.php 의 providers 에 프로바이더를 추가합니다. 개인적으로는 Laravel 의 Package Discovery 기능을 별로 좋아하지 않아서 직접 추가하는 것이며 추가해 주는데 등록해 주지 않아도 최신 버전의 라라벨에서는 정상 동작합니다.

    Code Block
    'providers' => [
        Laravel\Scout\ScoutServiceProvider::class,
        ScoutElastic\ScoutElasticServiceProvider::class,
    ]
  3. config에 설정 파일을 생성하기 위해 vendor publish 수행합니다.

    Code Block
    php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
    php artisan vendor:publish --provider="ScoutElastic\ScoutElasticServiceProvider"
  4. 컨피그 파일(config/scout_elastic.php) 설정 변경이 필요하면 수정합니다.
  5. .env 에 다음 내용을 추가합니다.

    Code Block
    SCOUT_DRIVER=elasticsearch
    
    ## laravel scout host
    SCOUT_ELASTIC_HOST=localhost:80
    Warning
    • nginx 를 붙여서 사용할 경우 SCOUT_ELASTIC_HOST 에 포트를 명시해야 합니다.(기본 9200)
    • URL 뒤에 trailing slash(Ex: my.site:80/) 를 붙이면 오작동하므로 주의하세요!
  6. Queue 를 사용하여 인덱싱할 경우 config/scout.php 의 다음 항목을 true 로 설정합니다.

    Code Block
    'queue' => true,

...

Code Block
languagephp
titleUserIndexConfigurator
<?php

namespace App;

use ScoutElastic\IndexConfigurator;
use ScoutElastic\Migratable;

class UserIndexConfigurator extends IndexConfigurator
{
    use Migratable;

    // index 이름을 직접 설정하려면 $name 변수에 이름을 지정해 주면 됩니다.
    // 생략할 경우 `IndexConfigurator` 를 제외한 snaked class 이름으로 생성됩니다.
    protected $name = 'user_index';

    // You can specify any settings you want, for example, analyzers.
     protected $settings = [
        'analysis' => [
            "tokenizer" => [
                "nori_user_dict" => [
                    "type" => "nori_tokenizer",
                    "decompound_mode" => "mixed",
                    "user_dictionary" => "userdict_ko.txt"
                ]
            ],
            'analyzer' => [
                'my_analyzer' => [
                    'type' => 'custom',
                    "tokenizer" => "nori_user_dict"
                ]
            ]
        ]
    ];

    // ES field 매핑
    protected $defaultMapping = [
        'properties' => [
            "id"=> [
                "type"=> "long"
            ],
            "name"=> [
                "type"=> "text",
                "analyzer"=> "koreanmy_analyzer",
                "search_analyzer"=> "koreanmy_analyzer"
            ],
            "email"=> [
                "type"=> "text",
                "analyzer"=> "koreanmy_analyzer",
                "search_analyzer"=> "koreanmy_analyzer"
            ],
            "created_at"=> [
                "type"=> "date",
                "format"=> "yyyy-MM-dd HH:mm:ss"
            ],
            "updated_at"=> [
                "type"=> "date",
                "format"=> "yyyy-MM-dd HH:mm:ss"
            ],
        ] // properties
    ];
}

...

localhost:9200/my_index 에 연결해서 인덱스가 생겼는지 확인해 봅니다.

...

Searchable Data

기본적으로 모델의 toArray() 를 호출한 결과를 인덱싱하므로 커스터마이징할 경우 toSearchableArray() 메서드 구현

...


...

검색 가능하게 Model 모델 설정

Model class 와 ES 연동은 간단하게 Searchable trait 을 추가하고 $indexConfigurator 변수에 사용할 IndexConfigurator 만 등록해 주면 됩니다.

주의할 점은 Searchable trait 은 Laravel\Scout\Searchable 이 아닌 ScoutElastic\Searchable 을 사용해야 합니다. 


Code Block
languagephp
<?php

class MyModel extends Model
{
    use Searchable;

    /**
     * Get the indexable data array for the model.
     *
     * @return array
     */
    public function toSearchableArray()
    {
        $array = $this->toArray();

        // Customize array...	 // Laravel\Scout\Searchable을 사용하지 않도록 주의
     use \ScoutElastic\Searchable; 

	 // 사용할 index
     protected $indexConfigurator   return $array;
    }
}= MyIndexConfigurator::class;


indexing

Batch indexing

scout:import artisan 명령으로 현재 모델을 모델 데이타를 배치로 인덱싱할 수 있음있습니다.

Code Block
$ php artisan scout:import "App\UserMyModel"


Record 추가

Laravel\Scout\Searchable 트레이트를 추가한 모델은  save() 메서드 호출시 자동으로 인덱싱인덱싱됩니다.

Code Block
$order = new App\Order;

// ...

$order->save();

...

또는 명시적으로 searchable() 메서드를 호출하면 인덱싱됨인덱싱이 됩니다.

Code Block
// 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 생성

Code Block
$ curl -XPUT 'localhost:9200/laravel?pretty'

2번째

Code Block
$ curl 'localhost:9200/_cat/indices?v'

Faker로 테스트 데이타 생성

...


테스트 데이타 생성

실제 테스트를 위해 Faker 로 Model factory 를 생성하고 indexing 해 보겠습니다.


  1. 테스트용 테이블을 만들기 위한 새로운 migration 생성합니다.

    Code Block
    $ php artisan make:migration --table=userscompany add_company_on_users_table
  2. User 테이블에 컬럼 추가컬럼을 추가합니다.

    Code Block
    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');
        });
    }
  3. migration 실행실행합니다.

    Code Block
    $ php artisan migrate
  4. database/factories/ModelFactory.php 수정 수정합니다.

    Code Block
    $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),
        ];
    });
  5. 팅커 구동

    Code Block
    $ php artisan tinker
  6. 테스트용 모델 팩토리 생성

    Code Block
    >>> factory('App\User', 300)->create();
  7. 검색

    Code Block
    >>> $us = App\User::search('민')->get();

...