babenkoivan/scout-elasticsearch-driver

该软件包已被弃用且不再维护。作者建议使用 babenkoivan/elastic-scout-driver 软件包。

Laravel Scout 的 Elasticsearch 驱动程序

v4.3.0 2021-03-22 18:41 UTC

README

💥 介绍一个新的 Laravel Elasticsearch 生态系统 💥

Packagist Packagist Build Status Donate

该软件包提供了在 Elasticsearch 中搜索和过滤数据的先进功能。查看其 功能

内容

功能

要求

该软件包已在以下配置中进行测试

  • PHP 版本 >=7.1.3, <=7.3
  • Laravel 框架版本 >=5.8, <=6
  • Elasticsearch 版本 >=7

安装

使用 Composer 安装软件包

composer require babenkoivan/scout-elasticsearch-driver

如果您正在使用 Laravel 版本 <= 5.4 或 禁用了软件包发现,请在 config/app.php 中添加以下提供者

'providers' => [
    Laravel\Scout\ScoutServiceProvider::class,
    ScoutElastic\ScoutElasticServiceProvider::class,
]

配置

要配置该软件包,您首先需要发布设置

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
php artisan vendor:publish --provider="ScoutElastic\ScoutElasticServiceProvider"

然后,在 config/scout.php 文件中将驱动设置设置为 elastic(或在 .env 中设置 SCOUT_DRIVER=elastic)并在 config/scout_elastic.php 文件中配置驱动程序本身。可用的选项包括

选项 描述
client 用于构建Elasticsearch客户端的设置哈希。更多信息请参阅这里。默认情况下,主机设置为localhost:9200
update_mapping 指定是否自动更新映射的选项。默认情况下设置为true
indexer 对于单个文档索引设置为single,对于批量文档索引设置为bulk。默认情况下设置为single
document_refresh 此选项控制更新后的文档何时出现在搜索结果中。可以设置为'true''false''wait_for'null。更多关于此选项的详细信息请参阅这里。默认设置为null

注意,如果您使用批量文档索引,您可能想要更改块大小,您可以在config/scout.php文件中完成此操作。

索引配置器

使用以下Artisan命令创建索引配置器类,以设置Elasticsearch索引的设置

php artisan make:index-configurator MyIndexConfigurator

它将在您项目的app文件夹中创建一个名为MyIndexConfigurator.php的文件。您可以在以下示例中指定索引名称和设置

<?php

namespace App;

use ScoutElastic\IndexConfigurator;

class MyIndexConfigurator extends IndexConfigurator
{
    // 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' => [
                'es_std' => [
                    'type' => 'standard',
                    'stopwords' => '_spanish_'
                ]
            ]    
        ]
    ];
}

更多关于索引设置的信息,您可以在Elasticsearch文档的索引管理部分中找到。

要创建索引,只需运行Artisan命令

php artisan elastic:create-index "App\MyIndexConfigurator"

注意,每个可搜索模型都需要自己的索引配置器。

Elasticsearch 6.0.0或更高版本创建的索引可能只能包含一个映射类型。在5.x中创建具有多个映射类型的索引将继续在Elasticsearch 6.x中按原样工作。映射类型将在Elasticsearch 7.0.0中完全删除。

更多信息请参阅这里

可搜索模型

要创建一个具有在Elasticsearch索引中执行搜索请求能力的模型,请使用以下命令

php artisan make:searchable-model MyModel --index-configurator=MyIndexConfigurator

执行命令后,您将在您的app文件夹中找到名为MyModel.php的文件

<?php

namespace App;

use ScoutElastic\Searchable;
use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    use Searchable;

    protected $indexConfigurator = MyIndexConfigurator::class;

    protected $searchRules = [
        //
    ];

    // Here you can specify a mapping for model fields
    protected $mapping = [
        'properties' => [
            'title' => [
                'type' => 'text',
                // Also you can configure multi-fields, more details you can find here https://elastic.ac.cn/guide/en/elasticsearch/reference/current/multi-fields.html
                'fields' => [
                    'raw' => [
                        'type' => 'keyword',
                    ]
                ]
            ],
        ]
    ];
}

