自定义引擎
如果内置的 Scout 搜索引擎不能满足你的需求,你可以写自定义的引擎并且将它注册到 Scout。你的引擎需要继承
Laravel\Scout\Engines\Engine
抽象类,这个抽象类包含了你自定义的引擎必须要实现的五种方法
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 map($results, $model)
<?php
namespace App\Engine;
use Laravel\Scout\Builder;
use Laravel\Scout\Engines\Engine;
use Elasticsearch\Client;
use Illuminate\Database\Eloquent\Collection;
class ElasticsearchEngine extends Engine{
//索引
protected $index;
//搜索引擎
protected $elastic;
//初始化
public function __construct(Client $elastic,$index)
{
$this->elastic=$elastic;
$this->index=$index;
}
//更新
public function update($models)
{
$params['body'] = [];
$models->each(function($model) use (&$params)
{
$params['body'][] = [
'update' => [
'_id' => $model->getKey(),
'_index' => $this->index,
'_type' => $model->searchableAs(),
]
];
$params['body'][] = [
'doc' => $model->toSearchableArray(),
'doc_as_upsert' => true
];
});
$this->elastic->bulk($params);
}
//删除
public function delete($models)
{
$params['body'] = [];
$models->each(function($model) use (&$params)
{
$params['body'][] = [
'delete' => [
'_id' => $model->getKey(),
'_index' =>$this->index,
'_type' => $model->searchableAs(),
]
];
});
$this->elastic->bulk($params);
}
//搜索
public function search(Builder $builder)
{
return $this->performSearch($builder, array_filter([
'numericFilters' => $this->filters($builder),
'size' => $builder->limit,
]));
}
//搜索参数
protected function performSearch(Builder $builder, array $options = [])
{
$params = [
'index' => $this->index,
'type' => $builder->index ?: $builder->model->searchableAs(),
'body' => [
'query' => [
'bool' => [
'must' => [['query_string' => [ 'query' => "*{$builder->query}*"]]]
]
]
]
];
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);
}
//获取查询的过滤器数组
protected function filters(Builder $builder)
{
return collect($builder->wheres)->map(function ($value, $key) {
if (is_array($value)) {
return ['terms' => [$key => $value]];
}
return ['match_phrase' => [$key => $value]];
})->values()->all();
}
//生成排序结果
protected function sort($builder)
{
if (count($builder->orders) == 0) {
return null;
}
return collect($builder->orders)->map(function($order) {
return [$order['column'] => $order['direction']];
})->toArray();
}
//分页
public function paginate(Builder $builder, $perPage, $page)
{
$result = $this->performSearch($builder, [
'numericFilters' => $this->filters($builder),
'from' => (($page * $perPage) - $perPage),
'size' => $perPage,
]);
$result['nbPages'] = $result['hits']['total']/$perPage;
return $result;
}
//采集并返回给定结果的主键
public function mapIds($results)
{
return collect($results['hits']['hits'])->pluck('_id')->values();
}
//将给定结果映射到给定模式的实例
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) {
return isset($models[$hit['_id']]) ? $models[$hit['_id']] : null;
})->filter()->values();
}
//获取总行数
public function getTotalCount($results)
{
return $results['hits']['total'];
}
}
注册引擎
你只需要从
AppServiceProvider
下的
boot
方法或者应用中使用的任何一个服务提供器调用
extend
方法
public function boot()
{
$this->bootElasticsearch();
}
protected function bootElasticsearch() {
resolve(EngineManager::class)->extend('elasticsearch', function () {
$config = config('scout.elasticsearch');
$client = ClientBuilder::create()
->setHosts($config['hosts'])
->build();
return new ElasticsearchEngine($client);
});
}
引擎注册后,你可以在
config/scout.php
配置文件中指定它为默认的 Scout
driver
'driver' => env('SCOUT_DRIVER', 'elasticsearch'),
'elasticsearch' => [
'index' => env('ELASTICSEARCH_INDEX', 'mall'),
'hosts' => [
env('ELASTICSEARCH_HOST', 'http://elasticsearch:9200'),
],
],
提示:先安装:https://github.com/elastic/elasticsearch-php
"elasticsearch/elasticsearch":
"~6.0"