hocvt/laravel-scout-elasticsearch

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

资助包维护!
Patreon

安装: 533

依赖: 0

建议者: 0

安全: 0

星标: 0

关注者: 1

分支: 113

v7.5.0 2024-03-29 06:52 UTC

This package is auto-updated.

Last update: 2024-09-10 10:07:26 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 提供的 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 类将引发错误。您可以在此处检查问题 here

条件

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 许可协议