每个可搜索模型代表一个Elasticsearch类型。默认情况下,类型名称与表名称相同,但您可以通过searchableAs方法设置任何类型名称。您还可以通过toSearchableArray方法指定由驱动程序索引的字段。有关这些选项的更多信息,您可以在Scout官方文档中找到。

MyModel类中您可以设置的最后一个重要选项是$searchRules属性。它允许您为模型设置不同的搜索算法。我们将在搜索规则部分中更详细地介绍它。

在您的模型中设置映射后,您可以更新Elasticsearch类型映射

php artisan elastic:update-mapping "App\MyModel"

用法

一旦创建了索引配置器、Elasticsearch索引和可搜索模型,您就可以开始了。现在您可以按照文档进行索引搜索数据。

基本搜索用法示例

// set query string
App\MyModel::search('phone')
    // specify columns to select
    ->select(['title', 'price'])
    // filter 
    ->where('color', 'red')
    // sort
    ->orderBy('price', 'asc')
    // collapse by field
    ->collapse('brand')
    // set offset
    ->from(0)
    // set limit
    ->take(10)
    // get results
    ->get();

如果您只需要查询的匹配数量,请使用 count 方法

App\MyModel::search('phone') 
    ->count();

如果您需要加载关系,请使用 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();

并过滤掉得分小于 min_score 的结果

App\MyModel::search('sales')
    ->minScore(1.0)
    ->get();

并添加更复杂的排序(例如 geo_distance)

$model = App\MyModel::search('sales')
    ->orderRaw([
       '_geo_distance' =>  [
           'coordinates' => [
               'lat'   =>  51.507351,
               'lon'   =>  -0.127758
           ],
           'order'     =>  'asc',
           'unit'      =>  'm'
       ]
    ])
    ->get();

// To retrieve sort result, use model `sortPayload` attribute:
$model->sortPayload;

最后,如果您想发送自定义请求,可以使用 searchRaw 方法

App\MyModel::searchRaw([
    'query' => [
        'bool' => [
            'must' => [
                'match' => [
                    '_all' => 'Brazil'
                ]
            ]
        ]
    ]
]);

此查询将返回原始响应。

控制台命令

以下列出了可用的 artisan 命令

命令 参数 描述
make:index-configurator name - 类名 创建一个新的 Elasticsearch 索引配置器。
make:searchable-model name - 类名 创建一个新的可搜索模型。
make:search-rule name - 类名 创建一个新的搜索规则。
elastic:create-index index-configurator - 索引配置器类 创建 Elasticsearch 索引。
elastic:update-index index-configurator - 索引配置器类 更新 Elasticsearch 索引的设置和映射。
elastic:drop-index index-configurator - 索引配置器类 删除 Elasticsearch 索引。
elastic:update-mapping model - 模型类 更新模型映射。
elastic:migrate-model model - 模型类,target-index - 要迁移的索引名称 将模型迁移到另一个索引。

要获取详细说明和所有可用选项,请在命令行中运行 php artisan help [命令]

搜索规则

搜索规则是一个描述搜索查询如何执行的类。要创建搜索规则,请使用以下命令

php artisan make:search-rule MySearchRule

在文件 app/MySearchRule.php 中,您将找到一个类定义

<?php

namespace App;

use ScoutElastic\SearchRule;

class MySearch extends SearchRule
{
    // This method returns an array, describes how to highlight the results.
    // If null is returned, no highlighting will be used. 
    public function buildHighlightPayload()
    {
        return [
            'fields' => [
                'name' => [
                    'type' => 'plain'
                ]
            ]
        ];
    }
    
    // This method returns an array, that represents bool query.
    public function buildQueryPayload()
    {
        return [
            'must' => [
                'match' => [
                    'name' => $this->builder->query
                ]
            ]
        ];
    }
}

您可以在这里阅读有关 bool 查询的更多信息,以及有关高亮显示的更多信息这里

默认搜索规则返回以下有效负载

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;
    
    // You can set several rules for one model. In this case, the first not empty result will be returned.
    protected $searchRules = [
        MySearchRule::class
    ];
}

您还可以在查询构建器中设置搜索规则

// You can set either a SearchRule class
App\MyModel::search('Brazil')
    ->rule(App\MySearchRule::class)
    ->get();
    
// or a callable
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;

可用过滤器

您可以使用不同类型的过滤器

