Laravel Elasticsearchの検索操作

12793 ワード

Elasticsearchは分布式の検索と分析エンジンであり、全文検索、構造化検索、分析に使用でき、これら3つを結合することができる.ElasticsearchはLuceneに基づいて開発され、Luceneのパッケージであり、REST APIの操作インタフェースを提供し、開梱してすぐに使用する.現在は最も広く使われているオープンソース検索エンジンの一つで、Wikipedia、Stack Overflow、GitHubなどはElasticsearchに基づいて検索エンジンを構築しています.
elasticsearchのインストール
https://github.com/medcl/elasticsearch-rtf 現在のバージョンはElasticsearch 5.1.1で、ikプラグインも直接持参しています.ElasticSearchをインストールし、サービスを実行し、サービスのインストールが正しいかどうかをテストします.http://127.0.0.1:9200
Laravelおよびプラグインのインストール
使用しているのはlaravel 5.5フレームワーク、composerインストールまたは公式サイトダウンロードです.
composer create-project laravel/laravel=5.5 blog 

composerインストールscout
composer require laravel/scout

elasticsearchドライバのインストール
composer require tamayo/laravel-scout-elastic

GuzzzleHttpパッケージの導入
composer require Guzzlehttp/guzzle

クラスをapp.phpに導く
'providers' => [
    ...
    ...
    Laravel\Scout\ScoutServiceProvider::class,
    ScoutEngines\Elasticsearch\ElasticsearchProvider::class,
]

vendor:publish scoutプロファイルの生成
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

config/scout.php elasticsearch環境の設定
return [
    'driver' => env('SCOUT_DRIVER', 'elasticsearch'),
    ...
    'elasticsearch' => [
        'index' => env('ELASTICSEARCH_INDEX', 'laravel'),
        'hosts' => [
            env('ELASTICSEARCH_HOST', '127.0.0.1'),
        ],
     ],
];

データセクション
migrationはarticleテーブルを作成し、データは自分で入力できます.
php artisan make:migration create_article_table
increments('id');
            $table->text('url');
            $table->string('author', 64)->nullable()->default(null);
            $table->text('title');
            $table->longText('content');
            $table->dateTime('post_date')->nullable()->default(null);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('article');
    }
}

コードセクション
articleのテンプレートとインデックスの作成
php artisan make:command InitEs

app/console/command/InitEs.php
namespace App\Console\Commands;

use GuzzleHttp\Client;
use Illuminate\Console\Command;

class InitEs extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'es:init';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Init es to create index';

    /**
     * Create a new command instance.
     *
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $client = new Client();
        $this->createTemplate($client);
        $this->createIndex($client);
    }

    protected function createIndex(Client $client)
    {
        $url = config('scout.elasticsearch.hosts')[0] . ':9200/' . config('scout.elasticsearch.index');
        $client->put($url, [
            'json' => [
                'settings' => [
                    'refresh_interval' => '5s',
                    'number_of_shards' => 1,
                    'number_of_replicas' => 0,
                ],
                'mappings' => [
                    '_default_' => [
                        '_all' => [
                            'enabled' => false
                        ]
                    ]
                ]
            ]
        ]);
    }

    protected function createTemplate(Client $client)
    {
        $url = config('scout.elasticsearch.hosts')[0] . ':9200/' . '_template/rtf';
        $client->put($url, [
            'json' => [
                'template' => '*',
                'settings' => [
                    'number_of_shards' => 1
                ],
                'mappings' => [
                    '_default_' => [
                        '_all' => [
                            'enabled' => true
                        ],
                        'dynamic_templates' => [
                            [
                                'strings' => [
                                    'match_mapping_type' => 'string',
                                    'mapping' => [
                                        'type' => 'text',
                                        'analyzer' => 'ik_smart',
                                        'ignore_above' => 256,
                                        'fields' => [
                                            'keyword' => [
                                                'type' => 'keyword'
                                            ]
                                        ]
                                    ]
                                ]
                            ]
                        ]
                    ]
                ]
            ]
        ]);

    }
}

呼び出しesスクリプト
php artisan es:init

Articleモデルapp/Model/article.phpの作成
 $this->title,
            'content' => $this->content
        ];
    }
}

データ・モデルのインポート
php artisan scout:import "App\Model\Article"

新しいアクセスページのコントローラPostController appHttpControllersPostController
get('keyword');
        $paginator = [];
        if ($q) {
            $paginator = Article::search($q)->paginate();
        }
        return view('search', compact('paginator', 'q'));
    }
}

キーワードを検索して配慮して、変数dumpが出てくる様子
LengthAwarePaginator {#338 ▼ #total: 1
  #lastPage: 1
  #items: Collection {#340 ▼  
        #attributes: array:9 [▼ "id" => 52
          "url" => "http://www.baidu.com"
          "author" => "johnny"
          "title" => "  "
          "content" => "          "
          "post_date" => "2018-07-19 10:58:35"
          "updated_at" => "2018-07-19 10:58:40"
          "created_at" => "2018-07-19 10:58:42"
          "highlight" => array:2 [▼ "content.keyword" => array:1 [▼ 0 => "          " ]
            "content" => array:1 [▼ 0 => "          " ] ] ]
        #original: array:8 [▶]
        #changes: []
        #casts: []
        #dates: []
        #dateFormat: null
        #appends: []
        #dispatchesEvents: []
        #observables: []
        #relations: []
        #touches: []
        +timestamps: true
        #hidden: []
        #visible: []
        #guarded: array:1 [▶]
        #scoutMetadata: [] } ] }
  #perPage: 15
  #currentPage: 1
  #path: "http://blog.com/search"
  #query: array:1 [▶]
  #fragment: null
  #pageName: "page" }
highlight、つまりハイライトはソースコードを し、highlightのjsonをvendortamayolaravel-scout-elasticsrcElasticsearchEngineに する があります
 $this->index,
            'type' => $builder->index ?: $builder->model->searchableAs(),
            'body' => [
                'query' => [
                    'bool' => [
                        'must' => [['query_string' => [ 'query' => "*{$builder->query}*"]]]
                    ]
                ]
            ]
        ];

        $params['body']['highlight']['fields']['*'] = new \stdClass();

        if ($sort = $this->sort($builder)) {
            $params['body']['sort'] = $sort;
        }

        if (isset($options['from'])) {
            $params['body']['from'] = $options['from'];
        }

        if (isset($options['size'])) {
            $params['body']['size'] = $options['size'];
        }

        if (isset($options['numericFilters']) && count($options['numericFilters'])) {
            $params['body']['query']['bool']['must'] = array_merge($params['body']['query']['bool']['must'],
                $options['numericFilters']);
        }
        if ($builder->callback) {
            return call_user_func(
                $builder->callback,
                $this->elastic,
                $builder->query,
                $params
            );
        }

        return $this->elastic->search($params);
    }
    ...
    ...

    /**
     * Map the given results to instances of the given model.
     *
     * @param  mixed  $results
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return Collection
     */
    public function map($results, $model)
    {
        if ($results['hits']['total'] === 0) {
            return Collection::make();
        }

        $keys = collect($results['hits']['hits'])
                        ->pluck('_id')->values()->all();

        $models = $model->whereIn(
            $model->getKeyName(), $keys
        )->get()->keyBy($model->getKeyName());

        return collect($results['hits']['hits'])->map(function ($hit) use ($model, $models) {
            $one = $models[$hit['_id']];
            if (isset($hit['highlight'])) {
                $one->highlight = $hit['highlight'];
            }
            return $one;
        })->filter()->values();
    }
   ...
   ...
 
}