安装 Elasticsearch 可以参考 Laradock 最佳实践。本文大部分内容来自 scout-elasticsearch-driver 项目的 README 文档。
一、安装 Scout 扩展
$ # 安装 Scout
$ composer require laravel/scout
$ # 发布配置文件
$ php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
二、安装 ES 驱动
$ # 安装驱动
$ composer require babenkoivan/scout-elasticsearch-driver
$ # 发布配置文件
$ php artisan vendor:publish --provider="ScoutElastic\ScoutElasticServiceProvider"
三、修改配置文件
在 config/scout.php 文件中将驱动修改为 elastic:
'driver' => env('SCOUT_DRIVER', 'elastic'),
在 config/scout_elastic.php 文件中配置驱动:
<?php
return [
'client' => [
'hosts' => [
env('SCOUT_ELASTIC_HOST', 'elasticsearch:9200')
]
],
'update_mapping' => env('SCOUT_ELASTIC_UPDATE_MAPPING', true),
'indexer' => env('SCOUT_ELASTIC_INDEXER', 'single'),
'document_refresh' => env('SCOUT_ELASTIC_DOCUMENT_REFRESH')
];
| Option | Description |
|---|---|
| client | 客户端配置,更多信息查看这里。默认主机地址设置为:localhost:9200。如果使用的是 Laradock 开发环境,需要修改为 elasticsearch:9200。 |
| update_mapping | 设置是否自动更新映射,默认为 true。 |
| indexer | 设置为 single(默认)单独索引文档,设置为 buld 批量索引文档。 |
| document_refresh | 配置已更新的 Documents 什么时候出现在搜索结果里。可被设置为 true,false,wait_for 或者 null。默认是 null。更多信息查看这里。 |
四、创建索引配置类
使用 Artisan 命令初始化一个索引配置类:
$ php artisan make:index-configurator IndexConfigurator/MyIndexConfigurator
这会在 app 目录下创建文件 IndexConfigurator/MyIndexConfigurator.php。
<?php
namespace App\IndexConfigurator;
use ScoutElastic\IndexConfigurator;
class MyIndexConfigurator extends IndexConfigurator
{
// 指定索引名不是强制性的,默认情况下是去掉 'IndexConfigurator' 部分的蛇形命名(snake case)
// 在这个例子当中,如果不设置该属性,则索引名是 my
protected $name = 'my_index';
// 你可以指定任何设置,例如:自定义分析器。
protected $settings = [
'analysis' => [
'analyzer' => [
'es_std' => [
'type' => 'standard',
'stopwords' => '_spanish_'
]
]
]
];
}
注意:每个模型都需要指定索引配置类,见下一节
更多关于索引设置的信息可以查看 Elasticsearch 的索引管理章节。
要创建与之对应的索引运行下面的 artisan 命令:
$ php artisan elastic:create-index App\\IndexConfigurator\\MyIndexConfigurator
运行上面的命令后索引会被创建,但是其映射(mapping)为空。
五、模型配置
模型中需要做的:
- 继承
ScoutElastic\Searchable这个 Trait。注意不是Laravel\Scout\Searchable。 - 设置对应的索引类
$indexConfigurator。 - 设置搜索规则
$searchRules。 - 设置映射选项
$mapping。
样例:
<?php
namespace App;
use ScoutElastic\Searchable;
use Illuminate\Database\Eloquent\Model;
class MyModel extends Model
{
use Searchable;
protected $indexConfigurator = MyIndexConfigurator::class;
protected $searchRules = [
//
];
// 在这里为模型字段指定映射
protected $mapping = [
'properties' => [
'text' => [
'type' => 'text',
'fields' => [
'raw' => [
'type' => 'keyword',
]
]
],
]
];
}
每个可搜索(searchable)模型对应一个 Elasticsearch type。默认 type 的名称与表名相同,但是可以通过 searchableAs 方法进行修改。可以通过 toSearchableArray 方法指定被索引的字段。更多信息参考官方文档的 Scout 扩展。
$searchRules 属性允许你对一个模型设置不同的算法。详见后面的搜索规则章节。
在设置完映射后,可以进行更新:
$ php artisan elastic:update-mapping App\\MyModel
导入数据到 ES 索引:
$ php artisan scout:import "App\Post"
从 ES 中移除数据(这个方法比较慢):
$ php artisan scout:flush "App\Post"
删除 ES 中的指定索引和数据:
$ curl -X DELETE 'localhost:9200/Index'
六、用法
一旦创建了索引配置类,ES 索引,和可搜索模型,就可以根据文档索引和搜索数据。
基础用法如下:
// 设置查询字符串
App\MyModel::search('phone')
// 指定选择的字段
->select(['title', 'price'])
// 过滤
->where('color', 'red')
// 排序
->orderBy('price', 'asc')
// collapse by field
->collapse('brand')
// 设置偏移
->from(0)
// 设置间隔
->take(10)
// 获取结果
->get();
如果只需要获取查询的匹配数量,使用 count 方法:
App\MyModel::search('phone')
->with('makers')
->get();
如果需要加载关联关系,使用 with 方法:
App\MyModel::search('phone')
->with('makers')
->get();
除了标准功能外,该包还提供了在 Elasticsearch 中过滤数据而无需指定查询字符串的可能性:
App\MyModel::search('*')
->where('id', 1)
->get();
平且可以覆盖搜索规则:
App\MyModel::search('Brazil')
->rule(App\MySearchRule::class)
->get();
使用多种 where 条件:
App\MyModel::search('*')
->whereRegexp('name.raw', 'A.+')
->where('age', '>=', 30)
->whereExists('unemployed')
->get();
如果要发送一个自定义的请求,可以使用 serachRaw 方法,这个请求返回原始响应。:
App\MyModel::searchRaw([
'query' => [
'bool' => [
'must' => [
'match' => [
'_all' => 'Brazil'
]
]
]
]
]);
七、终端命令
可用的终端命令如下:
| 命令 | 参数 | 描述 |
|---|---|---|
| make:index-configurator | name - 索引配置类名 | Creates a new Elasticsearch index configurator. |
| make:searchable-model | name - 模型类名 | Creates a new searchable model. |
| make:search-rule | name - 搜索规则类名 | Creates a new search rule. |
| elastic:create-index | index-configurator - 索引配置类 | Creates an Elasticsearch index. |
| elastic:update-index | index-configurator - 索引配置类 | 更新一个 ES 索引的设置和映射 |
| elastic:drop-index | index-configurator - 索引配置类 | 删除一个 ES 索引 |
| elastic:update-mapping | model - 模型类 | 更新一个模型的映射 |
| elastic:migrate | model - 模型类 target-index - 要迁移到的索引名称 | 迁移模型至另一个索引 |
通过执行命令 php artisan help [command] 获取更详细的描述和可用选项介绍。
八、搜索规则
搜索规则是描述搜索查询将如何执行的类。 要创建搜索规则,使用以下命令:
$ php artisan make:search-rule SearchRule\MySearchRule
在 app/MySearchRule.php 中你可以发现一个类定义:
<?php
namespace App\SearchRule;
use ScoutElastic\SearchRule;
class MySearchRule extends SearchRule
{
// 该方法返回一个数组,描述如何高亮搜索结果。
// 如果返回 null,则不高亮结果。
public function buildHighlightPayload()
{
return [
'fields' => [
'name' => [
'type' => 'plain'
]
]
];
}
// 该方法返回一个数组,对应布尔查询。
public function buildQueryPayload()
{
return [
'must' => [
'match' => [
'name' => $this->builder->query
]
]
];
}
}
默认搜索规则返回如下负载:
return [
'must' => [
'query_string' => [
'query' => $this->builder->query
]
]
];
这意味着默认情况下,当在模型上调用 search 方法时,它会尝试在任何字段中查找查询的字符串。
要指定模型的默认搜索规则,只需添加一个属性:
<?php
namespace App;
use ScoutElastic\Searchable;
use Illuminate\Database\Eloquent\Model;
class MyModel extends Model
{
use Searchable;
// 你可以为一个模型设置几个搜索规则,在这种情况下,将返回第一个非空结果。
protected $searchRules = [
MySearchRule::class
];
}
你也可以在查询构造器中设置搜索规则:
// 你可以设置一个搜索规则类
App\MyModel::search('Brazil')
->rule(App\MySearchRule::class)
->get();
// 或者是一个回调函数
App\MyModel::search('Brazil')
->rule(function($builder) {
return [
'must' => [
'match' => [
'Country' => $builder->query
]
]
];
})
->get();
要获取高亮,使用模型的 highlight 属性:
// Let's say we highlight field `name` of `MyModel`.
$model = App\MyModel::search('Brazil')
->rule(App\MySearchRule::class)
->first();
// Now you can get raw highlighted value:
$model->highlight->name;
// or string value:
$model->highlight->nameAsString;
九、可用的过滤器
可以使用不同类型的过滤器:
| 方法 | Example | Description |
|---|---|---|
| where($field,$value) | where(‘id’, 1) | 检查是否等值 |
| where($field,$operator,$value) | where(‘id’, ‘>=’, 1) | 根据给定的规则过滤,可用的操作符有: =, <, >, <=, >=, <>. |
| whereIn($field, $value) | where(‘id’, [1, 2, 3]) | Checks if a value is in a set of values. |
| whereNotIn($field, $value) | whereNotIn(‘id’, [1, 2, 3]) | 检查值是否不在一个集合中 |
| whereBetween($field, $value) | whereBetween(‘price’, [100, 200]) | 检查值是否在一个范围内 |
| whereNotBetween($field, $value) | whereNotBetween(‘price’, [100, 200]) | 检查值是否不在一个范围内 |
| whereExists($field) | whereExists(‘unemployed’) | Checks if a value is defined. |
| whereNotExists($field) | whereNotExists(‘unemployed’) | 检查值是否没定义 |
| whereRegexp($field, $value, $flags = ‘ALL’) | whereRegexp(‘name.raw’, ‘A.+’) | 根据给定的正则过滤, 这里 你可以找到更多语法。 |
| whereGeoDistance($field, $value, $distance) | whereGeoDistance(‘location’, [-70, 40], ‘1000m’) | 根据给定的点和距离过滤, 这里 你可以找到更多语法。 |
| whereGeoBoundingBox($field, array $value) | whereGeoBoundingBox(‘location’, [‘top_left’ => [-74.1, 40.73], ‘bottom_right’ => [-71.12, 40.01]]) | 根据跟定的边框过滤, 这里 你可以找到更多语法。 |
| whereGeoPolygon($field, array $points) | whereGeoPolygon(‘location’, [[-70, 40],[-80, 30],[-90, 20]]) | 根据给定的多边形过滤, 这里 你可以找到更多语法。 |
| whereGeoShape($field, array $shape) | whereGeoShape(‘shape’, [‘type’ => ‘circle’, ‘radius’ => ‘1km’, ‘coordinates’ => [4, 52]]) | 根据给定的形状过滤, 这里 你可以找到更多语法。 |
在大多数情况下,最好使用原始字段来过滤记录,即不分析字段。
十、零停机迁移
如你所知,你无法在 Elasticsearch 中更改已创建的字段的类型。在这种情况下,唯一的选择是创建一个具有必要映射的新索引,并将模型导入新索引。
迁移可能需要很长时间,因此为避免在此过程中停机,驱动程序将从旧索引读取并写入新索引。一旦迁移结束,它就会从新索引开始读取并删除旧索引。这就是 artisan elastic:migrate 命令的工作原理。
在运行命令之前,请确保索引配置类继承了 ScoutElastic\Migratable 这个 Trait。 如果没有,添加这个 Trait 并使用索引配置类名称作为参数运行 artisan elastic:update-index 命令:
$ php artisan elastic:update-index App\\IndexConfigurator\\MyIndexConfigurator
准备就绪后,更改你需要的模型的映射,并运行 elastic:migrate 命令,使用模型类作为第一个参数,并将所需的索引名称作为第二个参数:
$ php artisan elastic:migrate App\\MyModel my_index_v2
请注意,如果只需要在映射中添加新字段,请使用 elastic:update-mapping 命令。
十一、Debug
有两种方法可以帮助分析搜索查询的结果:
两种方法都从 ES 返回原始数据。
此外,可以通过调用 buildPayload 方法获取将发送到 ES 的查询体。
App\MyModel::search('Brazil')
->buildPayload();
请注意,此方法返回有效查询体的集合,因为可能在一个查询中使用多个搜索规则。