minh7721/laravel-scout-elasticsearch

使用ElasticSearch和Laravel Scout在多个模型中进行搜索

资助包维护!
Patreon

安装: 23

依赖: 0

建议者: 0

安全: 0

星标: 0

关注者: 0

分支: 113

8.0.0 2024-05-09 09:59 UTC

This package is auto-updated.

Last update: 2024-09-09 10:38:08 UTC


README

Support Ukraine Import progress report

Build Status Coverage Total Downloads Latest Version License

对于Laravel框架 < 6.0.0,请使用3.x分支

该包为将ElasticSearch集成到您的Laravel应用程序提供了完美的起点。它经过精心设计,以简化在Laravel框架中使用ElasticSearch。

它建立在最新版本的Laravel Scout之上,这是官方的Laravel搜索包。使用此包,您可以充分利用Laravel Scout的所有优秀功能,同时利用ElasticSearch的完整搜索体验。

如果您需要任何帮助,请通过stack overflow提出支持问题,这是首选和推荐的方式。

💕 特点

如果喜欢这个包,别忘了⭐它。🙏

  • Laravel Scout 10.x 支持
  • Laravel Nova 支持
  • 搜索多个模型
  • 零停机时间重新导入 - 在生产环境中导入数据非常容易。
  • 预加载关系 - 加快导入速度。
  • 一次性导入所有可搜索的模型。
  • 为每个模型提供完全可配置的映射。
  • 在查询中充分利用ElasticSearch的全部功能。

⚠️ 要求

  • PHP版本 >= 8.0
  • Laravel框架版本 >= 8.0.0

🚀 安装

使用composer安装包

composer require matchish/laravel-scout-elasticsearch

设置环境变量

SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine

该包使用官方包中的 \ElasticSearch\Client,但不尝试配置它,因此您可以在应用程序服务提供程序中自由配置。但如果您现在不想这样做,您可以使用包中的 Matchish\ElasticSearchServiceProvider
注册提供程序,添加到 config/app.php

'providers' => [
    // Other Service Providers

    \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class
],

设置 ELASTICSEARCH_HOST 环境变量

ELASTICSEARCH_HOST=host:port

或使用逗号作为分隔符以分隔附加节点

ELASTICSEARCH_HOST=host:port,host:port

并发布Elasticsearch配置示例
php artisan vendor:publish --tag config

💡 使用

注意:此包增加了对Laravel Scout的功能,因此我们建议您首先阅读Scout文档。Scout的文档可以在Laravel网站上找到。

索引设置映射

在创建索引时定义映射非常重要——不适当的初步定义和映射可能导致错误的搜索结果。

要定义索引的映射或设置,请使用正确的值设置配置。

例如,如果方法 searchableAs 返回 products 字符串

映射配置键应为
elasticsearch.indices.mappings.products
或者您可以使用配置键 elasticsearch.indices.mappings.default 指定默认映射

同样,您也可以定义设置

对于索引 products,它将是
elasticsearch.indices.settings.products

默认设置
elasticsearch.indices.settings.default

急切加载

为了加快导入速度,您可以在导入时使用全局作用域急切加载关系。

您应该在服务提供者中配置 ImportSourceFactory(在 register 方法中)

use Matchish\ScoutElasticSearch\Searchable\ImportSourceFactory;
...
public function register(): void
{
$this->app->bind(ImportSourceFactory::class, MyImportSourceFactory::class);

以下是一个 MyImportSourceFactory 的示例

namespace Matchish\ScoutElasticSearch\Searchable;

final class MyImportSourceFactory implements ImportSourceFactory
{
    public static function from(string $className): ImportSource
    {
        //Add all required scopes
        return new DefaultImportSource($className, [new WithCommentsScope()]);
    }
}

class WithCommentsScope implements Scope {

    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @param \Illuminate\Database\Eloquent\Model $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->with('comments');
    }
}

当您通过利用 Laravel Scout 通过 Searchable 特性提供的 toSearchableArray 方法保存模型时,您也可以自定义索引数据

示例

class Product extends Model 
{
    use Searchable;