方法 示例 描述
where($field, $value) where('id', 1) 检查等于简单值。
where($field, $operator, $value) where('id', '>=', 1) 根据给定规则过滤记录。可用的运算符有:=, <, >, <=, >=, <>。
whereIn($field, $value) whereIn('id', [1, 2, 3]) 检查值是否在一组值中。
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') 检查值是否已定义。
whereNotExists($field) whereNotExists('unemployed') 检查值是否未定义。
whereMatch($field, $value) whereMatch('tags', 'travel') 过滤匹配精确值的记录。这里可以找到更多关于语法的详细信息。
whereNotMatch($field, $value) whereNotMatch('tags', 'travel') 过滤不匹配精确值的记录。这里可以找到更多关于语法的详细信息。
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, $relation = 'INTERSECTS') whereGeoShape('shape', ['type' => 'circle', 'radius' => '1km', 'coordinates' => [4, 52]], 'WITHIN') 过滤给定形状内的记录。这里可以找到更多关于语法的详细信息。

在大多数情况下,最好使用原始字段来过滤记录,即未分析的字段。

零停机迁移

正如你可能知道的,你无法在Elasticsearch中更改已创建字段的类型。在这种情况下,唯一的选项是创建一个新的索引,包含必要的映射,并将你的模型导入到新的索引中。
迁移可能需要相当长的时间,因此为了避免在迁移过程中停机,驱动程序从旧索引读取并将数据写入新索引。一旦迁移完成,它开始从新索引读取,并删除旧索引。这就是artisan elastic:migrate-model 命令的工作方式。

在运行命令之前,请确保你的索引配置器使用了 ScoutElastic\Migratable 特性。如果不是这样,添加特性并使用你的索引配置器类名作为参数运行artisan elastic:update-index 命令。

php artisan elastic:update-index "App\MyIndexConfigurator"

准备好后,在模型映射中做出更改,并使用模型类作为第一个参数,所需的索引名作为第二个参数运行 elastic:migrate-model 命令。

php artisan elastic:migrate-model "App\MyModel" my_index_v2

注意,如果你只需在映射中添加新字段,请使用 elastic:update-mapping 命令。

调试

有两种方法可以帮助你分析搜索查询的结果

  • explain

    App\MyModel::search('Brazil')
        ->explain();
  • profile

    App\MyModel::search('Brazil')
        ->profile();

这两种方法都返回ES的原始数据。

此外,你可以通过调用 buildPayload 方法获取将被发送到ES的查询负载。

App\MyModel::search('Brazil')
    ->buildPayload();

请注意,由于一个查询中可能使用多个搜索规则,该方法返回一个负载集合。

替代方案

最近,我发布了一个新的 Laravel Elasticsearch 生态系统,它包括

  • Elastic Scout Driver - 一个为 Laravel Scout 提供的通用 Elasticsearch 驱动。如果您需要在 Laravel 应用中构建简单的搜索,它非常适合。
  • Elastic Scout Driver Plus - Elastic Scout Driver 的扩展。如果您想利用布尔查询、高亮等 Elasticsearch 功能,这是一个不错的选择。
  • Elastic Migrations - 一种创建、删除或更新 Elasticsearch 索引模式并与团队成员共享的简单方法。它的界面与 Laravel 数据库迁移相当相似。

如果您对其中任何一项感兴趣并想了解更多详情,请阅读 Laravel 应用程序中 Elasticsearch 的终极指南。这篇文章对提到的包进行了很好的概述,并提供了使用示例。

常见问题解答(FAQ)

  • 为什么你创建了一个新包而不是一个新的 scout-elasticsearch-driver 版本? - 由于明显的理由,我不想创建另一个大而全的包:没有关注点的分离,与其他 Scout 驱动不兼容,难以测试和开发等。由于 Elastic Scout Driver 是一个通用驱动程序,并没有实现所有 scout-elasticsearch-driver 的功能,因此将其称为新的 scout-elasticsearch-driver 版本是不正确的。
  • 这对 scout-elasticsearch-driver 有什么意义? - 目前,它由社区维护(感谢 @iget-esoares 和 @lucamichot 保持项目活跃 🎉)。我希望他们会继续为项目做出贡献,并在未来带来一个新版本的 scout-elasticsearch-driver