    /**
     * Get the indexable data array for the model.
     *
     * @return array
     */
    public function toSearchableArray()
    {
        $with = [
            'categories',
        ];

        $this->loadMissing($with);

        return $this->toArray();
    }
}

此示例将确保在保存模型时始终加载类别关系。

零停机重新导入

在生产环境中工作,为了在重新导入数据时保持现有的搜索体验,您也可以使用 scout:import2 Artisan 命令

php artisan scout:import2

该命令创建一个新的临时索引,将所有模型导入到其中,然后切换到索引并删除旧索引。

搜索

为了与原始 scout 包完全兼容,此包不添加新方法。
那么我们如何构建复杂的查询呢?有两种方法。
默认情况下,当您将查询传递给 search 方法时,引擎构建一个 query_string 查询,因此您可以构建如下查询

Product::search('(title:this OR description:this) AND (title:that OR description:that)')

如果这还不够,您可以将回调传递给查询构建器

$results = Product::search('zonga', function(\Elastic\Elasticsearch\Client $client, $body) {

    $minPriceAggregation = new MinAggregation('min_price');
    $minPriceAggregation->setField('price');
    
    $maxPriceAggregation = new MaxAggregation('max_price');
    $maxPriceAggregation->setField('price');
    
    $brandTermAggregation = new TermsAggregation('brand');
    $brandTermAggregation->setField('brand');

    $body->addAggregation($minPriceAggregation);
    $body->addAggregation($brandTermAggregation);
    
    return $client->search(['index' => 'products', 'body' => $body->toArray()])->asArray();
})->raw();

注意:回调函数将接收两个参数。第一个是 $client,它是来自 elasticsearch/elasticsearch 包的 \Elastic\Elasticsearch\Client 类的对象。第二个是 $body,它是来自 ongr/elasticsearch-dsl 包的 \ONGR\ElasticsearchDSL\Search 类的对象。因此,如您在上述示例中看到的,$client->search(....) 方法将返回一个 \Elastic\Elasticsearch\Response\Elasticsearch 对象。您需要使用 asArray() 方法来获取数组结果。否则,HitsIteratorAggregate 类将引发错误。您可以在 此处 检查问题。

条件

Scout 只支持 3 个条件:->where(column, value)(严格等于)、->whereIn(column, array)->whereNotIn(column, array)

Product::search('(title:this OR description:this) AND (title:that OR description:that)')
    ->where('price', 100)
    ->whereIn('type', ['used', 'like new'])
    ->whereNotIn('type', ['new', 'refurbished']);

Scout 不支持任何运算符,但您可以将 ElasticSearch 术语(如 RangeQuery)作为值传递给 ->where()

use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;

Product::search('(title:this OR description:this) AND (title:that OR description:that)')
    ->where('price', new RangeQuery('price', [
        RangeQuery::GTE => 100,
        RangeQuery::LTE => 1000,
    ]);

如果您只想使用 RangeQuery 进行搜索而没有任何 query_string,可以直接调用 search() 方法并留空参数。

use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;

Product::search()
    ->where('price', new RangeQuery('price', [
        RangeQuery::GTE => 100,
    ]);

ElasticSearch 术语的完整列表在 vendor/handcraftedinthealps/elasticsearch-dsl/src/Query/TermLevel 中。

搜索多个模型

您可以使用 MixedSearch 类来完成此操作,只需将索引名称通过逗号分隔传递给 within 方法。

MixedSearch::search('title:Barcelona or to:Barcelona')
    within(implode(',', [
        (new Ticket())->searchableAs(),
        (new Book())->searchableAs(),
    ]))
->get();

在此示例中,您将获得包含 TicketBook 模型的集合,其中 ticket 的到达城市或 book 的标题为 Barcelona

处理结果

通常,您的响应不是模型集合,而是聚合或带有高亮的模型等。在这种情况下,您需要实现自己的 HitsIteratorAggregate 实现,并将其绑定到服务提供者中

以下是一个示例

🆓 许可证

Scout ElasticSearch 是一个开源软件,许可协议为 MIT 许可协议